Index: chrome/browser/chromeos/printing/combining_printer_detector.cc |
diff --git a/chrome/browser/chromeos/printing/combining_printer_detector.cc b/chrome/browser/chromeos/printing/combining_printer_detector.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..920d42906128c9e0db3b22ce6941d9484b920582 |
--- /dev/null |
+++ b/chrome/browser/chromeos/printing/combining_printer_detector.cc |
@@ -0,0 +1,153 @@ |
+// Copyright 2017 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 "chrome/browser/chromeos/printing/combining_printer_detector.h" |
+ |
+#include <map> |
+#include <utility> |
+#include <vector> |
+ |
+#include "base/memory/ptr_util.h" |
+#include "base/observer_list.h" |
+#include "base/scoped_observer.h" |
+#include "chrome/browser/chromeos/printing/printer_detector.h" |
+#include "chromeos/printing/printer_configuration.h" |
+ |
+namespace chromeos { |
+namespace { |
+ |
+class CombiningPrinterDetectorImpl; |
+ |
+// We can't just implement PrinterDetector::Observer in |
+// CombiningPrinterDetectorImpl because we need to be able to determing *which* |
+// underlying detector is giving us new information. Thus we use delegate |
+// instantions to allow for a disambiguation about the source of a |
+// PrinterDetector callback from one of the detectors being combined. |
+class ObserverDelegate : public PrinterDetector::Observer { |
+ public: |
+ ObserverDelegate(CombiningPrinterDetectorImpl* parent, |
+ PrinterDetector* detector) |
+ : parent_(parent), observer_(this) { |
+ observer_.Add(detector); |
+ } |
+ void OnPrintersFound(const std::vector<Printer>& printers) override; |
+ void OnPrinterScanComplete() override; |
+ |
+ private: |
+ CombiningPrinterDetectorImpl* parent_; |
+ ScopedObserver<PrinterDetector, PrinterDetector::Observer> observer_; |
+}; |
+ |
+class CombiningPrinterDetectorImpl : public CombiningPrinterDetector { |
+ public: |
+ ~CombiningPrinterDetectorImpl() override = default; |
+ |
+ void AddDetector(PrinterDetector* detector) override { |
+ detectors_.push_back(detector); |
+ delegates_.push_back(base::MakeUnique<ObserverDelegate>(this, detector)); |
+ printers_.insert({delegates_.back().get(), detector->GetPrinters()}); |
+ scan_done_[delegates_.back().get()] = false; |
+ } |
+ |
+ void AddOwnedDetector(std::unique_ptr<PrinterDetector> detector) override { |
+ AddDetector(detector.get()); |
+ owned_detectors_.emplace_back(std::move(detector)); |
+ } |
+ |
+ // PrinterDetector implementations. |
+ void AddObserver(PrinterDetector::Observer* observer) override { |
+ observer_list_.AddObserver(observer); |
+ } |
+ |
+ void RemoveObserver(PrinterDetector::Observer* observer) override { |
+ observer_list_.RemoveObserver(observer); |
+ } |
+ |
+ // Note this is *not* the PrinterDetectorObserver interface directly, |
+ // it's the entry point for ObserverDelegates to pass along those messages |
+ // into this class. |
+ void OnPrintersFound(const ObserverDelegate* source, |
+ const std::vector<Printer>& printers) { |
+ // If this object doesn't know about the delegate trying to update its |
+ // printers, we missed delegate registration somehow, which shouldn't |
+ // happen. |
+ DCHECK(base::ContainsKey(printers_, source)); |
+ printers_[source] = printers; |
+ std::vector<Printer> all_printers = GetPrinters(); |
+ for (PrinterDetector::Observer& observer : observer_list_) { |
+ observer.OnPrintersFound(all_printers); |
+ } |
+ } |
+ |
+ void OnPrinterScanComplete(const ObserverDelegate* source) { |
+ DCHECK(base::ContainsKey(printers_, source)); |
+ bool& scan_done = scan_done_[source]; |
+ if (!scan_done) { |
+ scan_done = true; |
+ for (const auto& entry : scan_done_) { |
+ if (!entry.second) { |
+ // Not all done yet. |
+ return; |
+ } |
+ } |
+ // Final outstanding scan just finished, notify observers. |
+ for (PrinterDetector::Observer& observer : observer_list_) { |
+ observer.OnPrinterScanComplete(); |
+ } |
+ } |
+ } |
+ |
+ // Aggregate the printers from all underlying sources and return them. |
+ std::vector<Printer> GetPrinters() override { |
+ std::vector<Printer> ret; |
+ for (const auto& entry : printers_) { |
+ ret.insert(ret.end(), entry.second.begin(), entry.second.end()); |
+ } |
+ return ret; |
+ } |
+ |
+ void Start() override { |
+ for (PrinterDetector* detector : detectors_) { |
+ detector->Start(); |
+ } |
+ } |
+ |
+ private: |
+ // Map from observer delegate to the most recent list of printers from that |
+ // observer. |
+ std::map<const ObserverDelegate*, std::vector<Printer>> printers_; |
+ |
+ // Map from observer delegate to whether or not that observer has completed |
+ // its scan. |
+ std::map<const ObserverDelegate*, bool> scan_done_; |
+ |
+ // Observers of this object. |
+ base::ObserverList<PrinterDetector::Observer> observer_list_; |
+ |
+ std::vector<std::unique_ptr<PrinterDetector>> owned_detectors_; |
+ |
+ // Memory management -- this just exists to ensure that the held |
+ // elements get cleaned up. |
+ std::vector<std::unique_ptr<ObserverDelegate>> delegates_; |
+ |
+ // All detectors used by the combining detector, owned or unowned. |
+ std::vector<PrinterDetector*> detectors_; |
+}; |
+ |
+void ObserverDelegate::OnPrintersFound(const std::vector<Printer>& printers) { |
+ parent_->OnPrintersFound(this, printers); |
+} |
+ |
+void ObserverDelegate::OnPrinterScanComplete() { |
+ parent_->OnPrinterScanComplete(this); |
+} |
+ |
+} // namespace |
+ |
+// static |
+std::unique_ptr<CombiningPrinterDetector> CombiningPrinterDetector::Create() { |
+ return base::MakeUnique<CombiningPrinterDetectorImpl>(); |
+} |
+ |
+} // namespace chromeos |