1// Copyright (c) 2012 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#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_QUERY_H_
6#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_QUERY_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/callback_forward.h"
13#include "content/public/browser/download_item.h"
14
15namespace base {
16class Value;
17}
18
19// Filter and sort a vector of DownloadItem*s.
20//
21// The following example copies from |all_items| to |results| those
22// DownloadItem*s whose start time is 0 and whose id is odd, sorts primarily by
23// bytes received ascending and secondarily by url descending, and limits the
24// results to 20 items. Any number of filters or sorters is allowed. If all
25// sorters compare two DownloadItems equivalently, then they are sorted by their
26// id ascending.
27//
28// DownloadQuery query;
29// scoped_ptr<base::Value> start_time(base::Balue::CreateIntegerValue(0));
30// CHECK(query.AddFilter(FILTER_START_TIME, *start_time.get()));
31// bool FilterOutOddDownloads(const DownloadItem& item) {
32//   return 0 == (item.GetId() % 2);
33// }
34// CHECK(query.AddFilter(base::Bind(&FilterOutOddDownloads)));
35// query.AddSorter(SORT_BYTES_RECEIVED, ASCENDING);
36// query.AddSorter(SORT_URL, DESCENDING);
37// query.Limit(20);
38// DownloadVector all_items, results;
39// query.Search(all_items.begin(), all_items.end(), &results);
40class DownloadQuery {
41 public:
42  typedef std::vector<content::DownloadItem*> DownloadVector;
43
44  // FilterCallback is a Callback that takes a DownloadItem and returns true if
45  // the item matches the filter and false otherwise.
46  // query.AddFilter(base::Bind(&YourFilterFunction));
47  typedef base::Callback<bool(const content::DownloadItem&)> FilterCallback;
48
49  // All times are ISO 8601 strings.
50  enum FilterType {
51    FILTER_BYTES_RECEIVED,       // int
52    FILTER_DANGER_ACCEPTED,      // bool
53    FILTER_ENDED_AFTER,          // string
54    FILTER_ENDED_BEFORE,         // string
55    FILTER_END_TIME,             // string
56    FILTER_EXISTS,               // bool
57    FILTER_FILENAME,             // string
58    FILTER_FILENAME_REGEX,       // string
59    FILTER_MIME,                 // string
60    FILTER_PAUSED,               // bool
61    FILTER_QUERY,                // vector<base::string16>
62    FILTER_STARTED_AFTER,        // string
63    FILTER_STARTED_BEFORE,       // string
64    FILTER_START_TIME,           // string
65    FILTER_TOTAL_BYTES,          // int
66    FILTER_TOTAL_BYTES_GREATER,  // int
67    FILTER_TOTAL_BYTES_LESS,     // int
68    FILTER_URL,                  // string
69    FILTER_URL_REGEX,            // string
70  };
71
72  enum SortType {
73    SORT_BYTES_RECEIVED,
74    SORT_DANGER,
75    SORT_DANGER_ACCEPTED,
76    SORT_END_TIME,
77    SORT_EXISTS,
78    SORT_FILENAME,
79    SORT_MIME,
80    SORT_PAUSED,
81    SORT_START_TIME,
82    SORT_STATE,
83    SORT_TOTAL_BYTES,
84    SORT_URL,
85  };
86
87  enum SortDirection {
88    ASCENDING,
89    DESCENDING,
90  };
91
92  DownloadQuery();
93  ~DownloadQuery();
94
95  // Adds a new filter of type |type| with value |value| and returns true if
96  // |type| is valid and |value| is the correct Value-type and well-formed.
97  // Returns false if |type| is invalid or |value| is the incorrect Value-type
98  // or malformed.  Search() will filter out all DownloadItem*s that do not
99  // match all filters.  Multiple instances of the same FilterType are allowed,
100  // so you can pass two regexes to AddFilter(URL_REGEX,...) in order to
101  // Search() for items whose url matches both regexes. You can also pass two
102  // different DownloadStates to AddFilter(), which will cause Search() to
103  // filter out all items.
104  bool AddFilter(const FilterCallback& filter);
105  bool AddFilter(FilterType type, const base::Value& value);
106  void AddFilter(content::DownloadDangerType danger);
107  void AddFilter(content::DownloadItem::DownloadState state);
108
109  // Adds a new sorter of type |type| with direction |direction|.  After
110  // filtering DownloadItem*s, Search() will sort the results primarily by the
111  // sorter from the first call to Sort(), secondarily by the sorter from the
112  // second call to Sort(), and so on. For example, if the InputIterator passed
113  // to Search() yields four DownloadItems {id:0, error:0, start_time:0}, {id:1,
114  // error:0, start_time:1}, {id:2, error:1, start_time:0}, {id:3, error:1,
115  // start_time:1}, and Sort is called twice, once with (SORT_ERROR, ASCENDING)
116  // then with (SORT_START_TIME, DESCENDING), then Search() will return items
117  // ordered 1,0,3,2.
118  void AddSorter(SortType type, SortDirection direction);
119
120  // Limit the size of search results to |limit|.
121  void Limit(size_t limit) { limit_ = limit; }
122
123  // Filters DownloadItem*s from |iter| to |last| into |results|, sorts
124  // |results|, and limits the size of |results|. |results| must be non-NULL.
125  template <typename InputIterator>
126  void Search(InputIterator iter, const InputIterator last,
127              DownloadVector* results) const {
128    results->clear();
129    for (; iter != last; ++iter) {
130      if (Matches(**iter)) results->push_back(*iter);
131    }
132    FinishSearch(results);
133  }
134
135 private:
136  struct Sorter;
137  class DownloadComparator;
138  typedef std::vector<FilterCallback> FilterCallbackVector;
139  typedef std::vector<Sorter> SorterVector;
140
141  bool FilterRegex(const std::string& regex_str,
142                   const base::Callback<std::string(
143                       const content::DownloadItem&)>& accessor);
144  bool Matches(const content::DownloadItem& item) const;
145  void FinishSearch(DownloadVector* results) const;
146
147  FilterCallbackVector filters_;
148  SorterVector sorters_;
149  size_t limit_;
150
151  DISALLOW_COPY_AND_ASSIGN(DownloadQuery);
152};
153
154#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_QUERY_H_
155