Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: chrome/browser/ui/webui/print_preview_handler.cc

Issue 9114062: Move chrome/browser/ui/webui/print_preview* to chrome/browser/ui/webui/print_preview/ (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/print_preview_handler.h"
6
7 #include <ctype.h>
8
9 #include <string>
10 #include <vector>
11
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.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/memory/ref_counted.h"
19 #include "base/metrics/histogram.h"
20 #include "base/path_service.h"
21 #include "base/threading/thread.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "base/utf_string_conversions.h"
24 #include "base/values.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/platform_util.h"
27 #include "chrome/browser/prefs/pref_service.h"
28 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
29 #include "chrome/browser/printing/print_dialog_cloud.h"
30 #include "chrome/browser/printing/print_job_manager.h"
31 #include "chrome/browser/printing/print_preview_tab_controller.h"
32 #include "chrome/browser/printing/print_system_task_proxy.h"
33 #include "chrome/browser/printing/print_view_manager.h"
34 #include "chrome/browser/printing/printer_manager_dialog.h"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/browser/ui/browser_list.h"
37 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
38 #include "chrome/browser/ui/webui/cloud_print_signin_dialog.h"
39 #include "chrome/browser/ui/webui/print_preview_ui.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/pref_names.h"
42 #include "chrome/common/print_messages.h"
43 #include "content/browser/renderer_host/render_view_host.h"
44 #include "content/browser/renderer_host/render_view_host_delegate.h"
45 #include "content/browser/webui/web_ui.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/navigation_controller.h"
48 #include "content/public/browser/navigation_entry.h"
49 #include "content/public/browser/web_contents.h"
50 #include "printing/backend/print_backend.h"
51 #include "printing/metafile.h"
52 #include "printing/metafile_impl.h"
53 #include "printing/page_range.h"
54 #include "printing/page_size_margins.h"
55 #include "printing/print_settings.h"
56 #include "unicode/ulocdata.h"
57
58 #if !defined(OS_MACOSX)
59 #include "base/command_line.h"
60 #include "chrome/common/chrome_switches.h"
61 #endif
62
63 using content::BrowserThread;
64 using content::NavigationEntry;
65 using content::OpenURLParams;
66 using content::Referrer;
67 using content::WebContents;
68 using printing::Metafile;
69
70 namespace {
71
72 enum UserActionBuckets {
73 PRINT_TO_PRINTER,
74 PRINT_TO_PDF,
75 CANCEL,
76 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
77 PREVIEW_FAILED,
78 PREVIEW_STARTED,
79 INITIATOR_TAB_CRASHED, // UNUSED
80 INITIATOR_TAB_CLOSED,
81 PRINT_WITH_CLOUD_PRINT,
82 USERACTION_BUCKET_BOUNDARY
83 };
84
85 enum PrintSettingsBuckets {
86 LANDSCAPE,
87 PORTRAIT,
88 COLOR,
89 BLACK_AND_WHITE,
90 COLLATE,
91 SIMPLEX,
92 DUPLEX,
93 PRINT_SETTINGS_BUCKET_BOUNDARY
94 };
95
96 void ReportUserActionHistogram(enum UserActionBuckets event) {
97 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
98 USERACTION_BUCKET_BOUNDARY);
99 }
100
101 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
102 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
103 PRINT_SETTINGS_BUCKET_BOUNDARY);
104 }
105
106 // Name of a dictionary fielad holdong cloud print related data;
107 const char kCloudPrintData[] = "cloudPrintData";
108 // Name of a dictionary field holding the initiator tab title.
109 const char kInitiatorTabTitle[] = "initiatorTabTitle";
110 // Name of a dictionary field holding the measurement system according to the
111 // locale.
112 const char kMeasurementSystem[] = "measurementSystem";
113 // Name of a dictionary field holding the number format according to the locale.
114 const char kNumberFormat[] = "numberFormat";
115 // Name of a dictionary field specifying whether to print automatically in
116 // kiosk mode. See http://crbug.com/31395.
117 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
118
119
120 // Get the print job settings dictionary from |args|. The caller takes
121 // ownership of the returned DictionaryValue. Returns NULL on failure.
122 DictionaryValue* GetSettingsDictionary(const ListValue* args) {
123 std::string json_str;
124 if (!args->GetString(0, &json_str)) {
125 NOTREACHED() << "Could not read JSON argument";
126 return NULL;
127 }
128 if (json_str.empty()) {
129 NOTREACHED() << "Empty print job settings";
130 return NULL;
131 }
132 scoped_ptr<DictionaryValue> settings(static_cast<DictionaryValue*>(
133 base::JSONReader::Read(json_str, false)));
134 if (!settings.get() || !settings->IsType(Value::TYPE_DICTIONARY)) {
135 NOTREACHED() << "Print job settings must be a dictionary.";
136 return NULL;
137 }
138
139 if (settings->empty()) {
140 NOTREACHED() << "Print job settings dictionary is empty";
141 return NULL;
142 }
143
144 return settings.release();
145 }
146
147 int GetPageCountFromSettingsDictionary(const DictionaryValue& settings) {
148 int count = 0;
149 ListValue* page_range_array;
150 if (settings.GetList(printing::kSettingPageRange, &page_range_array)) {
151 for (size_t index = 0; index < page_range_array->GetSize(); ++index) {
152 DictionaryValue* dict;
153 if (!page_range_array->GetDictionary(index, &dict))
154 continue;
155
156 printing::PageRange range;
157 if (!dict->GetInteger(printing::kSettingPageRangeFrom, &range.from) ||
158 !dict->GetInteger(printing::kSettingPageRangeTo, &range.to)) {
159 continue;
160 }
161 count += (range.to - range.from) + 1;
162 }
163 }
164 return count;
165 }
166
167 // Track the popularity of print settings and report the stats.
168 void ReportPrintSettingsStats(const DictionaryValue& settings) {
169 bool landscape;
170 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
171 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
172
173 bool collate;
174 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
175 ReportPrintSettingHistogram(COLLATE);
176
177 int duplex_mode;
178 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
179 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
180
181 int color_mode;
182 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
183 ReportPrintSettingHistogram(
184 printing::isColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
185 }
186 }
187
188 // Callback that stores a PDF file on disk.
189 void PrintToPdfCallback(Metafile* metafile, const FilePath& path) {
190 metafile->SaveTo(path);
191 // |metafile| must be deleted on the UI thread.
192 BrowserThread::PostTask(
193 BrowserThread::UI, FROM_HERE,
194 base::Bind(&base::DeletePointer<Metafile>, metafile));
195 }
196
197 } // namespace
198
199 // static
200 FilePath* PrintPreviewHandler::last_saved_path_ = NULL;
201 std::string* PrintPreviewHandler::last_used_printer_cloud_print_data_ = NULL;
202 std::string* PrintPreviewHandler::last_used_printer_name_ = NULL;
203 printing::ColorModels PrintPreviewHandler::last_used_color_model_ =
204 printing::UNKNOWN_COLOR_MODEL;
205 printing::MarginType PrintPreviewHandler::last_used_margins_type_ =
206 printing::DEFAULT_MARGINS;
207 printing::PageSizeMargins*
208 PrintPreviewHandler::last_used_page_size_margins_ = NULL;
209
210 PrintPreviewHandler::PrintPreviewHandler()
211 : print_backend_(printing::PrintBackend::CreateInstance(NULL)),
212 regenerate_preview_request_count_(0),
213 manage_printers_dialog_request_count_(0),
214 reported_failed_preview_(false),
215 has_logged_printers_count_(false) {
216 ReportUserActionHistogram(PREVIEW_STARTED);
217 }
218
219 PrintPreviewHandler::~PrintPreviewHandler() {
220 if (select_file_dialog_.get())
221 select_file_dialog_->ListenerDestroyed();
222 }
223
224 void PrintPreviewHandler::RegisterMessages() {
225 web_ui()->RegisterMessageCallback("getPrinters",
226 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
227 base::Unretained(this)));
228 web_ui()->RegisterMessageCallback("getPreview",
229 base::Bind(&PrintPreviewHandler::HandleGetPreview,
230 base::Unretained(this)));
231 web_ui()->RegisterMessageCallback("print",
232 base::Bind(&PrintPreviewHandler::HandlePrint,
233 base::Unretained(this)));
234 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
235 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
236 base::Unretained(this)));
237 web_ui()->RegisterMessageCallback("showSystemDialog",
238 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
239 base::Unretained(this)));
240 web_ui()->RegisterMessageCallback("signIn",
241 base::Bind(&PrintPreviewHandler::HandleSignin,
242 base::Unretained(this)));
243 web_ui()->RegisterMessageCallback("manageCloudPrinters",
244 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
245 base::Unretained(this)));
246 web_ui()->RegisterMessageCallback("manageLocalPrinters",
247 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
248 base::Unretained(this)));
249 web_ui()->RegisterMessageCallback("closePrintPreviewTab",
250 base::Bind(&PrintPreviewHandler::HandleClosePreviewTab,
251 base::Unretained(this)));
252 web_ui()->RegisterMessageCallback("hidePreview",
253 base::Bind(&PrintPreviewHandler::HandleHidePreview,
254 base::Unretained(this)));
255 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
256 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
257 base::Unretained(this)));
258 web_ui()->RegisterMessageCallback("saveLastPrinter",
259 base::Bind(&PrintPreviewHandler::HandleSaveLastPrinter,
260 base::Unretained(this)));
261 web_ui()->RegisterMessageCallback("getInitialSettings",
262 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
263 base::Unretained(this)));
264 }
265
266 TabContentsWrapper* PrintPreviewHandler::preview_tab_wrapper() const {
267 return TabContentsWrapper::GetCurrentWrapperForContents(preview_tab());
268 }
269
270 WebContents* PrintPreviewHandler::preview_tab() const {
271 return web_ui()->web_contents();
272 }
273
274 void PrintPreviewHandler::HandleGetPrinters(const ListValue* /*args*/) {
275 scoped_refptr<PrintSystemTaskProxy> task =
276 new PrintSystemTaskProxy(AsWeakPtr(),
277 print_backend_.get(),
278 has_logged_printers_count_);
279 has_logged_printers_count_ = true;
280
281 BrowserThread::PostTask(
282 BrowserThread::FILE, FROM_HERE,
283 base::Bind(&PrintSystemTaskProxy::EnumeratePrinters, task.get()));
284 }
285
286 void PrintPreviewHandler::HandleGetPreview(const ListValue* args) {
287 DCHECK_EQ(3U, args->GetSize());
288 scoped_ptr<DictionaryValue> settings(GetSettingsDictionary(args));
289 if (!settings.get())
290 return;
291 int request_id = -1;
292 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
293 return;
294
295 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
296 print_preview_ui->OnPrintPreviewRequest(request_id);
297 // Add an additional key in order to identify |print_preview_ui| later on
298 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
299 // thread.
300 settings->SetString(printing::kPreviewUIAddr,
301 print_preview_ui->GetPrintPreviewUIAddress());
302
303 // Increment request count.
304 ++regenerate_preview_request_count_;
305
306 TabContentsWrapper* initiator_tab = GetInitiatorTab();
307 if (!initiator_tab) {
308 ReportUserActionHistogram(INITIATOR_TAB_CLOSED);
309 print_preview_ui->OnClosePrintPreviewTab();
310 return;
311 }
312
313 // Retrieve the page title and url and send it to the renderer process if
314 // headers and footers are to be displayed.
315 bool display_header_footer = false;
316 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
317 &display_header_footer)) {
318 NOTREACHED();
319 }
320 if (display_header_footer) {
321 settings->SetString(printing::kSettingHeaderFooterTitle,
322 initiator_tab->web_contents()->GetTitle());
323 std::string url;
324 NavigationEntry* entry =
325 initiator_tab->web_contents()->GetController().GetActiveEntry();
326 if (entry)
327 url = entry->GetVirtualURL().spec();
328 settings->SetString(printing::kSettingHeaderFooterURL, url);
329 }
330
331 bool generate_draft_data = false;
332 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
333 &generate_draft_data);
334 DCHECK(success);
335
336 if (!generate_draft_data) {
337 double draft_page_count_double = -1;
338 success = args->GetDouble(1, &draft_page_count_double);
339 DCHECK(success);
340 int draft_page_count = static_cast<int>(draft_page_count_double);
341
342 bool preview_modifiable = false;
343 success = args->GetBoolean(2, &preview_modifiable);
344 DCHECK(success);
345
346 if (draft_page_count != -1 && preview_modifiable &&
347 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
348 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
349 }
350 }
351
352 VLOG(1) << "Print preview request start";
353 RenderViewHost* rvh = initiator_tab->web_contents()->GetRenderViewHost();
354 rvh->Send(new PrintMsg_PrintPreview(rvh->routing_id(), *settings));
355 }
356
357 void PrintPreviewHandler::HandlePrint(const ListValue* args) {
358 ReportStats();
359
360 // Record the number of times the user requests to regenerate preview data
361 // before printing.
362 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
363 regenerate_preview_request_count_);
364
365 TabContentsWrapper* initiator_tab = GetInitiatorTab();
366 CHECK(initiator_tab);
367
368 RenderViewHost* init_rvh = initiator_tab->web_contents()->GetRenderViewHost();
369 init_rvh->Send(new PrintMsg_ResetScriptedPrintCount(init_rvh->routing_id()));
370
371 scoped_ptr<DictionaryValue> settings(GetSettingsDictionary(args));
372 if (!settings.get())
373 return;
374
375 // Storing last used color model.
376 int color_model;
377 if (!settings->GetInteger(printing::kSettingColor, &color_model))
378 color_model = printing::GRAY;
379 last_used_color_model_ = static_cast<printing::ColorModels>(color_model);
380
381 // Storing last used margin settings.
382 bool is_modifiable;
383 settings->GetBoolean(printing::kSettingPreviewModifiable, &is_modifiable);
384 if (is_modifiable) {
385 int margin_type;
386 if (!settings->GetInteger(printing::kSettingMarginsType, &margin_type))
387 margin_type = printing::DEFAULT_MARGINS;
388 last_used_margins_type_ = static_cast<printing::MarginType>(margin_type);
389 if (last_used_margins_type_ == printing::CUSTOM_MARGINS) {
390 if (!last_used_page_size_margins_)
391 last_used_page_size_margins_ = new printing::PageSizeMargins();
392 GetCustomMarginsFromJobSettings(*settings, last_used_page_size_margins_);
393 }
394 }
395
396 bool print_to_pdf = false;
397 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
398
399 bool open_pdf_in_preview = false;
400 #if defined(OS_MACOSX)
401 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
402 #endif
403
404 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
405
406 bool is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
407 bool is_cloud_dialog = false;
408 settings->GetBoolean(printing::kSettingCloudPrintDialog, &is_cloud_dialog);
409 if (is_cloud_printer && !open_pdf_in_preview) {
410 std::string print_ticket;
411 bool res = args->GetString(1, &print_ticket);
412 DCHECK(res);
413 SendCloudPrintJob(*settings, print_ticket);
414 } else if (print_to_pdf && !open_pdf_in_preview) {
415 HandlePrintToPdf(*settings);
416 } else if (is_cloud_dialog && !open_pdf_in_preview) {
417 HandlePrintWithCloudPrint();
418 } else {
419 ReportPrintSettingsStats(*settings);
420 ReportUserActionHistogram(PRINT_TO_PRINTER);
421 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter",
422 GetPageCountFromSettingsDictionary(*settings));
423
424 // This tries to activate the initiator tab as well, so do not clear the
425 // association with the initiator tab yet.
426 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
427 print_preview_ui->OnHidePreviewTab();
428
429 // Do this so the initiator tab can open a new print preview tab.
430 ClearInitiatorTabDetails();
431
432 // The PDF being printed contains only the pages that the user selected,
433 // so ignore the page range and print all pages.
434 settings->Remove(printing::kSettingPageRange, NULL);
435 RenderViewHost* rvh = web_ui()->web_contents()->GetRenderViewHost();
436 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->routing_id(), *settings));
437 }
438 initiator_tab->print_view_manager()->PrintPreviewDone();
439 }
440
441 void PrintPreviewHandler::HandlePrintToPdf(
442 const base::DictionaryValue& settings) {
443 if (print_to_pdf_path_.get()) {
444 // User has already selected a path, no need to show the dialog again.
445 PostPrintToPdfTask();
446 } else if (!select_file_dialog_.get() || !select_file_dialog_->IsRunning(
447 platform_util::GetTopLevel(preview_tab()->GetNativeView()))) {
448 ReportUserActionHistogram(PRINT_TO_PDF);
449 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF",
450 GetPageCountFromSettingsDictionary(settings));
451
452 // Pre-populating select file dialog with print job title.
453 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
454 string16 print_job_title_utf16 = print_preview_ui->initiator_tab_title();
455
456 #if defined(OS_WIN)
457 FilePath::StringType print_job_title(print_job_title_utf16);
458 #elif defined(OS_POSIX)
459 FilePath::StringType print_job_title = UTF16ToUTF8(print_job_title_utf16);
460 #endif
461
462 file_util::ReplaceIllegalCharactersInPath(&print_job_title, '_');
463 FilePath default_filename(print_job_title);
464 default_filename =
465 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
466
467 SelectFile(default_filename);
468 }
469 }
470
471 void PrintPreviewHandler::HandleHidePreview(const ListValue* /*args*/) {
472 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
473 print_preview_ui->OnHidePreviewTab();
474 }
475
476 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
477 const ListValue* /*args*/) {
478 TabContentsWrapper* initiator_tab = GetInitiatorTab();
479 if (initiator_tab) {
480 ClearInitiatorTabDetails();
481 } else {
482 // Initiator tab does not exists. Get the wrapper contents of current tab.
483 Browser* browser = BrowserList::GetLastActive();
484 if (browser)
485 initiator_tab = browser->GetSelectedTabContentsWrapper();
486 }
487
488 if (initiator_tab)
489 initiator_tab->print_view_manager()->PreviewPrintingRequestCancelled();
490 delete preview_tab_wrapper();
491 }
492
493 void PrintPreviewHandler::HandleSaveLastPrinter(const ListValue* args) {
494 std::string data_to_save;
495 if (args->GetString(0, &data_to_save) && !data_to_save.empty()) {
496 if (last_used_printer_name_ == NULL)
497 last_used_printer_name_ = new std::string();
498 *last_used_printer_name_ = data_to_save;
499 }
500 if (args->GetString(1, &data_to_save) && !data_to_save.empty()) {
501 if (last_used_printer_cloud_print_data_ == NULL)
502 last_used_printer_cloud_print_data_ = new std::string();
503 *last_used_printer_cloud_print_data_ = data_to_save;
504 }
505 }
506
507 void PrintPreviewHandler::HandleGetPrinterCapabilities(const ListValue* args) {
508 std::string printer_name;
509 bool ret = args->GetString(0, &printer_name);
510 if (!ret || printer_name.empty())
511 return;
512
513 scoped_refptr<PrintSystemTaskProxy> task =
514 new PrintSystemTaskProxy(AsWeakPtr(),
515 print_backend_.get(),
516 has_logged_printers_count_);
517
518 BrowserThread::PostTask(
519 BrowserThread::FILE, FROM_HERE,
520 base::Bind(&PrintSystemTaskProxy::GetPrinterCapabilities, task.get(),
521 printer_name));
522 }
523
524 void PrintPreviewHandler::HandleSignin(const ListValue* /*args*/) {
525 cloud_print_signin_dialog::CreateCloudPrintSigninDialog(preview_tab());
526 }
527
528 void PrintPreviewHandler::HandlePrintWithCloudPrint() {
529 // Record the number of times the user asks to print via cloud print
530 // instead of the print preview dialog.
531 ReportStats();
532 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
533
534 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
535 scoped_refptr<RefCountedBytes> data;
536 print_preview_ui->GetPrintPreviewDataForIndex(
537 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
538 CHECK(data.get());
539 DCHECK_GT(data->size(), 0U);
540 print_dialog_cloud::CreatePrintDialogForBytes(data,
541 string16(print_preview_ui->initiator_tab_title()),
542 string16(),
543 std::string("application/pdf"),
544 true);
545
546 // Once the cloud print dialog comes up we're no longer in a background
547 // printing situation. Close the print preview.
548 // TODO(abodenha@chromium.org) The flow should be changed as described in
549 // http://code.google.com/p/chromium/issues/detail?id=44093
550 ActivateInitiatorTabAndClosePreviewTab();
551 }
552
553 void PrintPreviewHandler::HandleManageCloudPrint(const ListValue* /*args*/) {
554 Browser* browser = BrowserList::GetLastActive();
555 browser->OpenURL(OpenURLParams(
556 CloudPrintURL(browser->profile()).GetCloudPrintServiceManageURL(),
557 Referrer(),
558 NEW_FOREGROUND_TAB,
559 content::PAGE_TRANSITION_LINK,
560 false));
561 }
562
563 void PrintPreviewHandler::HandleShowSystemDialog(const ListValue* /*args*/) {
564 ReportStats();
565 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
566
567 TabContentsWrapper* initiator_tab = GetInitiatorTab();
568 if (!initiator_tab)
569 return;
570
571 printing::PrintViewManager* manager = initiator_tab->print_view_manager();
572 manager->set_observer(this);
573 manager->PrintForSystemDialogNow();
574
575 // Cancel the pending preview request if exists.
576 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
577 print_preview_ui->OnCancelPendingPreviewRequest();
578 }
579
580 void PrintPreviewHandler::HandleManagePrinters(const ListValue* /*args*/) {
581 ++manage_printers_dialog_request_count_;
582 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
583 }
584
585 void PrintPreviewHandler::HandleClosePreviewTab(const ListValue* /*args*/) {
586 ReportStats();
587 ReportUserActionHistogram(CANCEL);
588
589 // Record the number of times the user requests to regenerate preview data
590 // before cancelling.
591 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
592 regenerate_preview_request_count_);
593 }
594
595 void PrintPreviewHandler::ReportStats() {
596 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
597 manage_printers_dialog_request_count_);
598 }
599
600 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
601 base::DictionaryValue* settings) {
602
603 // Getting the measurement system based on the locale.
604 UErrorCode errorCode = U_ZERO_ERROR;
605 const char* locale = g_browser_process->GetApplicationLocale().c_str();
606 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
607 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
608 system = UMS_SI;
609
610 // Getting the number formatting based on the locale and writing to
611 // dictionary.
612 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
613 settings->SetInteger(kMeasurementSystem, system);
614 }
615
616 void PrintPreviewHandler::GetLastUsedMarginSettings(
617 base::DictionaryValue* custom_margins) {
618 custom_margins->SetInteger(printing::kSettingMarginsType,
619 PrintPreviewHandler::last_used_margins_type_);
620 if (last_used_page_size_margins_) {
621 custom_margins->SetDouble(printing::kSettingMarginTop,
622 last_used_page_size_margins_->margin_top);
623 custom_margins->SetDouble(printing::kSettingMarginBottom,
624 last_used_page_size_margins_->margin_bottom);
625 custom_margins->SetDouble(printing::kSettingMarginLeft,
626 last_used_page_size_margins_->margin_left);
627 custom_margins->SetDouble(printing::kSettingMarginRight,
628 last_used_page_size_margins_->margin_right);
629 }
630 }
631
632 void PrintPreviewHandler::HandleGetInitialSettings(const ListValue* /*args*/) {
633 scoped_refptr<PrintSystemTaskProxy> task =
634 new PrintSystemTaskProxy(AsWeakPtr(),
635 print_backend_.get(),
636 has_logged_printers_count_);
637 BrowserThread::PostTask(
638 BrowserThread::FILE, FROM_HERE,
639 base::Bind(&PrintSystemTaskProxy::GetDefaultPrinter, task.get()));
640 }
641
642 void PrintPreviewHandler::SendInitialSettings(
643 const std::string& default_printer,
644 const std::string& cloud_print_data) {
645 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
646
647 base::DictionaryValue initial_settings;
648 initial_settings.SetString(kInitiatorTabTitle,
649 print_preview_ui->initiator_tab_title());
650 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
651 print_preview_ui->source_is_modifiable());
652 initial_settings.SetString(printing::kSettingPrinterName,
653 default_printer);
654 initial_settings.SetString(kCloudPrintData, cloud_print_data);
655
656 #if defined(OS_MACOSX)
657 bool kiosk_mode = false; // No kiosk mode on Mac yet.
658 #else
659 CommandLine* cmdline = CommandLine::ForCurrentProcess();
660 bool kiosk_mode = (cmdline->HasSwitch(switches::kKioskMode) &&
661 cmdline->HasSwitch(switches::kKioskModePrinting));
662 #endif
663 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode, kiosk_mode);
664
665 if (print_preview_ui->source_is_modifiable()) {
666 GetLastUsedMarginSettings(&initial_settings);
667 GetNumberFormatAndMeasurementSystem(&initial_settings);
668 }
669 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
670 }
671
672 void PrintPreviewHandler::ActivateInitiatorTabAndClosePreviewTab() {
673 TabContentsWrapper* initiator_tab = GetInitiatorTab();
674 if (initiator_tab)
675 initiator_tab->web_contents()->GetRenderViewHost()->delegate()->Activate();
676 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
677 print_preview_ui->OnClosePrintPreviewTab();
678 }
679
680 void PrintPreviewHandler::SendPrinterCapabilities(
681 const DictionaryValue& settings_info) {
682 VLOG(1) << "Get printer capabilities finished";
683 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
684 settings_info);
685 }
686
687 void PrintPreviewHandler::SetupPrinterList(const ListValue& printers) {
688 SendCloudPrintEnabled();
689 web_ui()->CallJavascriptFunction("setPrinters", printers);
690 }
691
692 void PrintPreviewHandler::SendCloudPrintEnabled() {
693 Profile* profile = BrowserList::GetLastActive()->profile();
694 PrefService* prefs = profile->GetPrefs();
695 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
696 GURL gcp_url(CloudPrintURL(profile).GetCloudPrintServiceURL());
697 base::StringValue gcp_url_value(gcp_url.spec());
698 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value);
699 }
700 }
701
702 void PrintPreviewHandler::SendCloudPrintJob(const DictionaryValue& settings,
703 std::string print_ticket) {
704 scoped_refptr<RefCountedBytes> data;
705 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
706 print_preview_ui->GetPrintPreviewDataForIndex(
707 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
708 CHECK(data.get());
709 DCHECK_GT(data->size(), 0U);
710
711 string16 print_job_title_utf16 =
712 preview_tab_wrapper()->print_view_manager()->RenderSourceName();
713 std::string print_job_title = UTF16ToUTF8(print_job_title_utf16);
714 std::string printer_id;
715 settings.GetString(printing::kSettingCloudPrintId, &printer_id);
716 // BASE64 encode the job data.
717 std::string raw_data(reinterpret_cast<const char*>(data->front()),
718 data->size());
719 std::string base64_data;
720 if (!base::Base64Encode(raw_data, &base64_data)) {
721 NOTREACHED() << "Base64 encoding PDF data.";
722 }
723
724 const char boundary[] = "----CloudPrintFormBoundaryjc9wuprokl8i";
725 const char prolog[] = "--%s\r\n"
726 "Content-Disposition: form-data; name=\"capabilities\"\r\n\r\n%s\r\n"
727 "--%s\r\n"
728 "Content-Disposition: form-data; name=\"contentType\"\r\n\r\ndataUrl\r\n"
729 "--%s\r\n"
730 "Content-Disposition: form-data; name=\"title\"\r\n\r\n%s\r\n"
731 "--%s\r\n"
732 "Content-Disposition: form-data; name=\"printerid\"\r\n\r\n%s\r\n"
733 "--%s\r\n"
734 "Content-Disposition: form-data; name=\"content\"\r\n\r\n"
735 "data:application/pdf;base64,%s\r\n"
736 "--%s\r\n";
737
738 // TODO(abodenha@chromium.org) This implies a large copy operation.
739 // Profile this and optimize if necessary.
740 std::string final_data;
741 base::SStringPrintf(&final_data,
742 prolog,
743 boundary,
744 print_ticket.c_str(),
745 boundary,
746 boundary,
747 print_job_title.c_str(),
748 boundary,
749 printer_id.c_str(),
750 boundary,
751 base64_data.c_str(),
752 boundary);
753
754 StringValue data_value(final_data);
755
756 web_ui()->CallJavascriptFunction("printToCloud", data_value);
757 }
758
759 TabContentsWrapper* PrintPreviewHandler::GetInitiatorTab() const {
760 printing::PrintPreviewTabController* tab_controller =
761 printing::PrintPreviewTabController::GetInstance();
762 if (!tab_controller)
763 return NULL;
764 return tab_controller->GetInitiatorTab(preview_tab_wrapper());
765 }
766
767 void PrintPreviewHandler::OnPrintDialogShown() {
768 ActivateInitiatorTabAndClosePreviewTab();
769 }
770
771 void PrintPreviewHandler::SelectFile(const FilePath& default_filename) {
772 SelectFileDialog::FileTypeInfo file_type_info;
773 file_type_info.extensions.resize(1);
774 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
775
776 // Initializing last_saved_path_ if it is not already initialized.
777 if (!last_saved_path_) {
778 last_saved_path_ = new FilePath();
779 // Allowing IO operation temporarily. It is ok to do so here because
780 // the select file dialog performs IO anyway in order to display the
781 // folders and also it is modal.
782 base::ThreadRestrictions::ScopedAllowIO allow_io;
783 PathService::Get(chrome::DIR_USER_DOCUMENTS, last_saved_path_);
784 }
785
786 if (!select_file_dialog_.get())
787 select_file_dialog_ = SelectFileDialog::Create(this);
788
789 select_file_dialog_->SelectFile(
790 SelectFileDialog::SELECT_SAVEAS_FILE,
791 string16(),
792 last_saved_path_->Append(default_filename),
793 &file_type_info,
794 0,
795 FILE_PATH_LITERAL(""),
796 preview_tab(),
797 platform_util::GetTopLevel(preview_tab()->GetNativeView()),
798 NULL);
799 }
800
801 void PrintPreviewHandler::OnTabDestroyed() {
802 TabContentsWrapper* initiator_tab = GetInitiatorTab();
803 if (!initiator_tab)
804 return;
805
806 initiator_tab->print_view_manager()->set_observer(NULL);
807 }
808
809 void PrintPreviewHandler::OnPrintPreviewFailed() {
810 if (reported_failed_preview_)
811 return;
812 reported_failed_preview_ = true;
813 ReportUserActionHistogram(PREVIEW_FAILED);
814 }
815
816 void PrintPreviewHandler::ShowSystemDialog() {
817 HandleShowSystemDialog(NULL);
818 }
819
820 void PrintPreviewHandler::FileSelected(const FilePath& path,
821 int index, void* params) {
822 // Updating last_saved_path_ to the newly selected folder.
823 *last_saved_path_ = path.DirName();
824
825 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
826 print_preview_ui->CallJavascriptFunction("fileSelectionCompleted");
827 scoped_refptr<RefCountedBytes> data;
828 print_preview_ui->GetPrintPreviewDataForIndex(
829 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
830 print_to_pdf_path_.reset(new FilePath(path));
831 if (data.get())
832 PostPrintToPdfTask();
833 }
834
835 void PrintPreviewHandler::PostPrintToPdfTask() {
836 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
837 scoped_refptr<RefCountedBytes> data;
838 print_preview_ui->GetPrintPreviewDataForIndex(
839 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
840 DCHECK(data.get());
841 printing::PreviewMetafile* metafile = new printing::PreviewMetafile;
842 metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
843 // PrintToPdfCallback takes ownership of |metafile|.
844 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
845 base::Bind(&PrintToPdfCallback, metafile,
846 *print_to_pdf_path_));
847 print_to_pdf_path_.reset();
848 ActivateInitiatorTabAndClosePreviewTab();
849 }
850
851 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
852 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(web_ui());
853 print_preview_ui->OnFileSelectionCancelled();
854 }
855
856 void PrintPreviewHandler::ClearInitiatorTabDetails() {
857 TabContentsWrapper* initiator_tab = GetInitiatorTab();
858 if (!initiator_tab)
859 return;
860
861 // We no longer require the initiator tab details. Remove those details
862 // associated with the preview tab to allow the initiator tab to create
863 // another preview tab.
864 printing::PrintPreviewTabController* tab_controller =
865 printing::PrintPreviewTabController::GetInstance();
866 if (tab_controller)
867 tab_controller->EraseInitiatorTabInfo(preview_tab_wrapper());
868 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/webui/print_preview_handler.h ('k') | chrome/browser/ui/webui/print_preview_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698