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

Unified 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, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/download/download_query.cc
diff --git a/content/browser/download/download_query.cc b/content/browser/download/download_query.cc
new file mode 100644
index 0000000000000000000000000000000000000000..89bb19ef9ab54c9231c953b89ba4429e8fe50654
--- /dev/null
+++ b/content/browser/download/download_query.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/download_query.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/string_split.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "content/browser/download/download_item.h"
+#include "googleurl/src/gurl.h"
+#include "unicode/regex.h"
+
+namespace download_util {
+
+// The FieldInterfaces allow us to keep the templateyness out of the header.
+
+// Filter fields can be used to filter DownloadItems out of the result set.
+class DownloadQuery::FilterFieldInterface {
+ public:
+ virtual ~FilterFieldInterface() {}
+ virtual bool Valid() = 0;
+ virtual bool Matches(const DownloadItem& item) const = 0;
+};
+
+// Sort fields are used by DownloadComparator to sort DownloadItems.
+class SortFieldInterface {
+ public:
+ virtual ~SortFieldInterface() {}
+
+ virtual DownloadQuery::SortFieldDirection direction() const = 0;
+
+ // Return 0 when left's field is equivalent to right's field, -1 when left <
+ // right, or 1 when left > right.
+ virtual int Compare(const DownloadItem& left,
+ const DownloadItem& right) const = 0;
+};
+
+namespace {
+
+typedef std::vector<SortFieldInterface*> SortFieldVector;
+
+// Functor passed to std::sort to sort DownloadItems.
+class DownloadComparator {
+ public:
+ DownloadComparator(const SortFieldVector& terms)
+ : terms_(terms) {
+ }
+
+ // Returns true if |left| sorts before |right|.
+ bool operator() (const DownloadItem* left, const DownloadItem* right);
+
+ private:
+ const SortFieldVector& terms_;
+
+ // std::sort requires this class to be copyable.
+};
+
+bool DownloadComparator::operator() (const DownloadItem* left,
+ const DownloadItem* right) {
+ for (SortFieldVector::const_iterator term = terms_.begin();
+ term != terms_.end(); ++term) {
+ int comparison = (*term)->Compare(*left, *right);
+ if (comparison != 0)
+ return ((*term)->direction() == DownloadQuery::ASCENDING) ==
+ (comparison < 0);
+ }
+ if (left->GetId() != right->GetId())
+ return left->GetId() < right->GetId();
+ CHECK_NE(left->GetDbHandle(), right->GetDbHandle());
+ return left->GetDbHandle() < right->GetDbHandle();
+}
+
+static int get_start_time(const DownloadItem& item) {
+ return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
+}
+
+static int get_end_time(const DownloadItem& item) {
+ return 0; // TODO(benjhayden): endTime
+}
+
+static bool get_danger_accepted(const DownloadItem& item) {
+ return (item.GetSafetyState() == DownloadItem::DANGEROUS_BUT_VALIDATED);
+}
+
+static string16 get_filename(const DownloadItem& item) {
+ 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.
+}
+
+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.
+class FilterField : public DownloadQuery::FilterFieldInterface {
+ public:
+ 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
+ explicit FilterField(const ValueType& value) : value_(value) {}
+ virtual ~FilterField() {}
+ virtual bool Valid() OVERRIDE { return true; }
+
+ protected:
+ const ValueType& value() const { return value_; }
+
+ private:
+ ValueType value_;
+};
+
+template <typename StringType>
+std::string ToUTF8(const StringType& s);
+
+template<> std::string ToUTF8(const std::string& s) {
+ return s;
+}
+
+template<> std::string ToUTF8(const string16& s) {
+ return UTF16ToUTF8(s);
+}
+
+template <typename StringType>
+class FilterFieldRegex : public FilterField<StringType> {
+ public:
+ explicit FilterFieldRegex(const StringType& value)
+ : FilterField<StringType>(value) {
+ }
+ virtual ~FilterFieldRegex() {}
+ using FilterField<StringType>::value;
+ virtual bool Valid() OVERRIDE {
+ UParseError re_err;
+ UErrorCode re_status = U_ZERO_ERROR;
+ scoped_ptr<icu::RegexPattern> pattern(icu::RegexPattern::compile(
+ icu::UnicodeString::fromUTF8(ToUTF8(value())),
+ re_err, re_status));
+ return U_SUCCESS(re_status);
+ }
+
+ protected:
+ bool RegexMatches(const StringType& text) const {
+ icu::UnicodeString pattern(ToUTF8(value()).c_str());
+ icu::UnicodeString input(ToUTF8(text).c_str());
+ UErrorCode status = U_ZERO_ERROR;
+ icu::RegexMatcher match(pattern, input, 0, status);
+ return match.find();
+ }
+};
+
+template <typename ValueType>
+class SortField : public SortFieldInterface {
+ public:
+ explicit SortField(DownloadQuery::SortFieldDirection direction)
+ : direction_(direction) {
+ }
+ virtual ~SortField() {}
+
+ virtual DownloadQuery::SortFieldDirection direction() const {
+ return direction_;
+ }
+
+ virtual ValueType GetField(const DownloadItem& item) const = 0;
+
+ virtual int Compare(const DownloadItem& left,
+ const DownloadItem& right) const OVERRIDE {
+ ValueType left_value = GetField(left), right_value = GetField(right);
+ if (left_value > right_value) return 1;
+ if (left_value < right_value) return -1;
+ if (left_value == right_value) return 0;
+ NOTREACHED();
+ return 0;
+ }
+
+ private:
+ DownloadQuery::SortFieldDirection direction_;
+};
+
+#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.
+ class __name : public __base { \
+ public: \
+ explicit __name(__ctor_arg_type x) : __base(x) {} \
+ virtual __method(const DownloadItem& item) const OVERRIDE { \
+ return __expr; \
+ } \
+ }; \
+ new __name(__ctor_arg); \
+ })
+
+SortFieldInterface* GetSortField(DownloadQuery::SortFieldName name,
+ DownloadQuery::SortFieldDirection direction) {
+ switch (name) {
+#define SORT_FIELD(__name, __type, __expr) \
+ case DownloadQuery::SORT_FIELD_ ## __name: return LAMBDA( \
+ SortField ## __name, SortField<__type>, __type GetField, __expr, \
+ DownloadQuery::SortFieldDirection, direction)
+ SORT_FIELD(START_TIME, int, get_start_time(item));
+ SORT_FIELD(URL, std::string, item.GetOriginalUrl().spec());
+ SORT_FIELD(FILENAME, string16, get_filename(item));
+ SORT_FIELD(DANGER, DownloadStateInfo::DangerType, item.GetDangerType());
+ SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item));
+ SORT_FIELD(STATE, DownloadItem::DownloadState, item.GetState());
+ SORT_FIELD(PAUSED, bool, item.IsPaused());
+ SORT_FIELD(MIME, std::string, item.GetMimeType());
+ SORT_FIELD(END_TIME, int, get_end_time(item));
+ SORT_FIELD(BYTES_RECEIVED, int, item.GetReceivedBytes());
+ SORT_FIELD(TOTAL_BYTES, int, item.GetTotalBytes());
+ SORT_FIELD(FILE_SIZE, int, 0); // TODO
+ SORT_FIELD(ERROR, int, 0); // TODO
+#undef SORT_FIELD
+ default: return NULL;
+ }
+}
+
+} // anonymous namespace
+
+DownloadQuery::DownloadQuery()
+ : limit_(kuint32max) {
+}
+
+DownloadQuery::~DownloadQuery() {
+ STLDeleteElements(&filter_fields_);
+}
+
+bool DownloadQuery::AddFilter(FilterFieldInterface* field) {
+ if (!field->Valid()) {
+ delete field;
+ return false;
+ }
+ filter_fields_.push_back(field);
+ return true;
+}
+
+#define START_FILTER_FIELDS(__type) \
+ template<> bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, \
+ const __type& _value) { \
+ typedef __type ValueType; \
+ switch (static_cast<int>(name)) {
+#define FILTER_FIELD(__name, __expr) \
+ case FILTER_FIELD_ ## __name: return AddFilter( \
+ LAMBDA(FilterField ## __name, FilterField<ValueType>, bool Matches, \
+ __expr, const ValueType&, _value));
+#define FILTER_FIELD_REGEX(__name, __expr) \
+ case FILTER_FIELD_ ## __name ## _REGEX: return AddFilter(LAMBDA( \
+ FilterField ## __name ## _REGEX, FilterFieldRegex<ValueType>, \
+ bool Matches, RegexMatches(__expr), const ValueType&, _value));
+#define END_FILTER_FIELDS \
+ } \
+ return false; \
+ }
+
+START_FILTER_FIELDS(int)
+ FILTER_FIELD(START_TIME, get_start_time(item) == value())
+ FILTER_FIELD(END_TIME, get_end_time(item) == value())
+ FILTER_FIELD(BYTES_RECEIVED, item.GetReceivedBytes() == value())
+ FILTER_FIELD(TOTAL_BYTES, item.GetTotalBytes() == value())
+ FILTER_FIELD(STARTED_BEFORE, get_start_time(item) < value())
+ FILTER_FIELD(STARTED_AFTER, get_start_time(item) > value())
+ FILTER_FIELD(ENDED_BEFORE, get_end_time(item) < value())
+ FILTER_FIELD(ENDED_AFTER, get_end_time(item) > value())
+ FILTER_FIELD(TOTAL_BYTES_GREATER, item.GetTotalBytes() > value())
+ FILTER_FIELD(TOTAL_BYTES_LESS, item.GetTotalBytes() < value())
+ FILTER_FIELD(FILE_SIZE_GREATER, false) // TODO
+ FILTER_FIELD(FILE_SIZE_LESS, false) // TODO
+ FILTER_FIELD(FILE_SIZE, false) // TODO
+ FILTER_FIELD(ERROR, false) // TODO
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(bool)
+ FILTER_FIELD(DANGER_ACCEPTED, get_danger_accepted(item) == value())
+ FILTER_FIELD(PAUSED, item.IsPaused() == value())
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(std::string)
+ FILTER_FIELD(URL, item.GetOriginalUrl().spec() == value())
+ FILTER_FIELD_REGEX(URL, item.GetOriginalUrl().spec())
+ FILTER_FIELD(MIME, item.GetMimeType() == value())
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(string16)
+ FILTER_FIELD(QUERY, item.MatchesQuery(value()))
+ FILTER_FIELD(FILENAME, get_filename(item) == value())
+ FILTER_FIELD_REGEX(FILENAME, get_filename(item))
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(base::Callback<bool(const DownloadItem& item)>)
+ FILTER_FIELD(FILTER, value().Run(item))
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(DownloadStateInfo::DangerType)
+ FILTER_FIELD(DANGER, item.GetDangerType() == value())
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(DownloadItem::DownloadState)
+ FILTER_FIELD(STATE, item.GetState() == value())
+END_FILTER_FIELDS
+
+#undef START_FILTER_FIELDS
+#undef FILTER_FIELD
+#undef END_FILTER_FIELDS
+
+void DownloadQuery::Sort(DownloadQuery::SortFieldName name,
+ DownloadQuery::SortFieldDirection direction) {
+ order_by_fields_.push_back(OrderTerm(name, direction));
+}
+
+bool DownloadQuery::Matches(const DownloadItem& item) const {
+ for (FilterFieldVector::const_iterator filter_field = filter_fields_.begin();
+ filter_field != filter_fields_.end(); ++filter_field) {
+ if (!(*filter_field)->Matches(item))
+ return false;
+ }
+ return true;
+}
+
+template <typename InputIterator>
+void DownloadQuery::Search(InputIterator iter, const InputIterator last,
+ DownloadQuery::DownloadVector* results) const {
+ results->clear();
+ for (; iter != last; ++iter) {
+ if (Matches(**iter))
+ results->push_back(*iter);
+ }
+ if (!order_by_fields_.empty()) {
+ SortFieldVector order_terms;
+ for (OrderTermVector::const_iterator iter = order_by_fields_.begin();
+ iter != order_by_fields_.end(); ++iter) {
+ SortFieldInterface* sort_field = GetSortField(
+ 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
+ if (sort_field)
+ order_terms.push_back(sort_field);
+ }
+ std::partial_sort(results->begin(),
+ results->begin() + std::min(limit_, results->size()),
+ results->end(),
+ DownloadComparator(order_terms));
+ STLDeleteElements(&order_terms);
+ }
+ if (results->size() > limit_)
+ results->resize(limit_);
+}
+
+template void DownloadQuery::Search(
+ std::set<DownloadItem*>::const_iterator iter,
+ const std::set<DownloadItem*>::const_iterator last,
+ DownloadQuery::DownloadVector* results) const;
+template void DownloadQuery::Search(
+ std::vector<DownloadItem*>::const_iterator iter,
+ const std::vector<DownloadItem*>::const_iterator last,
+ DownloadQuery::DownloadVector* results) const;
+template void DownloadQuery::Search(
+ std::vector<DownloadItem*>::iterator iter,
+ const std::vector<DownloadItem*>::iterator last,
+ DownloadQuery::DownloadVector* results) const;
+
+} // namespace download_util
+

Powered by Google App Engine
This is Rietveld 408576698