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 PRIVET_DUPLICATE_SELECTED
,
128 CLOUD_DUPLICATE_SELECTED
,
129 PRINT_DESTINATION_BUCKET_BOUNDARY
132 enum GcpPromoBuckets
{
136 GCP_PROMO_BUCKET_BOUNDARY
139 void ReportUserActionHistogram(enum UserActionBuckets event
) {
140 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event
,
141 USERACTION_BUCKET_BOUNDARY
);
144 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting
) {
145 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting
,
146 PRINT_SETTINGS_BUCKET_BOUNDARY
);
149 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event
) {
150 UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event
,
151 PRINT_DESTINATION_BUCKET_BOUNDARY
);
154 void ReportGcpPromoHistogram(enum GcpPromoBuckets event
) {
155 UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event
,
156 GCP_PROMO_BUCKET_BOUNDARY
);
159 // Name of a dictionary field holding cloud print related data;
160 const char kAppState
[] = "appState";
161 // Name of a dictionary field holding the initiator title.
162 const char kInitiatorTitle
[] = "initiatorTitle";
163 // Name of a dictionary field holding the measurement system according to the
165 const char kMeasurementSystem
[] = "measurementSystem";
166 // Name of a dictionary field holding the number format according to the locale.
167 const char kNumberFormat
[] = "numberFormat";
168 // Name of a dictionary field specifying whether to print automatically in
169 // kiosk mode. See http://crbug.com/31395.
170 const char kPrintAutomaticallyInKioskMode
[] = "printAutomaticallyInKioskMode";
172 const char kHidePrintWithSystemDialogLink
[] = "hidePrintWithSystemDialogLink";
174 // Name of a dictionary field holding the state of selection for document.
175 const char kDocumentHasSelection
[] = "documentHasSelection";
177 // Additional printer capability setting keys.
178 const char kPrinterId
[] = "printerId";
179 const char kDisableColorOption
[] = "disableColorOption";
180 const char kSetDuplexAsDefault
[] = "setDuplexAsDefault";
181 const char kPrinterDefaultDuplexValue
[] = "printerDefaultDuplexValue";
182 #if defined(USE_CUPS)
183 const char kCUPSsColorModel
[] = "cupsColorModel";
184 const char kCUPSsBWModel
[] = "cupsBWModel";
187 // Get the print job settings dictionary from |args|. The caller takes
188 // ownership of the returned DictionaryValue. Returns NULL on failure.
189 base::DictionaryValue
* GetSettingsDictionary(const base::ListValue
* args
) {
190 std::string json_str
;
191 if (!args
->GetString(0, &json_str
)) {
192 NOTREACHED() << "Could not read JSON argument";
195 if (json_str
.empty()) {
196 NOTREACHED() << "Empty print job settings";
199 scoped_ptr
<base::DictionaryValue
> settings(
200 static_cast<base::DictionaryValue
*>(
201 base::JSONReader::Read(json_str
)));
202 if (!settings
.get() || !settings
->IsType(base::Value::TYPE_DICTIONARY
)) {
203 NOTREACHED() << "Print job settings must be a dictionary.";
207 if (settings
->empty()) {
208 NOTREACHED() << "Print job settings dictionary is empty";
212 return settings
.release();
215 // Track the popularity of print settings and report the stats.
216 void ReportPrintSettingsStats(const base::DictionaryValue
& settings
) {
217 ReportPrintSettingHistogram(TOTAL
);
219 bool landscape
= false;
220 if (settings
.GetBoolean(printing::kSettingLandscape
, &landscape
))
221 ReportPrintSettingHistogram(landscape
? LANDSCAPE
: PORTRAIT
);
223 bool collate
= false;
224 if (settings
.GetBoolean(printing::kSettingCollate
, &collate
) && collate
)
225 ReportPrintSettingHistogram(COLLATE
);
228 if (settings
.GetInteger(printing::kSettingDuplexMode
, &duplex_mode
))
229 ReportPrintSettingHistogram(duplex_mode
? DUPLEX
: SIMPLEX
);
232 if (settings
.GetInteger(printing::kSettingColor
, &color_mode
)) {
233 ReportPrintSettingHistogram(
234 printing::IsColorModelSelected(color_mode
) ? COLOR
: BLACK_AND_WHITE
);
237 bool headers
= false;
238 if (settings
.GetBoolean(printing::kSettingHeaderFooterEnabled
, &headers
) &&
240 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS
);
243 bool css_background
= false;
244 if (settings
.GetBoolean(printing::kSettingShouldPrintBackgrounds
,
245 &css_background
) && css_background
) {
246 ReportPrintSettingHistogram(CSS_BACKGROUND
);
249 bool selection_only
= false;
250 if (settings
.GetBoolean(printing::kSettingShouldPrintSelectionOnly
,
251 &selection_only
) && selection_only
) {
252 ReportPrintSettingHistogram(SELECTION_ONLY
);
256 // Callback that stores a PDF file on disk.
257 void PrintToPdfCallback(printing::Metafile
* metafile
,
258 const base::FilePath
& path
) {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
260 metafile
->SaveTo(path
);
261 // |metafile| must be deleted on the UI thread.
262 BrowserThread::DeleteSoon(BrowserThread::UI
, FROM_HERE
, metafile
);
265 std::string
GetDefaultPrinterOnFileThread(
266 scoped_refptr
<printing::PrintBackend
> print_backend
) {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
269 std::string default_printer
= print_backend
->GetDefaultPrinterName();
270 VLOG(1) << "Default Printer: " << default_printer
;
271 return default_printer
;
274 void EnumeratePrintersOnFileThread(
275 scoped_refptr
<printing::PrintBackend
> print_backend
,
276 base::ListValue
* printers
) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
279 VLOG(1) << "Enumerate printers start";
280 printing::PrinterList printer_list
;
281 print_backend
->EnumeratePrinters(&printer_list
);
283 for (printing::PrinterList::iterator it
= printer_list
.begin();
284 it
!= printer_list
.end(); ++it
) {
285 base::DictionaryValue
* printer_info
= new base::DictionaryValue
;
286 std::string printer_name
;
287 #if defined(OS_MACOSX)
288 // On Mac, |it->printer_description| specifies the printer name and
289 // |it->printer_name| specifies the device name / printer queue name.
290 printer_name
= it
->printer_description
;
292 printer_name
= it
->printer_name
;
294 printer_info
->SetString(printing::kSettingPrinterName
, printer_name
);
295 printer_info
->SetString(printing::kSettingDeviceName
, it
->printer_name
);
296 VLOG(1) << "Found printer " << printer_name
297 << " with device name " << it
->printer_name
;
298 printers
->Append(printer_info
);
300 VLOG(1) << "Enumerate printers finished, found " << printers
->GetSize()
304 typedef base::Callback
<void(const base::DictionaryValue
*)>
305 GetPrinterCapabilitiesSuccessCallback
;
306 typedef base::Callback
<void(const std::string
&)>
307 GetPrinterCapabilitiesFailureCallback
;
309 void GetPrinterCapabilitiesOnFileThread(
310 scoped_refptr
<printing::PrintBackend
> print_backend
,
311 const std::string
& printer_name
,
312 const GetPrinterCapabilitiesSuccessCallback
& success_cb
,
313 const GetPrinterCapabilitiesFailureCallback
& failure_cb
) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
315 DCHECK(!printer_name
.empty());
317 VLOG(1) << "Get printer capabilities start for " << printer_name
;
318 crash_keys::ScopedPrinterInfo
crash_key(
319 print_backend
->GetPrinterDriverInfo(printer_name
));
321 if (!print_backend
->IsValidPrinter(printer_name
)) {
322 // TODO(gene): Notify explicitly if printer is not valid, instead of
323 // failed to get capabilities.
324 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
325 base::Bind(failure_cb
, printer_name
));
329 printing::PrinterSemanticCapsAndDefaults info
;
330 if (!print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
, &info
)) {
331 LOG(WARNING
) << "Failed to get capabilities for " << printer_name
;
332 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
333 base::Bind(failure_cb
, printer_name
));
337 scoped_ptr
<base::DictionaryValue
> settings_info(new base::DictionaryValue
);
338 settings_info
->SetString(kPrinterId
, printer_name
);
339 settings_info
->SetBoolean(kDisableColorOption
, !info
.color_changeable
);
340 settings_info
->SetBoolean(printing::kSettingSetColorAsDefault
,
342 #if defined(USE_CUPS)
343 settings_info
->SetInteger(kCUPSsColorModel
, info
.color_model
);
344 settings_info
->SetInteger(kCUPSsBWModel
, info
.bw_model
);
347 // TODO(gene): Make new capabilities format for Print Preview
348 // that will suit semantic capabiltities better.
349 // Refactor pld API code below
350 bool default_duplex
= info
.duplex_capable
?
351 (info
.duplex_default
!= printing::SIMPLEX
) : false;
352 int duplex_value
= info
.duplex_capable
?
353 printing::LONG_EDGE
: printing::UNKNOWN_DUPLEX_MODE
;
354 settings_info
->SetBoolean(kSetDuplexAsDefault
, default_duplex
);
355 settings_info
->SetInteger(kPrinterDefaultDuplexValue
, duplex_value
);
357 BrowserThread::PostTask(
358 BrowserThread::UI
, FROM_HERE
,
359 base::Bind(success_cb
, base::Owned(settings_info
.release())));
362 base::LazyInstance
<printing::StickySettings
> g_sticky_settings
=
363 LAZY_INSTANCE_INITIALIZER
;
365 printing::StickySettings
* GetStickySettings() {
366 return g_sticky_settings
.Pointer();
371 #if defined(USE_CUPS)
372 struct PrintPreviewHandler::CUPSPrinterColorModels
{
373 std::string printer_name
;
374 printing::ColorModel color_model
;
375 printing::ColorModel bw_model
;
379 class PrintPreviewHandler::AccessTokenService
380 : public OAuth2TokenService::Consumer
{
382 explicit AccessTokenService(PrintPreviewHandler
* handler
)
383 : OAuth2TokenService::Consumer("print_preview"),
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("stopGetPrivetPrinters",
549 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters
,
550 base::Unretained(this)));
551 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
552 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities
,
553 base::Unretained(this)));
556 bool PrintPreviewHandler::PrivetPrintingEnabled() {
557 #if defined(ENABLE_MDNS)
558 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
559 return !command_line
->HasSwitch(switches::kDisableDeviceDiscovery
) &&
560 !command_line
->HasSwitch(switches::kDisablePrivetLocalPrinting
);
566 WebContents
* PrintPreviewHandler::preview_web_contents() const {
567 return web_ui()->GetWebContents();
570 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue
* /*args*/) {
571 base::ListValue
* results
= new base::ListValue
;
572 BrowserThread::PostTaskAndReply(
573 BrowserThread::FILE, FROM_HERE
,
574 base::Bind(&EnumeratePrintersOnFileThread
, print_backend_
,
575 base::Unretained(results
)),
576 base::Bind(&PrintPreviewHandler::SetupPrinterList
,
577 weak_factory_
.GetWeakPtr(),
578 base::Owned(results
)));
581 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue
* args
) {
582 #if defined(ENABLE_MDNS)
583 if (PrivetPrintingEnabled()) {
584 Profile
* profile
= Profile::FromWebUI(web_ui());
585 service_discovery_client_
=
586 local_discovery::ServiceDiscoverySharedClient::GetInstance();
587 printer_lister_
.reset(new local_discovery::PrivetLocalPrinterLister(
588 service_discovery_client_
.get(),
589 profile
->GetRequestContext(),
591 printer_lister_
->Start();
595 if (!PrivetPrintingEnabled()) {
596 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
600 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
601 const base::ListValue
* args
) {
602 #if defined(ENABLE_MDNS)
603 if (PrivetPrintingEnabled()) {
604 printer_lister_
->Stop();
609 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
610 const base::ListValue
* args
) {
611 #if defined(ENABLE_MDNS)
613 bool success
= args
->GetString(0, &name
);
618 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient
,
619 base::Unretained(this)));
623 void PrintPreviewHandler::HandleGetPreview(const base::ListValue
* args
) {
624 DCHECK_EQ(3U, args
->GetSize());
625 scoped_ptr
<base::DictionaryValue
> settings(GetSettingsDictionary(args
));
629 if (!settings
->GetInteger(printing::kPreviewRequestID
, &request_id
))
632 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
633 web_ui()->GetController());
634 print_preview_ui
->OnPrintPreviewRequest(request_id
);
635 // Add an additional key in order to identify |print_preview_ui| later on
636 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
638 settings
->SetInteger(printing::kPreviewUIID
,
639 print_preview_ui
->GetIDForPrintPreviewUI());
641 // Increment request count.
642 ++regenerate_preview_request_count_
;
644 WebContents
* initiator
= GetInitiator();
646 ReportUserActionHistogram(INITIATOR_CLOSED
);
647 print_preview_ui
->OnClosePrintPreviewDialog();
651 // Retrieve the page title and url and send it to the renderer process if
652 // headers and footers are to be displayed.
653 bool display_header_footer
= false;
654 if (!settings
->GetBoolean(printing::kSettingHeaderFooterEnabled
,
655 &display_header_footer
)) {
658 if (display_header_footer
) {
659 settings
->SetString(printing::kSettingHeaderFooterTitle
,
660 initiator
->GetTitle());
662 content::NavigationEntry
* entry
=
663 initiator
->GetController().GetLastCommittedEntry();
665 url
= entry
->GetVirtualURL().spec();
666 settings
->SetString(printing::kSettingHeaderFooterURL
, url
);
669 bool generate_draft_data
= false;
670 bool success
= settings
->GetBoolean(printing::kSettingGenerateDraftData
,
671 &generate_draft_data
);
674 if (!generate_draft_data
) {
675 double draft_page_count_double
= -1;
676 success
= args
->GetDouble(1, &draft_page_count_double
);
678 int draft_page_count
= static_cast<int>(draft_page_count_double
);
680 bool preview_modifiable
= false;
681 success
= args
->GetBoolean(2, &preview_modifiable
);
684 if (draft_page_count
!= -1 && preview_modifiable
&&
685 print_preview_ui
->GetAvailableDraftPageCount() != draft_page_count
) {
686 settings
->SetBoolean(printing::kSettingGenerateDraftData
, true);
690 VLOG(1) << "Print preview request start";
691 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
692 rvh
->Send(new PrintMsg_PrintPreview(rvh
->GetRoutingID(), *settings
));
695 void PrintPreviewHandler::HandlePrint(const base::ListValue
* args
) {
698 // Record the number of times the user requests to regenerate preview data
700 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
701 regenerate_preview_request_count_
);
703 WebContents
* initiator
= GetInitiator();
705 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
706 rvh
->Send(new PrintMsg_ResetScriptedPrintCount(rvh
->GetRoutingID()));
709 scoped_ptr
<base::DictionaryValue
> settings(GetSettingsDictionary(args
));
713 // Never try to add headers/footers here. It's already in the generated PDF.
714 settings
->SetBoolean(printing::kSettingHeaderFooterEnabled
, false);
716 bool print_to_pdf
= false;
717 bool is_cloud_printer
= false;
718 bool print_with_privet
= false;
720 bool open_pdf_in_preview
= false;
721 #if defined(OS_MACOSX)
722 open_pdf_in_preview
= settings
->HasKey(printing::kSettingOpenPDFInPreview
);
725 if (!open_pdf_in_preview
) {
726 settings
->GetBoolean(printing::kSettingPrintToPDF
, &print_to_pdf
);
727 settings
->GetBoolean(printing::kSettingPrintWithPrivet
, &print_with_privet
);
728 is_cloud_printer
= settings
->HasKey(printing::kSettingCloudPrintId
);
732 settings
->GetInteger(printing::kSettingPreviewPageCount
, &page_count
);
735 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count
);
736 ReportUserActionHistogram(PRINT_TO_PDF
);
741 #if defined(ENABLE_MDNS)
742 if (print_with_privet
&& PrivetPrintingEnabled()) {
743 std::string printer_name
;
744 std::string print_ticket
;
745 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count
);
746 ReportUserActionHistogram(PRINT_WITH_PRIVET
);
750 if (!settings
->GetString(printing::kSettingDeviceName
, &printer_name
) ||
751 !settings
->GetString(printing::kSettingTicket
, &print_ticket
) ||
752 !settings
->GetInteger(printing::kSettingPageWidth
, &width
) ||
753 !settings
->GetInteger(printing::kSettingPageHeight
, &height
) ||
754 width
<= 0 || height
<=0) {
756 base::FundamentalValue
http_code_value(-1);
757 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
761 PrintToPrivetPrinter(printer_name
, print_ticket
, gfx::Size(width
, height
));
766 scoped_refptr
<base::RefCountedBytes
> data
;
767 base::string16 title
;
768 if (!GetPreviewDataAndTitle(&data
, &title
)) {
769 // Nothing to print, no preview available.
773 if (is_cloud_printer
) {
774 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
776 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT
);
777 SendCloudPrintJob(data
.get());
779 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count
);
780 ReportUserActionHistogram(PRINT_TO_PRINTER
);
781 ReportPrintSettingsStats(*settings
);
783 // This tries to activate the initiator as well, so do not clear the
784 // association with the initiator yet.
785 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
786 web_ui()->GetController());
787 print_preview_ui
->OnHidePreviewDialog();
789 // Do this so the initiator can open a new print preview dialog, while the
790 // current print preview dialog is still handling its print job.
791 ClearInitiatorDetails();
793 // The PDF being printed contains only the pages that the user selected,
794 // so ignore the page range and print all pages.
795 settings
->Remove(printing::kSettingPageRange
, NULL
);
796 // Reset selection only flag for the same reason.
797 settings
->SetBoolean(printing::kSettingShouldPrintSelectionOnly
, false);
799 #if defined(USE_CUPS)
800 if (!open_pdf_in_preview
) // We can get here even for cloud printers.
801 ConvertColorSettingToCUPSColorModel(settings
.get());
804 // Set ID to know whether printing is for preview.
805 settings
->SetInteger(printing::kPreviewUIID
,
806 print_preview_ui
->GetIDForPrintPreviewUI());
807 RenderViewHost
* rvh
= preview_web_contents()->GetRenderViewHost();
808 rvh
->Send(new PrintMsg_PrintForPrintPreview(rvh
->GetRoutingID(),
811 // For all other cases above, the preview dialog will stay open until the
812 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
813 // called. In the case below, since the preview dialog will be hidden and
814 // not closed, we need to make this call.
816 printing::PrintViewManager
* print_view_manager
=
817 printing::PrintViewManager::FromWebContents(initiator
);
818 print_view_manager
->PrintPreviewDone();
823 void PrintPreviewHandler::PrintToPdf() {
824 if (!print_to_pdf_path_
.empty()) {
825 // User has already selected a path, no need to show the dialog again.
826 PostPrintToPdfTask();
827 } else if (!select_file_dialog_
.get() ||
828 !select_file_dialog_
->IsRunning(platform_util::GetTopLevel(
829 preview_web_contents()->GetView()->GetNativeView()))) {
830 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
831 web_ui()->GetController());
832 // Pre-populating select file dialog with print job title.
833 base::string16 print_job_title_utf16
= print_preview_ui
->initiator_title();
836 base::FilePath::StringType
print_job_title(print_job_title_utf16
);
837 #elif defined(OS_POSIX)
838 base::FilePath::StringType print_job_title
=
839 base::UTF16ToUTF8(print_job_title_utf16
);
842 file_util::ReplaceIllegalCharactersInPath(&print_job_title
, '_');
843 base::FilePath
default_filename(print_job_title
);
845 default_filename
.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
847 SelectFile(default_filename
);
851 void PrintPreviewHandler::HandleHidePreview(const base::ListValue
* /*args*/) {
852 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
853 web_ui()->GetController());
854 print_preview_ui
->OnHidePreviewDialog();
857 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
858 const base::ListValue
* /*args*/) {
859 WebContents
* initiator
= GetInitiator();
861 ClearInitiatorDetails();
862 gfx::NativeWindow parent
= initiator
?
863 initiator
->GetView()->GetTopLevelNativeWindow() :
865 chrome::ShowPrintErrorDialog(parent
);
868 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue
* args
) {
869 std::string data_to_save
;
870 printing::StickySettings
* sticky_settings
= GetStickySettings();
871 if (args
->GetString(0, &data_to_save
) && !data_to_save
.empty())
872 sticky_settings
->StoreAppState(data_to_save
);
873 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
874 preview_web_contents()->GetBrowserContext())->GetPrefs());
877 void PrintPreviewHandler::HandleGetPrinterCapabilities(
878 const base::ListValue
* args
) {
879 std::string printer_name
;
880 bool ret
= args
->GetString(0, &printer_name
);
881 if (!ret
|| printer_name
.empty())
884 GetPrinterCapabilitiesSuccessCallback success_cb
=
885 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities
,
886 weak_factory_
.GetWeakPtr());
887 GetPrinterCapabilitiesFailureCallback failure_cb
=
888 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities
,
889 weak_factory_
.GetWeakPtr());
890 BrowserThread::PostTask(
891 BrowserThread::FILE, FROM_HERE
,
892 base::Bind(&GetPrinterCapabilitiesOnFileThread
,
893 print_backend_
, printer_name
, success_cb
, failure_cb
));
896 void PrintPreviewHandler::OnSigninComplete() {
897 PrintPreviewUI
* print_preview_ui
=
898 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
899 if (print_preview_ui
)
900 print_preview_ui
->OnReloadPrintersList();
903 void PrintPreviewHandler::HandleSignin(const base::ListValue
* /*args*/) {
904 Browser
* browser
= chrome::FindBrowserWithWebContents(GetInitiator());
905 print_dialog_cloud::CreateCloudPrintSigninTab(
907 base::Bind(&PrintPreviewHandler::OnSigninComplete
,
908 weak_factory_
.GetWeakPtr()));
911 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue
* args
) {
913 if (!args
->GetString(0, &type
))
916 token_service_
.reset(new AccessTokenService(this));
917 token_service_
->RequestToken(type
);
920 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
921 // Record the number of times the user asks to print via cloud print
922 // instead of the print preview dialog.
925 scoped_refptr
<base::RefCountedBytes
> data
;
926 base::string16 title
;
927 if (!GetPreviewDataAndTitle(&data
, &title
)) {
928 // Nothing to print, no preview available.
932 gfx::NativeWindow modal_parent
= platform_util::GetTopLevel(
933 preview_web_contents()->GetView()->GetNativeView());
934 print_dialog_cloud::CreatePrintDialogForBytes(
935 preview_web_contents()->GetBrowserContext(),
940 std::string("application/pdf"));
942 // Once the cloud print dialog comes up we're no longer in a background
943 // printing situation. Close the print preview.
944 // TODO(abodenha@chromium.org) The flow should be changed as described in
945 // http://code.google.com/p/chromium/issues/detail?id=44093
946 ClosePreviewDialog();
949 void PrintPreviewHandler::HandleManageCloudPrint(
950 const base::ListValue
* /*args*/) {
951 ++manage_cloud_printers_dialog_request_count_
;
952 Profile
* profile
= Profile::FromBrowserContext(
953 preview_web_contents()->GetBrowserContext());
954 preview_web_contents()->OpenURL(
955 content::OpenURLParams(
956 CloudPrintURL(profile
).GetCloudPrintServiceManageURL(),
959 content::PAGE_TRANSITION_LINK
,
963 void PrintPreviewHandler::HandleShowSystemDialog(
964 const base::ListValue
* /*args*/) {
966 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
968 WebContents
* initiator
= GetInitiator();
972 printing::PrintViewManager
* print_view_manager
=
973 printing::PrintViewManager::FromWebContents(initiator
);
974 print_view_manager
->set_observer(this);
975 print_view_manager
->PrintForSystemDialogNow();
977 // Cancel the pending preview request if exists.
978 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
979 web_ui()->GetController());
980 print_preview_ui
->OnCancelPendingPreviewRequest();
983 void PrintPreviewHandler::HandleManagePrinters(
984 const base::ListValue
* /*args*/) {
985 ++manage_printers_dialog_request_count_
;
986 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
989 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
990 const base::ListValue
* args
) {
992 if (!args
|| !args
->GetInteger(0, &page_count
))
994 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
997 PrintWithCloudPrintDialog();
1000 void PrintPreviewHandler::HandleClosePreviewDialog(
1001 const base::ListValue
* /*args*/) {
1003 ReportUserActionHistogram(CANCEL
);
1005 // Record the number of times the user requests to regenerate preview data
1006 // before cancelling.
1007 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1008 regenerate_preview_request_count_
);
1011 void PrintPreviewHandler::ReportStats() {
1012 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1013 manage_printers_dialog_request_count_
);
1014 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1015 manage_cloud_printers_dialog_request_count_
);
1018 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1019 base::DictionaryValue
* settings
) {
1021 // Getting the measurement system based on the locale.
1022 UErrorCode errorCode
= U_ZERO_ERROR
;
1023 const char* locale
= g_browser_process
->GetApplicationLocale().c_str();
1024 UMeasurementSystem system
= ulocdata_getMeasurementSystem(locale
, &errorCode
);
1025 if (errorCode
> U_ZERO_ERROR
|| system
== UMS_LIMIT
)
1028 // Getting the number formatting based on the locale and writing to
1030 settings
->SetString(kNumberFormat
, base::FormatDouble(123456.78, 2));
1031 settings
->SetInteger(kMeasurementSystem
, system
);
1034 void PrintPreviewHandler::HandleGetInitialSettings(
1035 const base::ListValue
* /*args*/) {
1036 // Send before SendInitialSettings to allow cloud printer auto select.
1037 SendCloudPrintEnabled();
1038 BrowserThread::PostTaskAndReplyWithResult(
1039 BrowserThread::FILE, FROM_HERE
,
1040 base::Bind(&GetDefaultPrinterOnFileThread
, print_backend_
),
1041 base::Bind(&PrintPreviewHandler::SendInitialSettings
,
1042 weak_factory_
.GetWeakPtr()));
1045 void PrintPreviewHandler::HandleReportUiEvent(const base::ListValue
* args
) {
1046 int event_group
, event_number
;
1047 if (!args
->GetInteger(0, &event_group
) || !args
->GetInteger(1, &event_number
))
1050 enum UiBucketGroups ui_bucket_group
=
1051 static_cast<enum UiBucketGroups
>(event_group
);
1052 if (ui_bucket_group
>= UI_BUCKET_GROUP_BOUNDARY
)
1055 switch (ui_bucket_group
) {
1056 case DESTINATION_SEARCH
: {
1057 enum PrintDestinationBuckets event
=
1058 static_cast<enum PrintDestinationBuckets
>(event_number
);
1059 if (event
>= PRINT_DESTINATION_BUCKET_BOUNDARY
)
1061 ReportPrintDestinationHistogram(event
);
1065 enum GcpPromoBuckets event
=
1066 static_cast<enum GcpPromoBuckets
>(event_number
);
1067 if (event
>= GCP_PROMO_BUCKET_BOUNDARY
)
1069 ReportGcpPromoHistogram(event
);
1077 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue
* args
) {
1079 if (!args
->GetString(0, &url
))
1081 Browser
* browser
= chrome::FindBrowserWithWebContents(GetInitiator());
1084 chrome::AddSelectedTabWithURL(browser
,
1086 content::PAGE_TRANSITION_LINK
);
1089 void PrintPreviewHandler::SendInitialSettings(
1090 const std::string
& default_printer
) {
1091 PrintPreviewUI
* print_preview_ui
=
1092 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1094 base::DictionaryValue initial_settings
;
1095 initial_settings
.SetString(kInitiatorTitle
,
1096 print_preview_ui
->initiator_title());
1097 initial_settings
.SetBoolean(printing::kSettingPreviewModifiable
,
1098 print_preview_ui
->source_is_modifiable());
1099 initial_settings
.SetString(printing::kSettingPrinterName
, default_printer
);
1100 initial_settings
.SetBoolean(kDocumentHasSelection
,
1101 print_preview_ui
->source_has_selection());
1102 initial_settings
.SetBoolean(printing::kSettingShouldPrintSelectionOnly
,
1103 print_preview_ui
->print_selection_only());
1104 printing::StickySettings
* sticky_settings
= GetStickySettings();
1105 sticky_settings
->RestoreFromPrefs(Profile::FromBrowserContext(
1106 preview_web_contents()->GetBrowserContext())->GetPrefs());
1107 if (sticky_settings
->printer_app_state())
1108 initial_settings
.SetString(kAppState
,
1109 *sticky_settings
->printer_app_state());
1111 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
1112 initial_settings
.SetBoolean(kPrintAutomaticallyInKioskMode
,
1113 cmdline
->HasSwitch(switches::kKioskModePrinting
));
1115 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1116 // so will cause the browser to appear hung, so we don't show the link in
1118 bool is_ash
= (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH
);
1119 initial_settings
.SetBoolean(kHidePrintWithSystemDialogLink
, is_ash
);
1122 if (print_preview_ui
->source_is_modifiable())
1123 GetNumberFormatAndMeasurementSystem(&initial_settings
);
1124 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings
);
1127 void PrintPreviewHandler::ClosePreviewDialog() {
1128 PrintPreviewUI
* print_preview_ui
=
1129 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1130 print_preview_ui
->OnClosePrintPreviewDialog();
1133 void PrintPreviewHandler::SendAccessToken(const std::string
& type
,
1134 const std::string
& access_token
) {
1135 VLOG(1) << "Get getAccessToken finished";
1136 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1137 base::StringValue(type
),
1138 base::StringValue(access_token
));
1141 void PrintPreviewHandler::SendPrinterCapabilities(
1142 const base::DictionaryValue
* settings_info
) {
1143 VLOG(1) << "Get printer capabilities finished";
1145 #if defined(USE_CUPS)
1146 SaveCUPSColorSetting(settings_info
);
1149 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1153 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1154 const std::string
& printer_name
) {
1155 VLOG(1) << "Get printer capabilities failed";
1156 base::StringValue
printer_name_value(printer_name
);
1157 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1158 printer_name_value
);
1161 void PrintPreviewHandler::SetupPrinterList(const base::ListValue
* printers
) {
1162 if (!has_logged_printers_count_
) {
1163 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers
->GetSize());
1164 has_logged_printers_count_
= true;
1167 web_ui()->CallJavascriptFunction("setPrinters", *printers
);
1170 void PrintPreviewHandler::SendCloudPrintEnabled() {
1171 Profile
* profile
= Profile::FromBrowserContext(
1172 preview_web_contents()->GetBrowserContext());
1173 PrefService
* prefs
= profile
->GetPrefs();
1174 if (prefs
->GetBoolean(prefs::kCloudPrintSubmitEnabled
)) {
1175 GURL
gcp_url(CloudPrintURL(profile
).GetCloudPrintServiceURL());
1176 base::StringValue
gcp_url_value(gcp_url
.spec());
1177 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value
);
1181 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes
* data
) {
1182 // BASE64 encode the job data.
1183 std::string
raw_data(reinterpret_cast<const char*>(data
->front()),
1185 std::string base64_data
;
1186 base::Base64Encode(raw_data
, &base64_data
);
1187 base::StringValue
data_value(base64_data
);
1189 web_ui()->CallJavascriptFunction("printToCloud", data_value
);
1192 WebContents
* PrintPreviewHandler::GetInitiator() const {
1193 printing::PrintPreviewDialogController
* dialog_controller
=
1194 printing::PrintPreviewDialogController::GetInstance();
1195 if (!dialog_controller
)
1197 return dialog_controller
->GetInitiator(preview_web_contents());
1200 void PrintPreviewHandler::OnPrintDialogShown() {
1201 ClosePreviewDialog();
1204 void PrintPreviewHandler::SelectFile(const base::FilePath
& default_filename
) {
1205 ui::SelectFileDialog::FileTypeInfo file_type_info
;
1206 file_type_info
.extensions
.resize(1);
1207 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pdf"));
1209 // Initializing |save_path_| if it is not already initialized.
1210 printing::StickySettings
* sticky_settings
= GetStickySettings();
1211 if (!sticky_settings
->save_path()) {
1212 // Allowing IO operation temporarily. It is ok to do so here because
1213 // the select file dialog performs IO anyway in order to display the
1214 // folders and also it is modal.
1215 base::ThreadRestrictions::ScopedAllowIO allow_io
;
1216 base::FilePath file_path
;
1217 PathService::Get(chrome::DIR_USER_DOCUMENTS
, &file_path
);
1218 sticky_settings
->StoreSavePath(file_path
);
1219 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1220 preview_web_contents()->GetBrowserContext())->GetPrefs());
1223 select_file_dialog_
= ui::SelectFileDialog::Create(
1224 this, new ChromeSelectFilePolicy(preview_web_contents())),
1225 select_file_dialog_
->SelectFile(
1226 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
1228 sticky_settings
->save_path()->Append(default_filename
),
1231 base::FilePath::StringType(),
1232 platform_util::GetTopLevel(
1233 preview_web_contents()->GetView()->GetNativeView()),
1237 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1238 WebContents
* initiator
= GetInitiator();
1242 printing::PrintViewManager
* print_view_manager
=
1243 printing::PrintViewManager::FromWebContents(initiator
);
1244 print_view_manager
->set_observer(NULL
);
1247 void PrintPreviewHandler::OnPrintPreviewFailed() {
1248 if (reported_failed_preview_
)
1250 reported_failed_preview_
= true;
1251 ReportUserActionHistogram(PREVIEW_FAILED
);
1254 void PrintPreviewHandler::ShowSystemDialog() {
1255 HandleShowSystemDialog(NULL
);
1258 void PrintPreviewHandler::FileSelected(const base::FilePath
& path
,
1259 int index
, void* params
) {
1260 // Updating |save_path_| to the newly selected folder.
1261 printing::StickySettings
* sticky_settings
= GetStickySettings();
1262 sticky_settings
->StoreSavePath(path
.DirName());
1263 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1264 preview_web_contents()->GetBrowserContext())->GetPrefs());
1265 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1266 print_to_pdf_path_
= path
;
1267 PostPrintToPdfTask();
1270 void PrintPreviewHandler::PostPrintToPdfTask() {
1271 scoped_refptr
<base::RefCountedBytes
> data
;
1272 base::string16 title
;
1273 if (!GetPreviewDataAndTitle(&data
, &title
)) {
1274 NOTREACHED() << "Preview data was checked before file dialog.";
1277 scoped_ptr
<printing::PreviewMetafile
> metafile(new printing::PreviewMetafile
);
1278 metafile
->InitFromData(static_cast<const void*>(data
->front()), data
->size());
1279 BrowserThread::PostTask(
1280 BrowserThread::FILE, FROM_HERE
,
1281 base::Bind(&PrintToPdfCallback
, metafile
.release(), print_to_pdf_path_
));
1282 print_to_pdf_path_
= base::FilePath();
1283 ClosePreviewDialog();
1286 void PrintPreviewHandler::FileSelectionCanceled(void* params
) {
1287 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1288 web_ui()->GetController());
1289 print_preview_ui
->OnFileSelectionCancelled();
1292 void PrintPreviewHandler::ClearInitiatorDetails() {
1293 WebContents
* initiator
= GetInitiator();
1297 // We no longer require the initiator details. Remove those details associated
1298 // with the preview dialog to allow the initiator to create another preview
1300 printing::PrintPreviewDialogController
* dialog_controller
=
1301 printing::PrintPreviewDialogController::GetInstance();
1302 if (dialog_controller
)
1303 dialog_controller
->EraseInitiatorInfo(preview_web_contents());
1306 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1307 scoped_refptr
<base::RefCountedBytes
>* data
,
1308 base::string16
* title
) const {
1309 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1310 web_ui()->GetController());
1311 scoped_refptr
<base::RefCountedBytes
> tmp_data
;
1312 print_preview_ui
->GetPrintPreviewDataForIndex(
1313 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX
, &tmp_data
);
1315 if (!tmp_data
.get()) {
1316 // Nothing to print, no preview available.
1319 DCHECK(tmp_data
->size() && tmp_data
->front());
1322 *title
= print_preview_ui
->initiator_title();
1326 #if defined(USE_CUPS)
1327 void PrintPreviewHandler::SaveCUPSColorSetting(
1328 const base::DictionaryValue
* settings
) {
1329 cups_printer_color_models_
.reset(new CUPSPrinterColorModels
);
1330 settings
->GetString(kPrinterId
, &cups_printer_color_models_
->printer_name
);
1331 settings
->GetInteger(
1333 reinterpret_cast<int*>(&cups_printer_color_models_
->color_model
));
1334 settings
->GetInteger(
1336 reinterpret_cast<int*>(&cups_printer_color_models_
->bw_model
));
1339 void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
1340 base::DictionaryValue
* settings
) const {
1341 if (!cups_printer_color_models_
)
1344 // Sanity check the printer name.
1345 std::string printer_name
;
1346 if (!settings
->GetString(printing::kSettingDeviceName
, &printer_name
) ||
1347 printer_name
!= cups_printer_color_models_
->printer_name
) {
1353 if (!settings
->GetInteger(printing::kSettingColor
, &color
)) {
1358 if (color
== printing::GRAY
) {
1359 if (cups_printer_color_models_
->bw_model
!= printing::UNKNOWN_COLOR_MODEL
) {
1360 settings
->SetInteger(printing::kSettingColor
,
1361 cups_printer_color_models_
->bw_model
);
1366 printing::ColorModel color_model
= cups_printer_color_models_
->color_model
;
1367 if (color_model
!= printing::UNKNOWN_COLOR_MODEL
)
1368 settings
->SetInteger(printing::kSettingColor
, color_model
);
1374 #if defined(ENABLE_MDNS)
1375 void PrintPreviewHandler::LocalPrinterChanged(
1377 const std::string
& name
,
1378 bool has_local_printing
,
1379 const local_discovery::DeviceDescription
& description
) {
1380 base::DictionaryValue info
;
1381 FillPrinterDescription(name
, description
, has_local_printing
, &info
);
1382 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info
);
1385 void PrintPreviewHandler::LocalPrinterRemoved(const std::string
& name
) {
1388 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1391 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1392 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1393 if (!PrivetUpdateClient(http_client
.Pass()))
1396 privet_capabilities_operation_
=
1397 privet_http_client_
->CreateCapabilitiesOperation(
1398 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities
,
1399 base::Unretained(this)));
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
;
1439 base::string16 title
;
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 const base::DictionaryValue
* capabilities
) {
1477 std::string name
= privet_capabilities_operation_
->GetHTTPClient()->GetName();
1479 if (!capabilities
|| capabilities
->HasKey(local_discovery::kPrivetKeyError
)) {
1480 SendPrivetCapabilitiesError(name
);
1484 base::DictionaryValue printer_info
;
1485 const local_discovery::DeviceDescription
* description
=
1486 printer_lister_
->GetDeviceDescription(name
);
1489 SendPrivetCapabilitiesError(name
);
1493 FillPrinterDescription(name
, *description
, true, &printer_info
);
1495 web_ui()->CallJavascriptFunction(
1496 "onPrivetCapabilitiesSet",
1500 privet_capabilities_operation_
.reset();
1503 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1504 const std::string
& device_name
) {
1505 base::StringValue
name_value(device_name
);
1506 web_ui()->CallJavascriptFunction(
1507 "failedToGetPrivetPrinterCapabilities",
1511 void PrintPreviewHandler::PrintToPrivetPrinter(
1512 const std::string
& device_name
,
1513 const std::string
& ticket
,
1514 const gfx::Size
& page_size
) {
1517 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient
,
1518 base::Unretained(this), ticket
, page_size
));
1521 bool PrintPreviewHandler::CreatePrivetHTTP(
1522 const std::string
& name
,
1523 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback
&
1525 const local_discovery::DeviceDescription
* device_description
=
1526 printer_lister_
->GetDeviceDescription(name
);
1528 if (!device_description
) {
1529 SendPrivetCapabilitiesError(name
);
1533 privet_http_factory_
=
1534 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1535 service_discovery_client_
,
1536 Profile::FromWebUI(web_ui())->GetRequestContext());
1537 privet_http_resolution_
= privet_http_factory_
->CreatePrivetHTTP(
1539 device_description
->address
,
1541 privet_http_resolution_
->Start();
1546 void PrintPreviewHandler::OnPrivetPrintingDone(
1547 const local_discovery::PrivetLocalPrintOperation
* print_operation
) {
1548 ClosePreviewDialog();
1551 void PrintPreviewHandler::OnPrivetPrintingError(
1552 const local_discovery::PrivetLocalPrintOperation
* print_operation
,
1554 base::FundamentalValue
http_code_value(http_code
);
1555 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
1558 void PrintPreviewHandler::FillPrinterDescription(
1559 const std::string
& name
,
1560 const local_discovery::DeviceDescription
& description
,
1561 bool has_local_printing
,
1562 base::DictionaryValue
* printer_value
) {
1563 printer_value
->SetString("serviceName", name
);
1564 printer_value
->SetString("name", description
.name
);
1565 printer_value
->SetBoolean("hasLocalPrinting", has_local_printing
);
1566 printer_value
->SetBoolean(
1568 description
.id
.empty());
1569 printer_value
->SetString("cloudID", description
.id
);