Home | History | Annotate | Download | only in printing
      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 #include "chrome/browser/printing/background_printing_manager.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/printing/print_job.h"
     10 #include "chrome/browser/printing/print_preview_dialog_controller.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "content/public/browser/notification_details.h"
     13 #include "content/public/browser/notification_source.h"
     14 #include "content/public/browser/render_view_host.h"
     15 #include "content/public/browser/web_contents.h"
     16 #include "content/public/browser/web_contents_delegate.h"
     17 #include "content/public/browser/web_contents_observer.h"
     18 
     19 using content::BrowserThread;
     20 using content::WebContents;
     21 
     22 namespace printing {
     23 
     24 class BackgroundPrintingManager::Observer
     25     : public content::WebContentsObserver {
     26  public:
     27   Observer(BackgroundPrintingManager* manager, WebContents* web_contents);
     28 
     29  private:
     30   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
     31   virtual void WebContentsDestroyed() OVERRIDE;
     32 
     33   BackgroundPrintingManager* manager_;
     34 };
     35 
     36 BackgroundPrintingManager::Observer::Observer(
     37     BackgroundPrintingManager* manager, WebContents* web_contents)
     38     : content::WebContentsObserver(web_contents),
     39       manager_(manager) {
     40 }
     41 
     42 void BackgroundPrintingManager::Observer::RenderProcessGone(
     43     base::TerminationStatus status) {
     44   manager_->DeletePreviewContents(web_contents());
     45 }
     46 void BackgroundPrintingManager::Observer::WebContentsDestroyed() {
     47   manager_->DeletePreviewContents(web_contents());
     48 }
     49 
     50 BackgroundPrintingManager::BackgroundPrintingManager() {
     51   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     52 }
     53 
     54 BackgroundPrintingManager::~BackgroundPrintingManager() {
     55   DCHECK(CalledOnValidThread());
     56   // The might be some WebContentses still in |printing_contents_map_| at this
     57   // point (e.g. when the last remaining tab closes and there is still a print
     58   // preview WebContents trying to print). In such a case it will fail to print,
     59   // but we should at least clean up the observers.
     60   // TODO(thestig): Handle this case better.
     61   STLDeleteValues(&printing_contents_map_);
     62 }
     63 
     64 void BackgroundPrintingManager::OwnPrintPreviewDialog(
     65     WebContents* preview_dialog) {
     66   DCHECK(CalledOnValidThread());
     67   DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog));
     68   CHECK(!HasPrintPreviewDialog(preview_dialog));
     69 
     70   printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog);
     71 
     72   // Watch for print jobs finishing. Everything else is watched for by the
     73   // Observer. TODO(avi, cait): finish the job of removing this last
     74   // notification.
     75   registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
     76                  content::Source<WebContents>(preview_dialog));
     77 
     78   // Activate the initiator.
     79   PrintPreviewDialogController* dialog_controller =
     80       PrintPreviewDialogController::GetInstance();
     81   if (!dialog_controller)
     82     return;
     83   WebContents* initiator = dialog_controller->GetInitiator(preview_dialog);
     84   if (!initiator)
     85     return;
     86   initiator->GetDelegate()->ActivateContents(initiator);
     87 }
     88 
     89 void BackgroundPrintingManager::Observe(
     90     int type,
     91     const content::NotificationSource& source,
     92     const content::NotificationDetails& details) {
     93   DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type);
     94   DeletePreviewContents(content::Source<WebContents>(source).ptr());
     95 }
     96 
     97 void BackgroundPrintingManager::DeletePreviewContents(
     98     WebContents* preview_contents) {
     99   WebContentsObserverMap::iterator i =
    100       printing_contents_map_.find(preview_contents);
    101   if (i == printing_contents_map_.end()) {
    102     // Everyone is racing to be the first to delete the |preview_contents|. If
    103     // this case is hit, someone else won the race, so there is no need to
    104     // continue. <http://crbug.com/100806>
    105     return;
    106   }
    107 
    108   // Stop all observation ...
    109   registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
    110                     content::Source<WebContents>(preview_contents));
    111   Observer* observer = i->second;
    112   printing_contents_map_.erase(i);
    113   delete observer;
    114 
    115   // ... and mortally wound the contents. (Deletion immediately is not a good
    116   // idea in case this was called from RenderViewGone.)
    117   base::MessageLoop::current()->DeleteSoon(FROM_HERE, preview_contents);
    118 }
    119 
    120 std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() {
    121   std::set<content::WebContents*> result;
    122   for (WebContentsObserverMap::iterator i = printing_contents_map_.begin();
    123        i != printing_contents_map_.end(); ++i) {
    124     result.insert(i->first);
    125   }
    126   return result;
    127 }
    128 
    129 bool BackgroundPrintingManager::HasPrintPreviewDialog(
    130     WebContents* preview_dialog) {
    131   return ContainsKey(printing_contents_map_, preview_dialog);
    132 }
    133 
    134 }  // namespace printing
    135