Chromium Code Reviews| Index: components/offline_pages/downloads/download_ui_adapter.cc |
| diff --git a/components/offline_pages/downloads/download_ui_adapter.cc b/components/offline_pages/downloads/download_ui_adapter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..aecbf596f5156ce246e98d4be7cfdbfecc4b2541 |
| --- /dev/null |
| +++ b/components/offline_pages/downloads/download_ui_adapter.cc |
| @@ -0,0 +1,145 @@ |
| +// Copyright 2016 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 "components/offline_pages/downloads/download_ui_adapter.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/guid.h" |
| +#include "base/logging.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| +#include "components/offline_pages/client_namespace_constants.h" |
| +#include "components/offline_pages/downloads/download_ui_item.h" |
| +#include "components/offline_pages/offline_page_model.h" |
| + |
| +namespace offline_pages { |
| + |
| +DownloadUIAdapter::DownloadUIAdapter(OfflinePageModel* model) |
| + : model_(model), |
| + is_loaded_(false), |
| + weak_ptr_factory_(this) { |
| +} |
| + |
| +DownloadUIAdapter::~DownloadUIAdapter() { } |
| + |
| +void DownloadUIAdapter::AddObserver(Observer* observer) { |
| + DCHECK(observer); |
| + if (!observers_.might_have_observers()) |
| + LoadCache(); |
| + observers_.AddObserver(observer); |
| + // If the items are already loaded, post the notification right away. |
| + // Don't just invoke it from here to avoid reentrancy in the client. |
| + if (is_loaded_) { |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, base::Bind(&DownloadUIAdapter::NotifyItemsLoaded, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Unretained(observer))); |
| + } |
| +} |
| + |
| +void DownloadUIAdapter::RemoveObserver(Observer* observer) { |
| + observers_.RemoveObserver(observer); |
| + // Once the last observer is gone, clear cached data. |
| + if (!observers_.might_have_observers()) |
| + ClearCache(); |
| +} |
| + |
| +void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) { |
| + // This signal is not used here. |
| +} |
| + |
| +void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) { |
| + DCHECK(model == model_); |
| + model_->GetAllPages( |
| + base::Bind(&DownloadUIAdapter::OnOfflinePagesChanged, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void DownloadUIAdapter::OfflinePageDeleted( |
| + int64_t offline_id, const ClientId& client_id) { |
| + for(const auto& item : items_) { |
| + if (item.second->guid == client_id.id) { |
| + items_.erase(item.first); |
| + FOR_EACH_OBSERVER(Observer, observers_, ItemDeleted(client_id.id)); |
| + return; |
| + } |
| + } |
| +} |
| + |
| +const DownloadUIItemsMap& DownloadUIAdapter::GetAllItems() const { |
| + return items_; |
| +} |
| + |
| +const DownloadUIItem* |
| + DownloadUIAdapter::GetItem(const std::string& guid) const { |
| + DownloadUIItemsMap::const_iterator it = items_.find(guid); |
| + if (it == items_.end()) |
| + return nullptr; |
| + return (*it).second.get(); |
| +} |
| + |
| +void DownloadUIAdapter::LoadCache() { |
| + DCHECK(!is_loaded_); |
| + // TODO(dimich): Add fetching from RequestQueue as well. |
| + model_->AddObserver(this); |
| + model_->GetAllPages( |
| + base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void DownloadUIAdapter::ClearCache() { |
| + model_->RemoveObserver(this); |
| + items_.clear(); |
| + is_loaded_ = false; |
| +} |
| + |
| +void DownloadUIAdapter::OnOfflinePagesLoaded( |
| + const MultipleOfflinePageItemResult& pages) { |
| + for (const auto& page : pages) { |
| + if (IsVisibleInUI(page)) { |
| + std::unique_ptr<DownloadUIItem> new_item(new DownloadUIItem(page)); |
| + DCHECK(items_.find(new_item->guid) == items_.end()); |
|
fgorski
2016/07/26 16:25:21
I like the idea below:
const std::string& guid = p
Dmitry Titov
2016/07/26 19:56:48
Done.
|
| + items_[new_item->guid] = std::move(new_item); |
| + } |
| + } |
| + is_loaded_ = true; |
| + FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded()); |
| +} |
| + |
| +void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) { |
| + if (observer && observers_.HasObserver(observer)) |
| + observer->ItemsLoaded(); |
| +} |
| + |
| +// This method is only called by OPM when a single item added. |
| +// TODO(dimich): change OPM to have real OnPageAdded/OnPageUpdated and |
| +// simplify this code. |
| +void DownloadUIAdapter::OnOfflinePagesChanged( |
| + const MultipleOfflinePageItemResult& pages) { |
| + std::vector<std::string> added_guids; |
| + for (const auto& page : pages) { |
| + if (!IsVisibleInUI(page)) // Item should be filtered out. |
| + continue; |
| + const std::string& guid = page.client_id.id; |
| + if (items_.find(guid) != items_.end()) // Item already exists. |
| + continue; |
| + std::unique_ptr<DownloadUIItem> item(new DownloadUIItem(page)); |
| + added_guids.push_back(guid); |
|
fgorski
2016/07/26 16:25:21
nit: Can you move this line up or down? It feels l
Dmitry Titov
2016/07/26 19:56:48
Done.
|
| + items_[guid] = std::move(item); |
| + } |
| + // Only one added page |
|
fgorski
2016/07/26 16:25:21
Interesting. Do we even need the update to be in t
Dmitry Titov
2016/07/26 19:56:48
I'd have it in interface. We will need it soon (in
|
| + CHECK(added_guids.size() <= 1); |
| + for (auto& guid : added_guids) { |
| + const DownloadUIItem& item = *(items_.find(guid)->second.get()); |
| + FOR_EACH_OBSERVER(Observer, observers_, ItemAdded(item)); |
| + } |
| +} |
| + |
| +bool DownloadUIAdapter::IsVisibleInUI(const OfflinePageItem& page) { |
| + // TODO(dimich): set up the right filter here. |
| + return page.client_id.name_space == kAsyncNamespace && |
| + base::IsValidGUID(page.client_id.id); |
| +} |
| + |
| +} // namespace offline_pages |