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