1 // Copyright 2015 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_UI_WEBUI_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_
6 #define CHROME_BROWSER_UI_WEBUI_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <set>
12 
13 #include "base/callback_forward.h"
14 #include "base/macros.h"
15 #include "base/strings/string16.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "chrome/browser/ui/webui/downloads/downloads.mojom.h"
19 #include "components/download/content/public/all_download_item_notifier.h"
20 #include "components/download/public/common/download_item.h"
21 #include "mojo/public/cpp/bindings/pending_remote.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 
24 namespace content {
25 class DownloadManager;
26 }
27 
28 // A class that tracks all downloads activity and keeps a sorted representation
29 // of the downloads as chrome://downloads wants to display them.
30 class DownloadsListTracker
31     : public download::AllDownloadItemNotifier::Observer {
32  public:
33   DownloadsListTracker(content::DownloadManager* download_manager,
34                        mojo::PendingRemote<downloads::mojom::Page> page);
35   ~DownloadsListTracker() override;
36 
37   // Clears all downloads on the page if currently sending updates and resets
38   // chunk tracking data.
39   void Reset();
40 
41   // This class only cares about downloads that match |search_terms|.
42   // An empty list shows all downloads (the default). Returns true if
43   // |search_terms| differ from the current ones.
44   bool SetSearchTerms(const std::vector<std::string>& search_terms);
45 
46   // Starts sending updates and sends a capped amount of downloads. Tracks which
47   // downloads have been sent. Re-call this to send more.
48   void StartAndSendChunk();
49 
50   // Stops sending updates to the page.
51   void Stop();
52 
53   content::DownloadManager* GetMainNotifierManager() const;
54   content::DownloadManager* GetOriginalNotifierManager() const;
55 
56   // AllDownloadItemNotifier::Observer:
57   void OnDownloadCreated(content::DownloadManager* manager,
58                          download::DownloadItem* download_item) override;
59   void OnDownloadUpdated(content::DownloadManager* manager,
60                          download::DownloadItem* download_item) override;
61   void OnDownloadRemoved(content::DownloadManager* manager,
62                          download::DownloadItem* download_item) override;
63 
64  protected:
65   // Testing constructor.
66   DownloadsListTracker(content::DownloadManager* download_manager,
67                        mojo::PendingRemote<downloads::mojom::Page> page,
68                        base::Callback<bool(const download::DownloadItem&)>);
69 
70   // Creates a dictionary value that's sent to the page as JSON.
71   virtual downloads::mojom::DataPtr CreateDownloadData(
72       download::DownloadItem* item) const;
73 
74   // Exposed for testing.
75   bool IsIncognito(const download::DownloadItem& item) const;
76 
77   const download::DownloadItem* GetItemForTesting(size_t index) const;
78 
79   void SetChunkSizeForTesting(size_t chunk_size);
80 
81  private:
82   struct StartTimeComparator {
83     bool operator()(const download::DownloadItem* a,
84                     const download::DownloadItem* b) const;
85   };
86   using SortedSet = std::set<download::DownloadItem*, StartTimeComparator>;
87 
88   // Called by both constructors to initialize common state.
89   void Init();
90 
91   // Clears and re-inserts all downloads items into |sorted_items_|.
92   void RebuildSortedItems();
93 
94   // Whether |item| should show on the current page.
95   bool ShouldShow(const download::DownloadItem& item) const;
96 
97   // Returns the index of |item| in |sorted_items_|.
98   size_t GetIndex(const SortedSet::iterator& item) const;
99 
100   // Calls "insertItems" if sending updates and the page knows about |insert|.
101   void InsertItem(const SortedSet::iterator& insert);
102 
103   // Calls "updateItem" if sending updates and the page knows about |update|.
104   void UpdateItem(const SortedSet::iterator& update);
105 
106   // Removes the item that corresponds to |remove| and sends "removeItems"
107   // if sending updates.
108   void RemoveItem(const SortedSet::iterator& remove);
109 
110   download::AllDownloadItemNotifier main_notifier_;
111   std::unique_ptr<download::AllDownloadItemNotifier> original_notifier_;
112 
113   mojo::Remote<downloads::mojom::Page> page_;
114 
115   // Callback used to determine if an item should show on the page. Set to
116   // |ShouldShow()| in default constructor, passed in while testing.
117   base::Callback<bool(const download::DownloadItem&)> should_show_;
118 
119   // When this is true, all changes to downloads that affect the page are sent
120   // via JavaScript.
121   bool sending_updates_ = false;
122 
123   SortedSet sorted_items_;
124 
125   // The number of items sent to the page so far.
126   size_t sent_to_page_ = 0u;
127 
128   // The maximum number of items sent to the page at a time.
129   size_t chunk_size_ = 20u;
130 
131   // Current search terms.
132   std::vector<base::string16> search_terms_;
133 
134   DISALLOW_COPY_AND_ASSIGN(DownloadsListTracker);
135 };
136 
137 #endif  // CHROME_BROWSER_UI_WEBUI_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_
138