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.
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/i18n/file_util_icu.h"
16 #include "base/i18n/number_formatting.h"
17 #include "base/json/json_reader.h"
18 #include "base/lazy_instance.h"
19 #include "base/memory/linked_ptr.h"
20 #include "base/memory/ref_counted_memory.h"
21 #include "base/metrics/histogram.h"
22 #include "base/path_service.h"
23 #include "base/prefs/pref_service.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/values.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/platform_util.h"
30 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
31 #include "chrome/browser/printing/print_dialog_cloud.h"
32 #include "chrome/browser/printing/print_error_dialog.h"
33 #include "chrome/browser/printing/print_job_manager.h"
34 #include "chrome/browser/printing/print_preview_dialog_controller.h"
35 #include "chrome/browser/printing/print_view_manager.h"
36 #include "chrome/browser/printing/printer_manager_dialog.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/signin/profile_oauth2_token_service.h"
39 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
40 #include "chrome/browser/signin/signin_manager.h"
41 #include "chrome/browser/signin/signin_manager_base.h"
42 #include "chrome/browser/signin/signin_manager_factory.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_tabstrip.h"
45 #include "chrome/browser/ui/chrome_select_file_policy.h"
46 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
47 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
48 #include "chrome/common/chrome_paths.h"
49 #include "chrome/common/chrome_switches.h"
50 #include "chrome/common/cloud_print/cloud_print_constants.h"
51 #include "chrome/common/crash_keys.h"
52 #include "chrome/common/pref_names.h"
53 #include "chrome/common/print_messages.h"
54 #include "content/public/browser/browser_context.h"
55 #include "content/public/browser/browser_thread.h"
56 #include "content/public/browser/navigation_controller.h"
57 #include "content/public/browser/navigation_entry.h"
58 #include "content/public/browser/render_view_host.h"
59 #include "content/public/browser/web_contents.h"
60 #include "content/public/browser/web_contents_view.h"
61 #include "content/public/browser/web_ui.h"
62 #include "google_apis/gaia/oauth2_token_service.h"
63 #include "printing/backend/print_backend.h"
64 #include "printing/metafile.h"
65 #include "printing/metafile_impl.h"
66 #include "printing/pdf_render_settings.h"
67 #include "printing/print_settings.h"
68 #include "printing/units.h"
69 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
71 #if defined(OS_CHROMEOS)
72 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
73 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
76 #if defined(ENABLE_MDNS)
77 #include "chrome/browser/local_discovery/privet_constants.h"
80 using content::BrowserThread
;
81 using content::RenderViewHost
;
82 using content::WebContents
;
86 enum UserActionBuckets
{
90 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
,
93 INITIATOR_CRASHED
, // UNUSED
95 PRINT_WITH_CLOUD_PRINT
,
97 USERACTION_BUCKET_BOUNDARY
100 enum PrintSettingsBuckets
{
112 PRINT_SETTINGS_BUCKET_BOUNDARY
115 enum UiBucketGroups
{
118 UI_BUCKET_GROUP_BOUNDARY
121 enum PrintDestinationBuckets
{
123 DESTINATION_CLOSED_CHANGED
,
124 DESTINATION_CLOSED_UNCHANGED
,
127 PRINT_DESTINATION_BUCKET_BOUNDARY
130 enum GcpPromoBuckets
{
134 GCP_PROMO_BUCKET_BOUNDARY
137 void ReportUserActionHistogram(enum UserActionBuckets event
) {
138 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event
,
139 USERACTION_BUCKET_BOUNDARY
);
142 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting
) {
143 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting
,
144 PRINT_SETTINGS_BUCKET_BOUNDARY
);
147 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event
) {
148 UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event
,
149 PRINT_DESTINATION_BUCKET_BOUNDARY
);
152 void ReportGcpPromoHistogram(enum GcpPromoBuckets event
) {
153 UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event
,
154 GCP_PROMO_BUCKET_BOUNDARY
);
157 // Name of a dictionary field holding cloud print related data;
158 const char kAppState
[] = "appState";
159 // Name of a dictionary field holding the initiator title.
160 const char kInitiatorTitle
[] = "initiatorTitle";
161 // Name of a dictionary field holding the measurement system according to the
163 const char kMeasurementSystem
[] = "measurementSystem";
164 // Name of a dictionary field holding the number format according to the locale.
165 const char kNumberFormat
[] = "numberFormat";
166 // Name of a dictionary field specifying whether to print automatically in
167 // kiosk mode. See http://crbug.com/31395.
168 const char kPrintAutomaticallyInKioskMode
[] = "printAutomaticallyInKioskMode";
170 const char kHidePrintWithSystemDialogLink
[] = "hidePrintWithSystemDialogLink";
172 // Name of a dictionary field holding the state of selection for document.
173 const char kDocumentHasSelection
[] = "documentHasSelection";
175 // Additional printer capability setting keys.
176 const char kPrinterId
[] = "printerId";
177 const char kDisableColorOption
[] = "disableColorOption";
178 const char kSetDuplexAsDefault
[] = "setDuplexAsDefault";
179 const char kPrinterDefaultDuplexValue
[] = "printerDefaultDuplexValue";
180 #if defined(USE_CUPS)
181 const char kCUPSsColorModel
[] = "cupsColorModel";
182 const char kCUPSsBWModel
[] = "cupsBWModel";
185 #if defined(ENABLE_MDNS)
186 const int kPrivetPrinterSearchDurationSeconds
= 3;
189 // Get the print job settings dictionary from |args|. The caller takes
190 // ownership of the returned DictionaryValue. Returns NULL on failure.
191 DictionaryValue
* GetSettingsDictionary(const ListValue
* args
) {
192 std::string json_str
;
193 if (!args
->GetString(0, &json_str
)) {
194 NOTREACHED() << "Could not read JSON argument";
197 if (json_str
.empty()) {
198 NOTREACHED() << "Empty print job settings";
201 scoped_ptr
<DictionaryValue
> settings(static_cast<DictionaryValue
*>(
202 base::JSONReader::Read(json_str
)));
203 if (!settings
.get() || !settings
->IsType(Value::TYPE_DICTIONARY
)) {
204 NOTREACHED() << "Print job settings must be a dictionary.";
208 if (settings
->empty()) {
209 NOTREACHED() << "Print job settings dictionary is empty";
213 return settings
.release();
216 // Track the popularity of print settings and report the stats.
217 void ReportPrintSettingsStats(const DictionaryValue
& settings
) {
218 ReportPrintSettingHistogram(TOTAL
);
220 bool landscape
= false;
221 if (settings
.GetBoolean(printing::kSettingLandscape
, &landscape
))
222 ReportPrintSettingHistogram(landscape
? LANDSCAPE
: PORTRAIT
);
224 bool collate
= false;
225 if (settings
.GetBoolean(printing::kSettingCollate
, &collate
) && collate
)
226 ReportPrintSettingHistogram(COLLATE
);
229 if (settings
.GetInteger(printing::kSettingDuplexMode
, &duplex_mode
))
230 ReportPrintSettingHistogram(duplex_mode
? DUPLEX
: SIMPLEX
);
233 if (settings
.GetInteger(printing::kSettingColor
, &color_mode
)) {
234 ReportPrintSettingHistogram(
235 printing::IsColorModelSelected(color_mode
) ? COLOR
: BLACK_AND_WHITE
);
238 bool headers
= false;
239 if (settings
.GetBoolean(printing::kSettingHeaderFooterEnabled
, &headers
) &&
241 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS
);
244 bool css_background
= false;
245 if (settings
.GetBoolean(printing::kSettingShouldPrintBackgrounds
,
246 &css_background
) && css_background
) {
247 ReportPrintSettingHistogram(CSS_BACKGROUND
);
250 bool selection_only
= false;
251 if (settings
.GetBoolean(printing::kSettingShouldPrintSelectionOnly
,
252 &selection_only
) && selection_only
) {
253 ReportPrintSettingHistogram(SELECTION_ONLY
);
257 // Callback that stores a PDF file on disk.
258 void PrintToPdfCallback(printing::Metafile
* metafile
,
259 const base::FilePath
& path
) {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
261 metafile
->SaveTo(path
);
262 // |metafile| must be deleted on the UI thread.
263 BrowserThread::DeleteSoon(BrowserThread::UI
, FROM_HERE
, metafile
);
266 std::string
GetDefaultPrinterOnFileThread(
267 scoped_refptr
<printing::PrintBackend
> print_backend
) {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
270 std::string default_printer
= print_backend
->GetDefaultPrinterName();
271 VLOG(1) << "Default Printer: " << default_printer
;
272 return default_printer
;
275 void EnumeratePrintersOnFileThread(
276 scoped_refptr
<printing::PrintBackend
> print_backend
,
277 base::ListValue
* printers
) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
280 VLOG(1) << "Enumerate printers start";
281 printing::PrinterList printer_list
;
282 print_backend
->EnumeratePrinters(&printer_list
);
284 for (printing::PrinterList::iterator it
= printer_list
.begin();
285 it
!= printer_list
.end(); ++it
) {
286 base::DictionaryValue
* printer_info
= new base::DictionaryValue
;
287 std::string printer_name
;
288 #if defined(OS_MACOSX)
289 // On Mac, |it->printer_description| specifies the printer name and
290 // |it->printer_name| specifies the device name / printer queue name.
291 printer_name
= it
->printer_description
;
293 printer_name
= it
->printer_name
;
295 printer_info
->SetString(printing::kSettingPrinterName
, printer_name
);
296 printer_info
->SetString(printing::kSettingDeviceName
, it
->printer_name
);
297 VLOG(1) << "Found printer " << printer_name
298 << " with device name " << it
->printer_name
;
299 printers
->Append(printer_info
);
301 VLOG(1) << "Enumerate printers finished, found " << printers
->GetSize()
305 typedef base::Callback
<void(const base::DictionaryValue
*)>
306 GetPrinterCapabilitiesSuccessCallback
;
307 typedef base::Callback
<void(const std::string
&)>
308 GetPrinterCapabilitiesFailureCallback
;
310 void GetPrinterCapabilitiesOnFileThread(
311 scoped_refptr
<printing::PrintBackend
> print_backend
,
312 const std::string
& printer_name
,
313 const GetPrinterCapabilitiesSuccessCallback
& success_cb
,
314 const GetPrinterCapabilitiesFailureCallback
& failure_cb
) {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
316 DCHECK(!printer_name
.empty());
318 VLOG(1) << "Get printer capabilities start for " << printer_name
;
319 crash_keys::ScopedPrinterInfo
crash_key(
320 print_backend
->GetPrinterDriverInfo(printer_name
));
322 if (!print_backend
->IsValidPrinter(printer_name
)) {
323 // TODO(gene): Notify explicitly if printer is not valid, instead of
324 // failed to get capabilities.
325 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
326 base::Bind(failure_cb
, printer_name
));
330 printing::PrinterSemanticCapsAndDefaults info
;
331 if (!print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
, &info
)) {
332 LOG(WARNING
) << "Failed to get capabilities for " << printer_name
;
333 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
334 base::Bind(failure_cb
, printer_name
));
338 scoped_ptr
<base::DictionaryValue
> settings_info(new base::DictionaryValue
);
339 settings_info
->SetString(kPrinterId
, printer_name
);
340 settings_info
->SetBoolean(kDisableColorOption
, !info
.color_changeable
);
341 settings_info
->SetBoolean(printing::kSettingSetColorAsDefault
,
343 #if defined(USE_CUPS)
344 settings_info
->SetInteger(kCUPSsColorModel
, info
.color_model
);
345 settings_info
->SetInteger(kCUPSsBWModel
, info
.bw_model
);
348 // TODO(gene): Make new capabilities format for Print Preview
349 // that will suit semantic capabiltities better.
350 // Refactor pld API code below
351 bool default_duplex
= info
.duplex_capable
?
352 (info
.duplex_default
!= printing::SIMPLEX
) : false;
353 int duplex_value
= info
.duplex_capable
?
354 printing::LONG_EDGE
: printing::UNKNOWN_DUPLEX_MODE
;
355 settings_info
->SetBoolean(kSetDuplexAsDefault
, default_duplex
);
356 settings_info
->SetInteger(kPrinterDefaultDuplexValue
, duplex_value
);
358 BrowserThread::PostTask(
359 BrowserThread::UI
, FROM_HERE
,
360 base::Bind(success_cb
, base::Owned(settings_info
.release())));
363 base::LazyInstance
<printing::StickySettings
> g_sticky_settings
=
364 LAZY_INSTANCE_INITIALIZER
;
366 printing::StickySettings
* GetStickySettings() {
367 return g_sticky_settings
.Pointer();
372 #if defined(USE_CUPS)
373 struct PrintPreviewHandler::CUPSPrinterColorModels
{
374 std::string printer_name
;
375 printing::ColorModel color_model
;
376 printing::ColorModel bw_model
;
380 class PrintPreviewHandler::AccessTokenService
381 : public OAuth2TokenService::Consumer
{
383 explicit AccessTokenService(PrintPreviewHandler
* handler
)
385 weak_factory_(this) {
388 void RequestToken(const std::string
& type
) {
389 if (requests_
.find(type
) != requests_
.end())
390 return; // Already in progress.
392 OAuth2TokenService
* service
= NULL
;
393 std::string account_id
;
394 if (type
== "profile") {
395 Profile
* profile
= Profile::FromWebUI(handler_
->web_ui());
397 ProfileOAuth2TokenService
* token_service
=
398 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
399 account_id
= token_service
->GetPrimaryAccountId();
400 service
= token_service
;
402 } else if (type
== "device") {
403 #if defined(OS_CHROMEOS)
404 chromeos::DeviceOAuth2TokenServiceFactory::Get(
406 &AccessTokenService::DidGetTokenService
,
407 weak_factory_
.GetWeakPtr(),
413 ContinueRequestToken(type
, service
, account_id
);
416 #if defined(OS_CHROMEOS)
417 // Continuation of RequestToken().
418 void DidGetTokenService(const std::string
& type
,
419 chromeos::DeviceOAuth2TokenService
* token_service
) {
420 std::string account_id
;
422 account_id
= token_service
->GetRobotAccountId();
423 ContinueRequestToken(type
,
429 // Continuation of RequestToken().
430 void ContinueRequestToken(const std::string
& type
,
431 OAuth2TokenService
* service
,
432 const std::string
& account_id
) {
434 OAuth2TokenService::ScopeSet oauth_scopes
;
435 oauth_scopes
.insert(cloud_print::kCloudPrintAuth
);
436 scoped_ptr
<OAuth2TokenService::Request
> request(
437 service
->StartRequest(account_id
, oauth_scopes
, this));
438 requests_
[type
].reset(request
.release());
440 handler_
->SendAccessToken(type
, std::string()); // Unknown type.
444 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
445 const std::string
& access_token
,
446 const base::Time
& expiration_time
) OVERRIDE
{
447 OnServiceResponce(request
, access_token
);
450 virtual void OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
451 const GoogleServiceAuthError
& error
) OVERRIDE
{
452 OnServiceResponce(request
, std::string());
456 void OnServiceResponce(const OAuth2TokenService::Request
* request
,
457 const std::string
& access_token
) {
458 for (Requests::iterator i
= requests_
.begin(); i
!= requests_
.end(); ++i
) {
459 if (i
->second
== request
) {
460 handler_
->SendAccessToken(i
->first
, access_token
);
468 typedef std::map
<std::string
,
469 linked_ptr
<OAuth2TokenService::Request
> > Requests
;
471 PrintPreviewHandler
* handler_
;
472 base::WeakPtrFactory
<AccessTokenService
> weak_factory_
;
474 DISALLOW_COPY_AND_ASSIGN(AccessTokenService
);
477 PrintPreviewHandler::PrintPreviewHandler()
478 : print_backend_(printing::PrintBackend::CreateInstance(NULL
)),
479 regenerate_preview_request_count_(0),
480 manage_printers_dialog_request_count_(0),
481 manage_cloud_printers_dialog_request_count_(0),
482 reported_failed_preview_(false),
483 has_logged_printers_count_(false),
484 weak_factory_(this) {
485 ReportUserActionHistogram(PREVIEW_STARTED
);
488 PrintPreviewHandler::~PrintPreviewHandler() {
489 if (select_file_dialog_
.get())
490 select_file_dialog_
->ListenerDestroyed();
493 void PrintPreviewHandler::RegisterMessages() {
494 web_ui()->RegisterMessageCallback("getPrinters",
495 base::Bind(&PrintPreviewHandler::HandleGetPrinters
,
496 base::Unretained(this)));
497 web_ui()->RegisterMessageCallback("getPreview",
498 base::Bind(&PrintPreviewHandler::HandleGetPreview
,
499 base::Unretained(this)));
500 web_ui()->RegisterMessageCallback("print",
501 base::Bind(&PrintPreviewHandler::HandlePrint
,
502 base::Unretained(this)));
503 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
504 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities
,
505 base::Unretained(this)));
506 web_ui()->RegisterMessageCallback("showSystemDialog",
507 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog
,
508 base::Unretained(this)));
509 web_ui()->RegisterMessageCallback("signIn",
510 base::Bind(&PrintPreviewHandler::HandleSignin
,
511 base::Unretained(this)));
512 web_ui()->RegisterMessageCallback("getAccessToken",
513 base::Bind(&PrintPreviewHandler::HandleGetAccessToken
,
514 base::Unretained(this)));
515 web_ui()->RegisterMessageCallback("manageCloudPrinters",
516 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint
,
517 base::Unretained(this)));
518 web_ui()->RegisterMessageCallback("manageLocalPrinters",
519 base::Bind(&PrintPreviewHandler::HandleManagePrinters
,
520 base::Unretained(this)));
521 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
522 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog
,
523 base::Unretained(this)));
524 web_ui()->RegisterMessageCallback("hidePreview",
525 base::Bind(&PrintPreviewHandler::HandleHidePreview
,
526 base::Unretained(this)));
527 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
528 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest
,
529 base::Unretained(this)));
530 web_ui()->RegisterMessageCallback("saveAppState",
531 base::Bind(&PrintPreviewHandler::HandleSaveAppState
,
532 base::Unretained(this)));
533 web_ui()->RegisterMessageCallback("getInitialSettings",
534 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings
,
535 base::Unretained(this)));
536 web_ui()->RegisterMessageCallback("reportUiEvent",
537 base::Bind(&PrintPreviewHandler::HandleReportUiEvent
,
538 base::Unretained(this)));
539 web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
540 base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog
,
541 base::Unretained(this)));
542 web_ui()->RegisterMessageCallback("forceOpenNewTab",
543 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab
,
544 base::Unretained(this)));
545 web_ui()->RegisterMessageCallback("getPrivetPrinters",
546 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters
,
547 base::Unretained(this)));
548 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
549 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities
,
550 base::Unretained(this)));
553 bool PrintPreviewHandler::PrivetPrintingEnabled() {
554 #if defined(ENABLE_MDNS)
555 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
556 return !command_line
->HasSwitch(switches::kDisableDeviceDiscovery
) &&
557 !command_line
->HasSwitch(switches::kDisablePrivetLocalPrinting
);
563 WebContents
* PrintPreviewHandler::preview_web_contents() const {
564 return web_ui()->GetWebContents();
567 void PrintPreviewHandler::HandleGetPrinters(const ListValue
* /*args*/) {
568 base::ListValue
* results
= new base::ListValue
;
569 BrowserThread::PostTaskAndReply(
570 BrowserThread::FILE, FROM_HERE
,
571 base::Bind(&EnumeratePrintersOnFileThread
, print_backend_
,
572 base::Unretained(results
)),
573 base::Bind(&PrintPreviewHandler::SetupPrinterList
,
574 weak_factory_
.GetWeakPtr(),
575 base::Owned(results
)));
578 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue
* args
) {
579 #if defined(ENABLE_MDNS)
580 if (PrivetPrintingEnabled()) {
581 Profile
* profile
= Profile::FromWebUI(web_ui());
582 service_discovery_client_
=
583 local_discovery::ServiceDiscoverySharedClient::GetInstance();
584 printer_lister_
.reset(new local_discovery::PrivetLocalPrinterLister(
585 service_discovery_client_
.get(),
586 profile
->GetRequestContext(),
588 printer_lister_
->Start();
590 base::MessageLoop::current()->PostDelayedTask(
592 base::Bind(&PrintPreviewHandler::StopPrivetPrinterSearch
,
593 weak_factory_
.GetWeakPtr()),
594 base::TimeDelta::FromSeconds(kPrivetPrinterSearchDurationSeconds
));
598 if (!PrivetPrintingEnabled()) {
599 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
603 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
604 const base::ListValue
* args
) {
605 #if defined(ENABLE_MDNS)
607 bool success
= args
->GetString(0, &name
);
612 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient
,
613 base::Unretained(this)));
617 void PrintPreviewHandler::HandleGetPreview(const ListValue
* args
) {
618 DCHECK_EQ(3U, args
->GetSize());
619 scoped_ptr
<DictionaryValue
> settings(GetSettingsDictionary(args
));
623 if (!settings
->GetInteger(printing::kPreviewRequestID
, &request_id
))
626 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
627 web_ui()->GetController());
628 print_preview_ui
->OnPrintPreviewRequest(request_id
);
629 // Add an additional key in order to identify |print_preview_ui| later on
630 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
632 settings
->SetInteger(printing::kPreviewUIID
,
633 print_preview_ui
->GetIDForPrintPreviewUI());
635 // Increment request count.
636 ++regenerate_preview_request_count_
;
638 WebContents
* initiator
= GetInitiator();
640 ReportUserActionHistogram(INITIATOR_CLOSED
);
641 print_preview_ui
->OnClosePrintPreviewDialog();
645 // Retrieve the page title and url and send it to the renderer process if
646 // headers and footers are to be displayed.
647 bool display_header_footer
= false;
648 if (!settings
->GetBoolean(printing::kSettingHeaderFooterEnabled
,
649 &display_header_footer
)) {
652 if (display_header_footer
) {
653 settings
->SetString(printing::kSettingHeaderFooterTitle
,
654 initiator
->GetTitle());
656 content::NavigationEntry
* entry
=
657 initiator
->GetController().GetLastCommittedEntry();
659 url
= entry
->GetVirtualURL().spec();
660 settings
->SetString(printing::kSettingHeaderFooterURL
, url
);
663 bool generate_draft_data
= false;
664 bool success
= settings
->GetBoolean(printing::kSettingGenerateDraftData
,
665 &generate_draft_data
);
668 if (!generate_draft_data
) {
669 double draft_page_count_double
= -1;
670 success
= args
->GetDouble(1, &draft_page_count_double
);
672 int draft_page_count
= static_cast<int>(draft_page_count_double
);
674 bool preview_modifiable
= false;
675 success
= args
->GetBoolean(2, &preview_modifiable
);
678 if (draft_page_count
!= -1 && preview_modifiable
&&
679 print_preview_ui
->GetAvailableDraftPageCount() != draft_page_count
) {
680 settings
->SetBoolean(printing::kSettingGenerateDraftData
, true);
684 VLOG(1) << "Print preview request start";
685 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
686 rvh
->Send(new PrintMsg_PrintPreview(rvh
->GetRoutingID(), *settings
));
689 void PrintPreviewHandler::HandlePrint(const ListValue
* args
) {
692 // Record the number of times the user requests to regenerate preview data
694 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
695 regenerate_preview_request_count_
);
697 WebContents
* initiator
= GetInitiator();
699 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
700 rvh
->Send(new PrintMsg_ResetScriptedPrintCount(rvh
->GetRoutingID()));
703 scoped_ptr
<DictionaryValue
> settings(GetSettingsDictionary(args
));
707 // Never try to add headers/footers here. It's already in the generated PDF.
708 settings
->SetBoolean(printing::kSettingHeaderFooterEnabled
, false);
710 bool print_to_pdf
= false;
711 bool is_cloud_printer
= false;
712 bool print_with_privet
= false;
714 bool open_pdf_in_preview
= false;
715 #if defined(OS_MACOSX)
716 open_pdf_in_preview
= settings
->HasKey(printing::kSettingOpenPDFInPreview
);
719 if (!open_pdf_in_preview
) {
720 settings
->GetBoolean(printing::kSettingPrintToPDF
, &print_to_pdf
);
721 settings
->GetBoolean(printing::kSettingPrintWithPrivet
, &print_with_privet
);
722 is_cloud_printer
= settings
->HasKey(printing::kSettingCloudPrintId
);
726 settings
->GetInteger(printing::kSettingPreviewPageCount
, &page_count
);
729 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count
);
730 ReportUserActionHistogram(PRINT_TO_PDF
);
735 #if defined(ENABLE_MDNS)
736 if (print_with_privet
&& PrivetPrintingEnabled()) {
737 std::string printer_name
;
738 std::string print_ticket
;
739 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count
);
740 ReportUserActionHistogram(PRINT_WITH_PRIVET
);
744 if (!settings
->GetString(printing::kSettingDeviceName
, &printer_name
) ||
745 !settings
->GetString(printing::kSettingTicket
, &print_ticket
) ||
746 !settings
->GetInteger(printing::kSettingPageWidth
, &width
) ||
747 !settings
->GetInteger(printing::kSettingPageHeight
, &height
) ||
748 width
<= 0 || height
<=0) {
750 base::FundamentalValue
http_code_value(-1);
751 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
755 PrintToPrivetPrinter(printer_name
, print_ticket
, gfx::Size(width
, height
));
760 scoped_refptr
<base::RefCountedBytes
> data
;
762 if (!GetPreviewDataAndTitle(&data
, &title
)) {
763 // Nothing to print, no preview available.
767 if (is_cloud_printer
) {
768 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
770 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT
);
771 SendCloudPrintJob(data
.get());
773 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count
);
774 ReportUserActionHistogram(PRINT_TO_PRINTER
);
775 ReportPrintSettingsStats(*settings
);
777 // This tries to activate the initiator as well, so do not clear the
778 // association with the initiator yet.
779 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
780 web_ui()->GetController());
781 print_preview_ui
->OnHidePreviewDialog();
783 // Do this so the initiator can open a new print preview dialog, while the
784 // current print preview dialog is still handling its print job.
785 ClearInitiatorDetails();
787 // The PDF being printed contains only the pages that the user selected,
788 // so ignore the page range and print all pages.
789 settings
->Remove(printing::kSettingPageRange
, NULL
);
790 // Reset selection only flag for the same reason.
791 settings
->SetBoolean(printing::kSettingShouldPrintSelectionOnly
, false);
793 #if defined(USE_CUPS)
794 if (!open_pdf_in_preview
) // We can get here even for cloud printers.
795 ConvertColorSettingToCUPSColorModel(settings
.get());
798 // Set ID to know whether printing is for preview.
799 settings
->SetInteger(printing::kPreviewUIID
,
800 print_preview_ui
->GetIDForPrintPreviewUI());
801 RenderViewHost
* rvh
= preview_web_contents()->GetRenderViewHost();
802 rvh
->Send(new PrintMsg_PrintForPrintPreview(rvh
->GetRoutingID(),
805 // For all other cases above, the preview dialog will stay open until the
806 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
807 // called. In the case below, since the preview dialog will be hidden and
808 // not closed, we need to make this call.
810 printing::PrintViewManager
* print_view_manager
=
811 printing::PrintViewManager::FromWebContents(initiator
);
812 print_view_manager
->PrintPreviewDone();
817 void PrintPreviewHandler::PrintToPdf() {
818 if (!print_to_pdf_path_
.empty()) {
819 // User has already selected a path, no need to show the dialog again.
820 PostPrintToPdfTask();
821 } else if (!select_file_dialog_
.get() ||
822 !select_file_dialog_
->IsRunning(platform_util::GetTopLevel(
823 preview_web_contents()->GetView()->GetNativeView()))) {
824 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
825 web_ui()->GetController());
826 // Pre-populating select file dialog with print job title.
827 string16 print_job_title_utf16
= print_preview_ui
->initiator_title();
830 base::FilePath::StringType
print_job_title(print_job_title_utf16
);
831 #elif defined(OS_POSIX)
832 base::FilePath::StringType print_job_title
=
833 UTF16ToUTF8(print_job_title_utf16
);
836 file_util::ReplaceIllegalCharactersInPath(&print_job_title
, '_');
837 base::FilePath
default_filename(print_job_title
);
839 default_filename
.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
841 SelectFile(default_filename
);
845 void PrintPreviewHandler::HandleHidePreview(const ListValue
* /*args*/) {
846 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
847 web_ui()->GetController());
848 print_preview_ui
->OnHidePreviewDialog();
851 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
852 const ListValue
* /*args*/) {
853 WebContents
* initiator
= GetInitiator();
855 ClearInitiatorDetails();
856 gfx::NativeWindow parent
= initiator
?
857 initiator
->GetView()->GetTopLevelNativeWindow() :
859 chrome::ShowPrintErrorDialog(parent
);
862 void PrintPreviewHandler::HandleSaveAppState(const ListValue
* args
) {
863 std::string data_to_save
;
864 printing::StickySettings
* sticky_settings
= GetStickySettings();
865 if (args
->GetString(0, &data_to_save
) && !data_to_save
.empty())
866 sticky_settings
->StoreAppState(data_to_save
);
867 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
868 preview_web_contents()->GetBrowserContext())->GetPrefs());
871 void PrintPreviewHandler::HandleGetPrinterCapabilities(const ListValue
* args
) {
872 std::string printer_name
;
873 bool ret
= args
->GetString(0, &printer_name
);
874 if (!ret
|| printer_name
.empty())
877 GetPrinterCapabilitiesSuccessCallback success_cb
=
878 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities
,
879 weak_factory_
.GetWeakPtr());
880 GetPrinterCapabilitiesFailureCallback failure_cb
=
881 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities
,
882 weak_factory_
.GetWeakPtr());
883 BrowserThread::PostTask(
884 BrowserThread::FILE, FROM_HERE
,
885 base::Bind(&GetPrinterCapabilitiesOnFileThread
,
886 print_backend_
, printer_name
, success_cb
, failure_cb
));
889 void PrintPreviewHandler::OnSigninComplete() {
890 PrintPreviewUI
* print_preview_ui
=
891 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
892 if (print_preview_ui
)
893 print_preview_ui
->OnReloadPrintersList();
896 void PrintPreviewHandler::HandleSignin(const ListValue
* /*args*/) {
897 gfx::NativeWindow modal_parent
= platform_util::GetTopLevel(
898 preview_web_contents()->GetView()->GetNativeView());
899 print_dialog_cloud::CreateCloudPrintSigninDialog(
900 preview_web_contents()->GetBrowserContext(),
902 base::Bind(&PrintPreviewHandler::OnSigninComplete
,
903 weak_factory_
.GetWeakPtr()));
906 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue
* args
) {
908 if (!args
->GetString(0, &type
))
911 token_service_
.reset(new AccessTokenService(this));
912 token_service_
->RequestToken(type
);
915 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
916 // Record the number of times the user asks to print via cloud print
917 // instead of the print preview dialog.
920 scoped_refptr
<base::RefCountedBytes
> data
;
922 if (!GetPreviewDataAndTitle(&data
, &title
)) {
923 // Nothing to print, no preview available.
927 gfx::NativeWindow modal_parent
= platform_util::GetTopLevel(
928 preview_web_contents()->GetView()->GetNativeView());
929 print_dialog_cloud::CreatePrintDialogForBytes(
930 preview_web_contents()->GetBrowserContext(),
935 std::string("application/pdf"));
937 // Once the cloud print dialog comes up we're no longer in a background
938 // printing situation. Close the print preview.
939 // TODO(abodenha@chromium.org) The flow should be changed as described in
940 // http://code.google.com/p/chromium/issues/detail?id=44093
941 ClosePreviewDialog();
944 void PrintPreviewHandler::HandleManageCloudPrint(const ListValue
* /*args*/) {
945 ++manage_cloud_printers_dialog_request_count_
;
946 Profile
* profile
= Profile::FromBrowserContext(
947 preview_web_contents()->GetBrowserContext());
948 preview_web_contents()->OpenURL(
949 content::OpenURLParams(
950 CloudPrintURL(profile
).GetCloudPrintServiceManageURL(),
953 content::PAGE_TRANSITION_LINK
,
957 void PrintPreviewHandler::HandleShowSystemDialog(const ListValue
* /*args*/) {
959 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
961 WebContents
* initiator
= GetInitiator();
965 printing::PrintViewManager
* print_view_manager
=
966 printing::PrintViewManager::FromWebContents(initiator
);
967 print_view_manager
->set_observer(this);
968 print_view_manager
->PrintForSystemDialogNow();
970 // Cancel the pending preview request if exists.
971 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
972 web_ui()->GetController());
973 print_preview_ui
->OnCancelPendingPreviewRequest();
976 void PrintPreviewHandler::HandleManagePrinters(const ListValue
* /*args*/) {
977 ++manage_printers_dialog_request_count_
;
978 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
981 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
982 const base::ListValue
* args
) {
984 if (!args
|| !args
->GetInteger(0, &page_count
))
986 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
989 PrintWithCloudPrintDialog();
992 void PrintPreviewHandler::HandleClosePreviewDialog(const ListValue
* /*args*/) {
994 ReportUserActionHistogram(CANCEL
);
996 // Record the number of times the user requests to regenerate preview data
997 // before cancelling.
998 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
999 regenerate_preview_request_count_
);
1002 void PrintPreviewHandler::ReportStats() {
1003 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1004 manage_printers_dialog_request_count_
);
1005 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1006 manage_cloud_printers_dialog_request_count_
);
1009 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1010 base::DictionaryValue
* settings
) {
1012 // Getting the measurement system based on the locale.
1013 UErrorCode errorCode
= U_ZERO_ERROR
;
1014 const char* locale
= g_browser_process
->GetApplicationLocale().c_str();
1015 UMeasurementSystem system
= ulocdata_getMeasurementSystem(locale
, &errorCode
);
1016 if (errorCode
> U_ZERO_ERROR
|| system
== UMS_LIMIT
)
1019 // Getting the number formatting based on the locale and writing to
1021 settings
->SetString(kNumberFormat
, base::FormatDouble(123456.78, 2));
1022 settings
->SetInteger(kMeasurementSystem
, system
);
1025 void PrintPreviewHandler::HandleGetInitialSettings(const ListValue
* /*args*/) {
1026 // Send before SendInitialSettings to allow cloud printer auto select.
1027 SendCloudPrintEnabled();
1028 BrowserThread::PostTaskAndReplyWithResult(
1029 BrowserThread::FILE, FROM_HERE
,
1030 base::Bind(&GetDefaultPrinterOnFileThread
, print_backend_
),
1031 base::Bind(&PrintPreviewHandler::SendInitialSettings
,
1032 weak_factory_
.GetWeakPtr()));
1035 void PrintPreviewHandler::HandleReportUiEvent(const ListValue
* args
) {
1036 int event_group
, event_number
;
1037 if (!args
->GetInteger(0, &event_group
) || !args
->GetInteger(1, &event_number
))
1040 enum UiBucketGroups ui_bucket_group
=
1041 static_cast<enum UiBucketGroups
>(event_group
);
1042 if (ui_bucket_group
>= UI_BUCKET_GROUP_BOUNDARY
)
1045 switch (ui_bucket_group
) {
1046 case DESTINATION_SEARCH
: {
1047 enum PrintDestinationBuckets event
=
1048 static_cast<enum PrintDestinationBuckets
>(event_number
);
1049 if (event
>= PRINT_DESTINATION_BUCKET_BOUNDARY
)
1051 ReportPrintDestinationHistogram(event
);
1055 enum GcpPromoBuckets event
=
1056 static_cast<enum GcpPromoBuckets
>(event_number
);
1057 if (event
>= GCP_PROMO_BUCKET_BOUNDARY
)
1059 ReportGcpPromoHistogram(event
);
1067 void PrintPreviewHandler::HandleForceOpenNewTab(const ListValue
* args
) {
1069 if (!args
->GetString(0, &url
))
1071 Browser
* browser
= chrome::FindBrowserWithWebContents(GetInitiator());
1074 chrome::AddSelectedTabWithURL(browser
,
1076 content::PAGE_TRANSITION_LINK
);
1079 void PrintPreviewHandler::SendInitialSettings(
1080 const std::string
& default_printer
) {
1081 PrintPreviewUI
* print_preview_ui
=
1082 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1084 base::DictionaryValue initial_settings
;
1085 initial_settings
.SetString(kInitiatorTitle
,
1086 print_preview_ui
->initiator_title());
1087 initial_settings
.SetBoolean(printing::kSettingPreviewModifiable
,
1088 print_preview_ui
->source_is_modifiable());
1089 initial_settings
.SetString(printing::kSettingPrinterName
, default_printer
);
1090 initial_settings
.SetBoolean(kDocumentHasSelection
,
1091 print_preview_ui
->source_has_selection());
1092 initial_settings
.SetBoolean(printing::kSettingShouldPrintSelectionOnly
,
1093 print_preview_ui
->print_selection_only());
1094 printing::StickySettings
* sticky_settings
= GetStickySettings();
1095 sticky_settings
->RestoreFromPrefs(Profile::FromBrowserContext(
1096 preview_web_contents()->GetBrowserContext())->GetPrefs());
1097 if (sticky_settings
->printer_app_state())
1098 initial_settings
.SetString(kAppState
,
1099 *sticky_settings
->printer_app_state());
1101 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
1102 initial_settings
.SetBoolean(kPrintAutomaticallyInKioskMode
,
1103 cmdline
->HasSwitch(switches::kKioskModePrinting
));
1105 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1106 // so will cause the browser to appear hung, so we don't show the link in
1108 bool is_ash
= (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH
);
1109 initial_settings
.SetBoolean(kHidePrintWithSystemDialogLink
, is_ash
);
1112 if (print_preview_ui
->source_is_modifiable())
1113 GetNumberFormatAndMeasurementSystem(&initial_settings
);
1114 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings
);
1117 void PrintPreviewHandler::ClosePreviewDialog() {
1118 PrintPreviewUI
* print_preview_ui
=
1119 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1120 print_preview_ui
->OnClosePrintPreviewDialog();
1123 void PrintPreviewHandler::SendAccessToken(const std::string
& type
,
1124 const std::string
& access_token
) {
1125 VLOG(1) << "Get getAccessToken finished";
1126 web_ui()->CallJavascriptFunction("onDidGetAccessToken", StringValue(type
),
1127 StringValue(access_token
));
1130 void PrintPreviewHandler::SendPrinterCapabilities(
1131 const DictionaryValue
* settings_info
) {
1132 VLOG(1) << "Get printer capabilities finished";
1134 #if defined(USE_CUPS)
1135 SaveCUPSColorSetting(settings_info
);
1138 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1142 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1143 const std::string
& printer_name
) {
1144 VLOG(1) << "Get printer capabilities failed";
1145 base::StringValue
printer_name_value(printer_name
);
1146 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1147 printer_name_value
);
1150 void PrintPreviewHandler::SetupPrinterList(const base::ListValue
* printers
) {
1151 if (!has_logged_printers_count_
) {
1152 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers
->GetSize());
1153 has_logged_printers_count_
= true;
1156 web_ui()->CallJavascriptFunction("setPrinters", *printers
);
1159 void PrintPreviewHandler::SendCloudPrintEnabled() {
1160 Profile
* profile
= Profile::FromBrowserContext(
1161 preview_web_contents()->GetBrowserContext());
1162 PrefService
* prefs
= profile
->GetPrefs();
1163 if (prefs
->GetBoolean(prefs::kCloudPrintSubmitEnabled
)) {
1164 GURL
gcp_url(CloudPrintURL(profile
).GetCloudPrintServiceURL());
1165 base::StringValue
gcp_url_value(gcp_url
.spec());
1166 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value
);
1170 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes
* data
) {
1171 // BASE64 encode the job data.
1172 std::string
raw_data(reinterpret_cast<const char*>(data
->front()),
1174 std::string base64_data
;
1175 if (!base::Base64Encode(raw_data
, &base64_data
)) {
1176 NOTREACHED() << "Base64 encoding PDF data.";
1178 StringValue
data_value(base64_data
);
1180 web_ui()->CallJavascriptFunction("printToCloud", data_value
);
1183 WebContents
* PrintPreviewHandler::GetInitiator() const {
1184 printing::PrintPreviewDialogController
* dialog_controller
=
1185 printing::PrintPreviewDialogController::GetInstance();
1186 if (!dialog_controller
)
1188 return dialog_controller
->GetInitiator(preview_web_contents());
1191 void PrintPreviewHandler::OnPrintDialogShown() {
1192 ClosePreviewDialog();
1195 void PrintPreviewHandler::SelectFile(const base::FilePath
& default_filename
) {
1196 ui::SelectFileDialog::FileTypeInfo file_type_info
;
1197 file_type_info
.extensions
.resize(1);
1198 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pdf"));
1200 // Initializing |save_path_| if it is not already initialized.
1201 printing::StickySettings
* sticky_settings
= GetStickySettings();
1202 if (!sticky_settings
->save_path()) {
1203 // Allowing IO operation temporarily. It is ok to do so here because
1204 // the select file dialog performs IO anyway in order to display the
1205 // folders and also it is modal.
1206 base::ThreadRestrictions::ScopedAllowIO allow_io
;
1207 base::FilePath file_path
;
1208 PathService::Get(chrome::DIR_USER_DOCUMENTS
, &file_path
);
1209 sticky_settings
->StoreSavePath(file_path
);
1210 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1211 preview_web_contents()->GetBrowserContext())->GetPrefs());
1214 select_file_dialog_
= ui::SelectFileDialog::Create(
1215 this, new ChromeSelectFilePolicy(preview_web_contents())),
1216 select_file_dialog_
->SelectFile(
1217 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
1219 sticky_settings
->save_path()->Append(default_filename
),
1222 base::FilePath::StringType(),
1223 platform_util::GetTopLevel(
1224 preview_web_contents()->GetView()->GetNativeView()),
1228 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1229 WebContents
* initiator
= GetInitiator();
1233 printing::PrintViewManager
* print_view_manager
=
1234 printing::PrintViewManager::FromWebContents(initiator
);
1235 print_view_manager
->set_observer(NULL
);
1238 void PrintPreviewHandler::OnPrintPreviewFailed() {
1239 if (reported_failed_preview_
)
1241 reported_failed_preview_
= true;
1242 ReportUserActionHistogram(PREVIEW_FAILED
);
1245 void PrintPreviewHandler::ShowSystemDialog() {
1246 HandleShowSystemDialog(NULL
);
1249 void PrintPreviewHandler::FileSelected(const base::FilePath
& path
,
1250 int index
, void* params
) {
1251 // Updating |save_path_| to the newly selected folder.
1252 printing::StickySettings
* sticky_settings
= GetStickySettings();
1253 sticky_settings
->StoreSavePath(path
.DirName());
1254 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1255 preview_web_contents()->GetBrowserContext())->GetPrefs());
1256 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1257 print_to_pdf_path_
= path
;
1258 PostPrintToPdfTask();
1261 void PrintPreviewHandler::PostPrintToPdfTask() {
1262 scoped_refptr
<base::RefCountedBytes
> data
;
1264 if (!GetPreviewDataAndTitle(&data
, &title
)) {
1265 NOTREACHED() << "Preview data was checked before file dialog.";
1268 scoped_ptr
<printing::PreviewMetafile
> metafile(new printing::PreviewMetafile
);
1269 metafile
->InitFromData(static_cast<const void*>(data
->front()), data
->size());
1270 BrowserThread::PostTask(
1271 BrowserThread::FILE, FROM_HERE
,
1272 base::Bind(&PrintToPdfCallback
, metafile
.release(), print_to_pdf_path_
));
1273 print_to_pdf_path_
= base::FilePath();
1274 ClosePreviewDialog();
1277 void PrintPreviewHandler::FileSelectionCanceled(void* params
) {
1278 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1279 web_ui()->GetController());
1280 print_preview_ui
->OnFileSelectionCancelled();
1283 void PrintPreviewHandler::ClearInitiatorDetails() {
1284 WebContents
* initiator
= GetInitiator();
1288 // We no longer require the initiator details. Remove those details associated
1289 // with the preview dialog to allow the initiator to create another preview
1291 printing::PrintPreviewDialogController
* dialog_controller
=
1292 printing::PrintPreviewDialogController::GetInstance();
1293 if (dialog_controller
)
1294 dialog_controller
->EraseInitiatorInfo(preview_web_contents());
1297 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1298 scoped_refptr
<base::RefCountedBytes
>* data
,
1299 string16
* title
) const {
1300 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1301 web_ui()->GetController());
1302 scoped_refptr
<base::RefCountedBytes
> tmp_data
;
1303 print_preview_ui
->GetPrintPreviewDataForIndex(
1304 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX
, &tmp_data
);
1306 if (!tmp_data
.get()) {
1307 // Nothing to print, no preview available.
1310 DCHECK(tmp_data
->size() && tmp_data
->front());
1313 *title
= print_preview_ui
->initiator_title();
1317 #if defined(USE_CUPS)
1318 void PrintPreviewHandler::SaveCUPSColorSetting(
1319 const base::DictionaryValue
* settings
) {
1320 cups_printer_color_models_
.reset(new CUPSPrinterColorModels
);
1321 settings
->GetString(kPrinterId
, &cups_printer_color_models_
->printer_name
);
1322 settings
->GetInteger(
1324 reinterpret_cast<int*>(&cups_printer_color_models_
->color_model
));
1325 settings
->GetInteger(
1327 reinterpret_cast<int*>(&cups_printer_color_models_
->bw_model
));
1330 void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
1331 base::DictionaryValue
* settings
) const {
1332 if (!cups_printer_color_models_
)
1335 // Sanity check the printer name.
1336 std::string printer_name
;
1337 if (!settings
->GetString(printing::kSettingDeviceName
, &printer_name
) ||
1338 printer_name
!= cups_printer_color_models_
->printer_name
) {
1344 if (!settings
->GetInteger(printing::kSettingColor
, &color
)) {
1349 if (color
== printing::GRAY
) {
1350 if (cups_printer_color_models_
->bw_model
!= printing::UNKNOWN_COLOR_MODEL
) {
1351 settings
->SetInteger(printing::kSettingColor
,
1352 cups_printer_color_models_
->bw_model
);
1357 printing::ColorModel color_model
= cups_printer_color_models_
->color_model
;
1358 if (color_model
!= printing::UNKNOWN_COLOR_MODEL
)
1359 settings
->SetInteger(printing::kSettingColor
, color_model
);
1365 #if defined(ENABLE_MDNS)
1366 void PrintPreviewHandler::LocalPrinterChanged(
1368 const std::string
& name
,
1369 bool has_local_printing
,
1370 const local_discovery::DeviceDescription
& description
) {
1371 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
1372 if (has_local_printing
||
1373 (command_line
->HasSwitch(switches::kEnablePrintPreviewRegisterPromos
) &&
1374 description
.id
.empty())) {
1375 base::DictionaryValue info
;
1376 FillPrinterDescription(name
, description
, has_local_printing
, &info
);
1377 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info
);
1381 void PrintPreviewHandler::LocalPrinterRemoved(const std::string
& name
) {
1384 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1387 void PrintPreviewHandler::StopPrivetPrinterSearch() {
1388 printer_lister_
->Stop();
1389 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1392 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1393 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1394 if (!PrivetUpdateClient(http_client
.Pass()))
1397 privet_capabilities_operation_
=
1398 privet_http_client_
->CreateCapabilitiesOperation(
1400 privet_capabilities_operation_
->Start();
1403 bool PrintPreviewHandler::PrivetUpdateClient(
1404 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1406 SendPrivetCapabilitiesError(privet_http_resolution_
->GetName());
1407 privet_http_resolution_
.reset();
1411 privet_local_print_operation_
.reset();
1412 privet_capabilities_operation_
.reset();
1413 privet_http_client_
= http_client
.Pass();
1415 privet_http_resolution_
.reset();
1420 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1421 std::string print_ticket
,
1422 gfx::Size page_size
,
1423 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1424 if (!PrivetUpdateClient(http_client
.Pass()))
1427 StartPrivetLocalPrint(print_ticket
, page_size
);
1430 void PrintPreviewHandler::StartPrivetLocalPrint(
1431 const std::string
& print_ticket
,
1432 const gfx::Size
& page_size
) {
1433 privet_local_print_operation_
=
1434 privet_http_client_
->CreateLocalPrintOperation(this);
1436 privet_local_print_operation_
->SetTicket(print_ticket
);
1438 scoped_refptr
<base::RefCountedBytes
> data
;
1441 if (!GetPreviewDataAndTitle(&data
, &title
)) {
1442 base::FundamentalValue
http_code_value(-1);
1443 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
1447 privet_local_print_operation_
->SetJobname(
1448 base::UTF16ToUTF8(title
));
1450 const int dpi
= printing::kDefaultPdfDpi
;
1452 scale
/= printing::kPointsPerInch
;
1453 // Make vertical rectangle to optimize streaming to printer. Fix orientation
1455 gfx::Rect
area(std::min(page_size
.width(), page_size
.height()) * scale
,
1456 std::max(page_size
.width(), page_size
.height()) * scale
);
1457 privet_local_print_operation_
->SetConversionSettings(
1458 printing::PdfRenderSettings(area
, dpi
, true));
1460 privet_local_print_operation_
->SetData(data
);
1462 Profile
* profile
= Profile::FromWebUI(web_ui());
1463 SigninManagerBase
* signin_manager
=
1464 SigninManagerFactory::GetForProfileIfExists(profile
);
1466 if (signin_manager
) {
1467 privet_local_print_operation_
->SetUsername(
1468 signin_manager
->GetAuthenticatedUsername());
1471 privet_local_print_operation_
->Start();
1475 void PrintPreviewHandler::OnPrivetCapabilities(
1476 local_discovery::PrivetCapabilitiesOperation
* capabilities_operation
,
1478 const base::DictionaryValue
* capabilities
) {
1479 std::string name
= capabilities_operation
->GetHTTPClient()->GetName();
1481 if (!capabilities
|| capabilities
->HasKey(local_discovery::kPrivetKeyError
)) {
1482 SendPrivetCapabilitiesError(name
);
1486 base::DictionaryValue printer_info
;
1487 const local_discovery::DeviceDescription
* description
=
1488 printer_lister_
->GetDeviceDescription(name
);
1491 SendPrivetCapabilitiesError(name
);
1495 FillPrinterDescription(name
, *description
, true, &printer_info
);
1497 web_ui()->CallJavascriptFunction(
1498 "onPrivetCapabilitiesSet",
1502 privet_capabilities_operation_
.reset();
1505 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1506 const std::string
& device_name
) {
1507 base::StringValue
name_value(device_name
);
1508 web_ui()->CallJavascriptFunction(
1509 "failedToGetPrivetPrinterCapabilities",
1513 void PrintPreviewHandler::PrintToPrivetPrinter(
1514 const std::string
& device_name
,
1515 const std::string
& ticket
,
1516 const gfx::Size
& page_size
) {
1519 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient
,
1520 base::Unretained(this), ticket
, page_size
));
1523 bool PrintPreviewHandler::CreatePrivetHTTP(
1524 const std::string
& name
,
1525 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback
&
1527 const local_discovery::DeviceDescription
* device_description
=
1528 printer_lister_
->GetDeviceDescription(name
);
1530 if (!device_description
) {
1531 SendPrivetCapabilitiesError(name
);
1535 privet_http_factory_
=
1536 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1537 service_discovery_client_
,
1538 Profile::FromWebUI(web_ui())->GetRequestContext());
1539 privet_http_resolution_
= privet_http_factory_
->CreatePrivetHTTP(
1541 device_description
->address
,
1543 privet_http_resolution_
->Start();
1548 void PrintPreviewHandler::OnPrivetPrintingDone(
1549 const local_discovery::PrivetLocalPrintOperation
* print_operation
) {
1550 ClosePreviewDialog();
1553 void PrintPreviewHandler::OnPrivetPrintingError(
1554 const local_discovery::PrivetLocalPrintOperation
* print_operation
,
1556 base::FundamentalValue
http_code_value(http_code
);
1557 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
1560 void PrintPreviewHandler::FillPrinterDescription(
1561 const std::string
& name
,
1562 const local_discovery::DeviceDescription
& description
,
1563 bool has_local_printing
,
1564 base::DictionaryValue
* printer_value
) {
1565 printer_value
->SetString("serviceName", name
);
1566 printer_value
->SetString("name", description
.name
);
1567 printer_value
->SetBoolean("hasLocalPrinting", has_local_printing
);
1568 printer_value
->SetBoolean("isUnregistered", description
.id
.empty());