1// Copyright (c) 2011 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/print_job_manager.h"
6
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/prefs/pref_service.h"
9#include "chrome/browser/printing/print_job.h"
10#include "chrome/browser/printing/printer_query.h"
11#include "chrome/common/pref_names.h"
12#include "content/common/notification_service.h"
13#include "printing/printed_document.h"
14#include "printing/printed_page.h"
15
16namespace printing {
17
18PrintJobManager::PrintJobManager() {
19  registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
20                 NotificationService::AllSources());
21}
22
23PrintJobManager::~PrintJobManager() {
24  base::AutoLock lock(lock_);
25  queued_queries_.clear();
26}
27
28void PrintJobManager::OnQuit() {
29#if defined(OS_MACOSX)
30  // OnQuit is too late to try to wait for jobs on the Mac, since the runloop
31  // has already been torn down; instead, StopJobs(true) is called earlier in
32  // the shutdown process, and this is just here in case something sneaks
33  // in after that.
34  StopJobs(false);
35#else
36  StopJobs(true);
37#endif
38  registrar_.RemoveAll();
39}
40
41void PrintJobManager::StopJobs(bool wait_for_finish) {
42  if (current_jobs_.empty())
43    return;
44  {
45    // Copy the array since it can be modified in transit.
46    PrintJobs current_jobs(current_jobs_);
47    // Wait for each job to finish.
48    for (size_t i = 0; i < current_jobs.size(); ++i) {
49      PrintJob* job = current_jobs[i];
50      if (!job)
51        continue;
52      // Wait for 120 seconds for the print job to be spooled.
53      if (wait_for_finish)
54        job->FlushJob(120000);
55      job->Stop();
56    }
57  }
58  current_jobs_.clear();
59}
60
61void PrintJobManager::QueuePrinterQuery(PrinterQuery* job) {
62  base::AutoLock lock(lock_);
63  DCHECK(job);
64  queued_queries_.push_back(make_scoped_refptr(job));
65  DCHECK(job->is_valid());
66}
67
68void PrintJobManager::PopPrinterQuery(int document_cookie,
69                                      scoped_refptr<PrinterQuery>* job) {
70  base::AutoLock lock(lock_);
71  for (PrinterQueries::iterator itr = queued_queries_.begin();
72       itr != queued_queries_.end();
73       ++itr) {
74    PrinterQuery* current_query = *itr;
75    if (current_query->cookie() == document_cookie &&
76        !current_query->is_callback_pending()) {
77      *job = current_query;
78      queued_queries_.erase(itr);
79      DCHECK(current_query->is_valid());
80      return;
81    }
82  }
83}
84
85
86void PrintJobManager::Observe(NotificationType type,
87                              const NotificationSource& source,
88                              const NotificationDetails& details) {
89  switch (type.value) {
90    case NotificationType::PRINT_JOB_EVENT: {
91      OnPrintJobEvent(Source<PrintJob>(source).ptr(),
92                      *Details<JobEventDetails>(details).ptr());
93      break;
94    }
95    case NotificationType::PREF_CHANGED: {
96      const std::string* pref_name = Details<std::string>(details).ptr();
97      if (*pref_name == prefs::kPrintingEnabled) {
98        PrefService *local_state = g_browser_process->local_state();
99        set_printing_enabled(local_state->GetBoolean(prefs::kPrintingEnabled));
100      }
101      break;
102    }
103    default: {
104      NOTREACHED();
105      break;
106    }
107  }
108}
109
110void PrintJobManager::OnPrintJobEvent(
111    PrintJob* print_job,
112    const JobEventDetails& event_details) {
113  switch (event_details.type()) {
114    case JobEventDetails::NEW_DOC: {
115      DCHECK(current_jobs_.end() == std::find(current_jobs_.begin(),
116                                              current_jobs_.end(),
117                                              print_job));
118      // Causes a AddRef().
119      current_jobs_.push_back(make_scoped_refptr(print_job));
120      break;
121    }
122    case JobEventDetails::JOB_DONE: {
123      PrintJobs::iterator itr = std::find(current_jobs_.begin(),
124                                          current_jobs_.end(),
125                                          print_job);
126      DCHECK(current_jobs_.end() != itr);
127      current_jobs_.erase(itr);
128      DCHECK(current_jobs_.end() == std::find(current_jobs_.begin(),
129                                              current_jobs_.end(),
130                                              print_job));
131      break;
132    }
133    case JobEventDetails::FAILED: {
134      PrintJobs::iterator itr = std::find(current_jobs_.begin(),
135                                          current_jobs_.end(),
136                                          print_job);
137      // A failed job may have never started.
138      if (current_jobs_.end() != itr) {
139        current_jobs_.erase(itr);
140        DCHECK(current_jobs_.end() ==
141                  std::find(current_jobs_.begin(),
142                            current_jobs_.end(),
143                            print_job));
144      }
145      break;
146    }
147    case JobEventDetails::USER_INIT_DONE:
148    case JobEventDetails::USER_INIT_CANCELED:
149    case JobEventDetails::DEFAULT_INIT_DONE:
150    case JobEventDetails::NEW_PAGE:
151    case JobEventDetails::PAGE_DONE:
152    case JobEventDetails::DOC_DONE:
153    case JobEventDetails::ALL_PAGES_REQUESTED: {
154      // Don't care.
155      break;
156    }
157    default: {
158      NOTREACHED();
159      break;
160    }
161  }
162}
163
164bool PrintJobManager::printing_enabled() {
165  base::AutoLock lock(enabled_lock_);
166  return printing_enabled_;
167}
168
169void PrintJobManager::set_printing_enabled(bool printing_enabled) {
170  base::AutoLock lock(enabled_lock_);
171  printing_enabled_ = printing_enabled;
172}
173
174}  // namespace printing
175