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

Unified 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: rewrite 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
« no previous file with comments | « content/browser/download/download_query.h ('k') | content/browser/download/download_query_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..20ad559276bc71cf3909f3bc0fe02f4e56a7bd89
--- /dev/null
+++ b/content/browser/download/download_query.cc
@@ -0,0 +1,355 @@
+// 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/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/string_split.h"
+#include "base/utf_string_conversions.h"
+#include "unicode/regex.h"
+#include "content/browser/download/download_item.h"
+
+namespace download_util {
+
+// The FieldInterfaces allow us to keep the templateyness out of the header.
+
+// Filter fields can be used to filter DownloadVector 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 DownloadVector.
+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 DownloadVector.
+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->id() != right->id())
+ return left->id() < right->id();
+ CHECK_NE(left->db_handle(), right->db_handle());
+ return left->db_handle() < right->db_handle();
+}
+
+static int get_start_time(const DownloadItem& item) {
+ return (item.start_time() - 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.safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED);
+}
+
+static string16 get_filename(const DownloadItem& item) {
+ return item.full_path().LossyDisplayName();
+}
+
+template <typename ValueType_>
+class FilterField : public DownloadQuery::FilterFieldInterface {
+ public:
+ typedef ValueType_ ValueType;
+ 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;
+ pattern_.reset(icu::RegexPattern::compile(
+ icu::UnicodeString::fromUTF8(ToUTF8(value())),
+ re_err, re_status));
+ return U_SUCCESS(re_status);
+ }
+
+ protected:
+ bool RegexMatches(const StringType& text) const {
+ UErrorCode status = U_ZERO_ERROR;
+ scoped_ptr<icu::RegexMatcher> matcher(pattern_->matcher(
+ icu::UnicodeString::fromUTF8(ToUTF8(text)), status));
+ return U_SUCCESS(status) &&
+ matcher->find(0, status);
+ }
+
+ private:
+ scoped_ptr<icu::RegexPattern> pattern_;
+};
+
+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) ({ \
+ 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.original_url().spec());
+ SORT_FIELD(FILENAME, string16, get_filename(item));
+ SORT_FIELD(DANGER, DownloadItem::DangerType, item.GetDangerType());
+ SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item));
+ SORT_FIELD(STATE, DownloadItem::DownloadState, item.state());
+ SORT_FIELD(PAUSED, bool, item.is_paused());
+ SORT_FIELD(MIME, std::string, item.mime_type());
+ SORT_FIELD(END_TIME, int, get_end_time(item));
+ SORT_FIELD(BYTES_RECEIVED, int, item.received_bytes());
+ SORT_FIELD(TOTAL_BYTES, int, item.total_bytes());
+ 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))
+ FILTER_FIELD(END_TIME, get_end_time(item))
+ FILTER_FIELD(BYTES_RECEIVED, item.received_bytes())
+ FILTER_FIELD(TOTAL_BYTES, item.total_bytes())
+ 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.total_bytes() > value())
+ FILTER_FIELD(TOTAL_BYTES_LESS, item.total_bytes() < value())
+ FILTER_FIELD(FILE_SIZE_GREATER, false) // TODO
+ FILTER_FIELD(FILE_SIZE_LESS, false) // TODO
+ FILTER_FIELD(FILE_SIZE, 0) // TODO
+ FILTER_FIELD(ERROR, 0) // TODO
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(bool)
+ FILTER_FIELD(DANGER_ACCEPTED, get_danger_accepted(item))
+ FILTER_FIELD(PAUSED, item.is_paused())
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(std::string)
+ FILTER_FIELD(URL, item.original_url().spec() == value())
+ FILTER_FIELD_REGEX(URL, item.original_url().spec())
+ FILTER_FIELD(MIME, item.mime_type() == 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(DownloadItem::DangerType)
+ FILTER_FIELD(DANGER, item.GetDangerType() == value())
+END_FILTER_FIELDS
+
+START_FILTER_FIELDS(DownloadItem::DownloadState)
+ FILTER_FIELD(STATE, item.state() == 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);
+ 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
+
« no previous file with comments | « content/browser/download/download_query.h ('k') | content/browser/download/download_query_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698