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/printer_query.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/message_loop/message_loop.h"
10#include "base/threading/thread_restrictions.h"
11#include "base/values.h"
12#include "chrome/browser/printing/print_job_worker.h"
13
14namespace printing {
15
16PrinterQuery::PrinterQuery(int render_process_id, int render_view_id)
17    : worker_(new PrintJobWorker(render_process_id, render_view_id, this)),
18      is_print_dialog_box_shown_(false),
19      cookie_(PrintSettings::NewCookie()),
20      last_status_(PrintingContext::FAILED) {
21  DCHECK(base::MessageLoopForIO::IsCurrent());
22}
23
24PrinterQuery::~PrinterQuery() {
25  // The job should be finished (or at least canceled) when it is destroyed.
26  DCHECK(!is_print_dialog_box_shown_);
27  // If this fires, it is that this pending printer context has leaked.
28  DCHECK(!worker_.get());
29}
30
31void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
32                                   PrintingContext::Result result) {
33  is_print_dialog_box_shown_ = false;
34  last_status_ = result;
35  if (result != PrintingContext::FAILED) {
36    settings_ = new_settings;
37    cookie_ = PrintSettings::NewCookie();
38  } else {
39    // Failure.
40    cookie_ = 0;
41  }
42
43  if (!callback_.is_null()) {
44    // This may cause reentrancy like to call StopWorker().
45    callback_.Run();
46    callback_.Reset();
47  }
48}
49
50PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
51  DCHECK(callback_.is_null());
52  DCHECK(worker_.get());
53
54  worker_->SetNewOwner(new_owner);
55  return worker_.release();
56}
57
58const PrintSettings& PrinterQuery::settings() const {
59  return settings_;
60}
61
62int PrinterQuery::cookie() const {
63  return cookie_;
64}
65
66void PrinterQuery::GetSettings(
67    GetSettingsAskParam ask_user_for_settings,
68    int expected_page_count,
69    bool has_selection,
70    MarginType margin_type,
71    const base::Closure& callback) {
72  DCHECK(RunsTasksOnCurrentThread());
73  DCHECK(!is_print_dialog_box_shown_);
74
75  StartWorker(callback);
76
77  // Real work is done in PrintJobWorker::GetSettings().
78  is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
79  worker_->PostTask(FROM_HERE,
80                    base::Bind(&PrintJobWorker::GetSettings,
81                               base::Unretained(worker_.get()),
82                               is_print_dialog_box_shown_,
83                               expected_page_count,
84                               has_selection,
85                               margin_type));
86}
87
88void PrinterQuery::SetSettings(scoped_ptr<base::DictionaryValue> new_settings,
89                               const base::Closure& callback) {
90  StartWorker(callback);
91
92  worker_->PostTask(FROM_HERE,
93                    base::Bind(&PrintJobWorker::SetSettings,
94                               base::Unretained(worker_.get()),
95                               base::Passed(&new_settings)));
96}
97
98void PrinterQuery::StartWorker(const base::Closure& callback) {
99  DCHECK(callback_.is_null());
100  DCHECK(worker_.get());
101
102  // Lazily create the worker thread. There is one worker thread per print job.
103  if (!worker_->IsRunning())
104    worker_->Start();
105
106  callback_ = callback;
107}
108
109void PrinterQuery::StopWorker() {
110  if (worker_.get()) {
111    // http://crbug.com/66082: We're blocking on the PrinterQuery's worker
112    // thread.  It's not clear to me if this may result in blocking the current
113    // thread for an unacceptable time.  We should probably fix it.
114    base::ThreadRestrictions::ScopedAllowIO allow_io;
115    worker_->Stop();
116    worker_.reset();
117  }
118}
119
120bool PrinterQuery::is_callback_pending() const {
121  return !callback_.is_null();
122}
123
124bool PrinterQuery::is_valid() const {
125  return worker_.get() != NULL;
126}
127
128}  // namespace printing
129