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

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: DownloadQuery 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/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stl_util.h"
15 #include "base/string16.h"
16 #include "base/string_split.h"
17 #include "base/time.h"
18 #include "base/utf_string_conversions.h"
19 #include "content/browser/download/download_item.h"
20 #include "googleurl/src/gurl.h"
21 #include "unicode/regex.h"
22
23 namespace download_util {
24
25 // The FieldInterfaces allow us to keep the templateyness out of the header.
26
27 // Filter fields can be used to filter DownloadItems out of the result set.
28 class DownloadQuery::FilterFieldInterface {
29 public:
30 virtual ~FilterFieldInterface() {}
31 virtual bool Valid() = 0;
32 virtual bool Matches(const DownloadItem& item) const = 0;
33 };
34
35 // Sort fields are used by DownloadComparator to sort DownloadItems.
36 class SortFieldInterface {
37 public:
38 virtual ~SortFieldInterface() {}
39
40 virtual DownloadQuery::SortFieldDirection direction() const = 0;
41
42 // Return 0 when left's field is equivalent to right's field, -1 when left <
43 // right, or 1 when left > right.
44 virtual int Compare(const DownloadItem& left,
45 const DownloadItem& right) const = 0;
46 };
47
48 namespace {
49
50 typedef std::vector<SortFieldInterface*> SortFieldVector;
51
52 // Functor passed to std::sort to sort DownloadItems.
53 class DownloadComparator {
54 public:
55 DownloadComparator(const SortFieldVector& terms)
56 : terms_(terms) {
57 }
58
59 // Returns true if |left| sorts before |right|.
60 bool operator() (const DownloadItem* left, const DownloadItem* right);
61
62 private:
63 const SortFieldVector& terms_;
64
65 // std::sort requires this class to be copyable.
66 };
67
68 bool DownloadComparator::operator() (const DownloadItem* left,
69 const DownloadItem* right) {
70 for (SortFieldVector::const_iterator term = terms_.begin();
71 term != terms_.end(); ++term) {
72 int comparison = (*term)->Compare(*left, *right);
73 if (comparison != 0)
74 return ((*term)->direction() == DownloadQuery::ASCENDING) ==
75 (comparison < 0);
76 }
77 if (left->GetId() != right->GetId())
78 return left->GetId() < right->GetId();
79 CHECK_NE(left->GetDbHandle(), right->GetDbHandle());
80 return left->GetDbHandle() < right->GetDbHandle();
81 }
82
83 static int get_start_time(const DownloadItem& item) {
84 return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
85 }
86
87 static int get_end_time(const DownloadItem& item) {
88 return 0; // TODO(benjhayden): endTime
89 }
90
91 static bool get_danger_accepted(const DownloadItem& item) {
92 return (item.GetSafetyState() == DownloadItem::DANGEROUS_BUT_VALIDATED);
93 }
94
95 static string16 get_filename(const DownloadItem& item) {
96 return item.GetFullPath().LossyDisplayName();
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 A comment here as to why we're using the LossyDisp
benjhayden 2011/11/30 16:21:47 Done.
97 }
98
99 template <typename ValueType_>
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 nit: I think it would be useful to have comments i
benjhayden 2011/11/30 16:21:47 Done.
100 class FilterField : public DownloadQuery::FilterFieldInterface {
101 public:
102 typedef ValueType_ ValueType;
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 Just for my education, what's the value in type tr
benjhayden 2011/11/30 16:21:47 Short: Done. Long: If any of FilterField's methods
103 explicit FilterField(const ValueType& value) : value_(value) {}
104 virtual ~FilterField() {}
105 virtual bool Valid() OVERRIDE { return true; }
106
107 protected:
108 const ValueType& value() const { return value_; }
109
110 private:
111 ValueType value_;
112 };
113
114 template <typename StringType>
115 std::string ToUTF8(const StringType& s);
116
117 template<> std::string ToUTF8(const std::string& s) {
118 return s;
119 }
120
121 template<> std::string ToUTF8(const string16& s) {
122 return UTF16ToUTF8(s);
123 }
124
125 template <typename StringType>
126 class FilterFieldRegex : public FilterField<StringType> {
127 public:
128 explicit FilterFieldRegex(const StringType& value)
129 : FilterField<StringType>(value) {
130 }
131 virtual ~FilterFieldRegex() {}
132 using FilterField<StringType>::value;
133 virtual bool Valid() OVERRIDE {
134 UParseError re_err;
135 UErrorCode re_status = U_ZERO_ERROR;
136 scoped_ptr<icu::RegexPattern> pattern(icu::RegexPattern::compile(
137 icu::UnicodeString::fromUTF8(ToUTF8(value())),
138 re_err, re_status));
139 return U_SUCCESS(re_status);
140 }
141
142 protected:
143 bool RegexMatches(const StringType& text) const {
144 icu::UnicodeString pattern(ToUTF8(value()).c_str());
145 icu::UnicodeString input(ToUTF8(text).c_str());
146 UErrorCode status = U_ZERO_ERROR;
147 icu::RegexMatcher match(pattern, input, 0, status);
148 return match.find();
149 }
150 };
151
152 template <typename ValueType>
153 class SortField : public SortFieldInterface {
154 public:
155 explicit SortField(DownloadQuery::SortFieldDirection direction)
156 : direction_(direction) {
157 }
158 virtual ~SortField() {}
159
160 virtual DownloadQuery::SortFieldDirection direction() const {
161 return direction_;
162 }
163
164 virtual ValueType GetField(const DownloadItem& item) const = 0;
165
166 virtual int Compare(const DownloadItem& left,
167 const DownloadItem& right) const OVERRIDE {
168 ValueType left_value = GetField(left), right_value = GetField(right);
169 if (left_value > right_value) return 1;
170 if (left_value < right_value) return -1;
171 if (left_value == right_value) return 0;
172 NOTREACHED();
173 return 0;
174 }
175
176 private:
177 DownloadQuery::SortFieldDirection direction_;
178 };
179
180 #define LAMBDA(__name, __base, __method, __expr, __ctor_arg_type, __ctor_arg) ({ \
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 nit: This line looks long--I suspect > 80 columns?
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 nit/suggestion (up to you): I personally prefer li
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 A comment describing the context for this macro (w
benjhayden 2011/11/30 16:21:47 Done.
benjhayden 2011/11/30 16:21:47 Done.
benjhayden 2011/11/30 16:21:47 Done.
181 class __name : public __base { \
182 public: \
183 explicit __name(__ctor_arg_type x) : __base(x) {} \
184 virtual __method(const DownloadItem& item) const OVERRIDE { \
185 return __expr; \
186 } \
187 }; \
188 new __name(__ctor_arg); \
189 })
190
191 SortFieldInterface* GetSortField(DownloadQuery::SortFieldName name,
192 DownloadQuery::SortFieldDirection direction) {
193 switch (name) {
194 #define SORT_FIELD(__name, __type, __expr) \
195 case DownloadQuery::SORT_FIELD_ ## __name: return LAMBDA( \
196 SortField ## __name, SortField<__type>, __type GetField, __expr, \
197 DownloadQuery::SortFieldDirection, direction)
198 SORT_FIELD(START_TIME, int, get_start_time(item));
199 SORT_FIELD(URL, std::string, item.GetOriginalUrl().spec());
200 SORT_FIELD(FILENAME, string16, get_filename(item));
201 SORT_FIELD(DANGER, DownloadStateInfo::DangerType, item.GetDangerType());
202 SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item));
203 SORT_FIELD(STATE, DownloadItem::DownloadState, item.GetState());
204 SORT_FIELD(PAUSED, bool, item.IsPaused());
205 SORT_FIELD(MIME, std::string, item.GetMimeType());
206 SORT_FIELD(END_TIME, int, get_end_time(item));
207 SORT_FIELD(BYTES_RECEIVED, int, item.GetReceivedBytes());
208 SORT_FIELD(TOTAL_BYTES, int, item.GetTotalBytes());
209 SORT_FIELD(FILE_SIZE, int, 0); // TODO
210 SORT_FIELD(ERROR, int, 0); // TODO
211 #undef SORT_FIELD
212 default: return NULL;
213 }
214 }
215
216 } // anonymous namespace
217
218 DownloadQuery::DownloadQuery()
219 : limit_(kuint32max) {
220 }
221
222 DownloadQuery::~DownloadQuery() {
223 STLDeleteElements(&filter_fields_);
224 }
225
226 bool DownloadQuery::AddFilter(FilterFieldInterface* field) {
227 if (!field->Valid()) {
228 delete field;
229 return false;
230 }
231 filter_fields_.push_back(field);
232 return true;
233 }
234
235 #define START_FILTER_FIELDS(__type) \
236 template<> bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, \
237 const __type& _value) { \
238 typedef __type ValueType; \
239 switch (static_cast<int>(name)) {
240 #define FILTER_FIELD(__name, __expr) \
241 case FILTER_FIELD_ ## __name: return AddFilter( \
242 LAMBDA(FilterField ## __name, FilterField<ValueType>, bool Matches, \
243 __expr, const ValueType&, _value));
244 #define FILTER_FIELD_REGEX(__name, __expr) \
245 case FILTER_FIELD_ ## __name ## _REGEX: return AddFilter(LAMBDA( \
246 FilterField ## __name ## _REGEX, FilterFieldRegex<ValueType>, \
247 bool Matches, RegexMatches(__expr), const ValueType&, _value));
248 #define END_FILTER_FIELDS \
249 } \
250 return false; \
251 }
252
253 START_FILTER_FIELDS(int)
254 FILTER_FIELD(START_TIME, get_start_time(item) == value())
255 FILTER_FIELD(END_TIME, get_end_time(item) == value())
256 FILTER_FIELD(BYTES_RECEIVED, item.GetReceivedBytes() == value())
257 FILTER_FIELD(TOTAL_BYTES, item.GetTotalBytes() == value())
258 FILTER_FIELD(STARTED_BEFORE, get_start_time(item) < value())
259 FILTER_FIELD(STARTED_AFTER, get_start_time(item) > value())
260 FILTER_FIELD(ENDED_BEFORE, get_end_time(item) < value())
261 FILTER_FIELD(ENDED_AFTER, get_end_time(item) > value())
262 FILTER_FIELD(TOTAL_BYTES_GREATER, item.GetTotalBytes() > value())
263 FILTER_FIELD(TOTAL_BYTES_LESS, item.GetTotalBytes() < value())
264 FILTER_FIELD(FILE_SIZE_GREATER, false) // TODO
265 FILTER_FIELD(FILE_SIZE_LESS, false) // TODO
266 FILTER_FIELD(FILE_SIZE, false) // TODO
267 FILTER_FIELD(ERROR, false) // TODO
268 END_FILTER_FIELDS
269
270 START_FILTER_FIELDS(bool)
271 FILTER_FIELD(DANGER_ACCEPTED, get_danger_accepted(item) == value())
272 FILTER_FIELD(PAUSED, item.IsPaused() == value())
273 END_FILTER_FIELDS
274
275 START_FILTER_FIELDS(std::string)
276 FILTER_FIELD(URL, item.GetOriginalUrl().spec() == value())
277 FILTER_FIELD_REGEX(URL, item.GetOriginalUrl().spec())
278 FILTER_FIELD(MIME, item.GetMimeType() == value())
279 END_FILTER_FIELDS
280
281 START_FILTER_FIELDS(string16)
282 FILTER_FIELD(QUERY, item.MatchesQuery(value()))
283 FILTER_FIELD(FILENAME, get_filename(item) == value())
284 FILTER_FIELD_REGEX(FILENAME, get_filename(item))
285 END_FILTER_FIELDS
286
287 START_FILTER_FIELDS(base::Callback<bool(const DownloadItem& item)>)
288 FILTER_FIELD(FILTER, value().Run(item))
289 END_FILTER_FIELDS
290
291 START_FILTER_FIELDS(DownloadStateInfo::DangerType)
292 FILTER_FIELD(DANGER, item.GetDangerType() == value())
293 END_FILTER_FIELDS
294
295 START_FILTER_FIELDS(DownloadItem::DownloadState)
296 FILTER_FIELD(STATE, item.GetState() == value())
297 END_FILTER_FIELDS
298
299 #undef START_FILTER_FIELDS
300 #undef FILTER_FIELD
301 #undef END_FILTER_FIELDS
302
303 void DownloadQuery::Sort(DownloadQuery::SortFieldName name,
304 DownloadQuery::SortFieldDirection direction) {
305 order_by_fields_.push_back(OrderTerm(name, direction));
306 }
307
308 bool DownloadQuery::Matches(const DownloadItem& item) const {
309 for (FilterFieldVector::const_iterator filter_field = filter_fields_.begin();
310 filter_field != filter_fields_.end(); ++filter_field) {
311 if (!(*filter_field)->Matches(item))
312 return false;
313 }
314 return true;
315 }
316
317 template <typename InputIterator>
318 void DownloadQuery::Search(InputIterator iter, const InputIterator last,
319 DownloadQuery::DownloadVector* results) const {
320 results->clear();
321 for (; iter != last; ++iter) {
322 if (Matches(**iter))
323 results->push_back(*iter);
324 }
325 if (!order_by_fields_.empty()) {
326 SortFieldVector order_terms;
327 for (OrderTermVector::const_iterator iter = order_by_fields_.begin();
328 iter != order_by_fields_.end(); ++iter) {
329 SortFieldInterface* sort_field = GetSortField(
330 iter->name, iter->direction);
Randy Smith (Not in Mondays) 2011/11/23 21:07:34 Any reason not to do this as the Sort calls are be
benjhayden 2011/11/30 16:21:47 I meant to do that and forgot. It required moving
331 if (sort_field)
332 order_terms.push_back(sort_field);
333 }
334 std::partial_sort(results->begin(),
335 results->begin() + std::min(limit_, results->size()),
336 results->end(),
337 DownloadComparator(order_terms));
338 STLDeleteElements(&order_terms);
339 }
340 if (results->size() > limit_)
341 results->resize(limit_);
342 }
343
344 template void DownloadQuery::Search(
345 std::set<DownloadItem*>::const_iterator iter,
346 const std::set<DownloadItem*>::const_iterator last,
347 DownloadQuery::DownloadVector* results) const;
348 template void DownloadQuery::Search(
349 std::vector<DownloadItem*>::const_iterator iter,
350 const std::vector<DownloadItem*>::const_iterator last,
351 DownloadQuery::DownloadVector* results) const;
352 template void DownloadQuery::Search(
353 std::vector<DownloadItem*>::iterator iter,
354 const std::vector<DownloadItem*>::iterator last,
355 DownloadQuery::DownloadVector* results) const;
356
357 } // namespace download_util
358
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698