michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: #include michael@0: #else michael@0: #include michael@0: #endif michael@0: #include michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "mozcontainer.h" michael@0: #include "nsIPrintSettings.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsPrintDialogGTK.h" michael@0: #include "nsPrintSettingsGTK.h" michael@0: #include "nsString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIFile.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIStringBundle.h" michael@0: #include "nsIPrintSettingsService.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIBaseWindow.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: #include "nsIDocShell.h" michael@0: #include "WidgetUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::widget; michael@0: michael@0: static const char header_footer_tags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"}; michael@0: michael@0: #define CUSTOM_VALUE_INDEX gint(ArrayLength(header_footer_tags)) michael@0: michael@0: static GtkWindow * michael@0: get_gtk_window_for_nsiwidget(nsIWidget *widget) michael@0: { michael@0: return GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET)); michael@0: } michael@0: michael@0: static void michael@0: ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data) michael@0: { michael@0: if (gtk_combo_box_get_active(changed_box) != CUSTOM_VALUE_INDEX) { michael@0: g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(gtk_combo_box_get_active(changed_box))); michael@0: return; michael@0: } michael@0: michael@0: GtkWindow* printDialog = GTK_WINDOW(user_data); michael@0: nsCOMPtr bundleSvc = michael@0: do_GetService(NS_STRINGBUNDLE_CONTRACTID); michael@0: michael@0: nsCOMPtr printBundle; michael@0: bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle)); michael@0: nsXPIDLString intlString; michael@0: michael@0: printBundle->GetStringFromName(MOZ_UTF16("headerFooterCustom"), getter_Copies(intlString)); michael@0: GtkWidget* prompt_dialog = gtk_dialog_new_with_buttons(NS_ConvertUTF16toUTF8(intlString).get(), printDialog, michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), michael@0: #else michael@0: (GtkDialogFlags)(GTK_DIALOG_MODAL), michael@0: #endif michael@0: GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, michael@0: GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, michael@0: nullptr); michael@0: gtk_dialog_set_default_response(GTK_DIALOG(prompt_dialog), GTK_RESPONSE_ACCEPT); michael@0: gtk_dialog_set_alternative_button_order(GTK_DIALOG(prompt_dialog), michael@0: GTK_RESPONSE_ACCEPT, michael@0: GTK_RESPONSE_REJECT, michael@0: -1); michael@0: michael@0: printBundle->GetStringFromName(MOZ_UTF16("customHeaderFooterPrompt"), getter_Copies(intlString)); michael@0: GtkWidget* custom_label = gtk_label_new(NS_ConvertUTF16toUTF8(intlString).get()); michael@0: GtkWidget* custom_entry = gtk_entry_new(); michael@0: GtkWidget* question_icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG); michael@0: michael@0: // To be convenient, prefill the textbox with the existing value, if any, and select it all so they can easily michael@0: // both edit it and type in a new one. michael@0: const char* current_text = (const char*) g_object_get_data(G_OBJECT(changed_box), "custom-text"); michael@0: if (current_text) { michael@0: gtk_entry_set_text(GTK_ENTRY(custom_entry), current_text); michael@0: gtk_editable_select_region(GTK_EDITABLE(custom_entry), 0, -1); michael@0: } michael@0: gtk_entry_set_activates_default(GTK_ENTRY(custom_entry), TRUE); michael@0: michael@0: GtkWidget* custom_vbox = gtk_vbox_new(TRUE, 2); michael@0: gtk_box_pack_start(GTK_BOX(custom_vbox), custom_label, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(custom_vbox), custom_entry, FALSE, FALSE, 5); // Make entry 5px underneath label michael@0: GtkWidget* custom_hbox = gtk_hbox_new(FALSE, 2); michael@0: gtk_box_pack_start(GTK_BOX(custom_hbox), question_icon, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(custom_hbox), custom_vbox, FALSE, FALSE, 10); // Make question icon 10px away from content michael@0: gtk_container_set_border_width(GTK_CONTAINER(custom_hbox), 2); michael@0: gtk_widget_show_all(custom_hbox); michael@0: michael@0: gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(prompt_dialog))), michael@0: custom_hbox, FALSE, FALSE, 0); michael@0: gint diag_response = gtk_dialog_run(GTK_DIALOG(prompt_dialog)); michael@0: michael@0: if (diag_response == GTK_RESPONSE_ACCEPT) { michael@0: const gchar* response_text = gtk_entry_get_text(GTK_ENTRY(custom_entry)); michael@0: g_object_set_data_full(G_OBJECT(changed_box), "custom-text", strdup(response_text), (GDestroyNotify) free); michael@0: g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX)); michael@0: } else { michael@0: // Go back to the previous index michael@0: gint previous_active = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(changed_box), "previous-active")); michael@0: gtk_combo_box_set_active(changed_box, previous_active); michael@0: } michael@0: michael@0: gtk_widget_destroy(prompt_dialog); michael@0: } michael@0: michael@0: class nsPrintDialogWidgetGTK { michael@0: public: michael@0: nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aPrintSettings); michael@0: ~nsPrintDialogWidgetGTK() { gtk_widget_destroy(dialog); } michael@0: NS_ConvertUTF16toUTF8 GetUTF8FromBundle(const char* aKey); michael@0: const gint Run(); michael@0: michael@0: nsresult ImportSettings(nsIPrintSettings *aNSSettings); michael@0: nsresult ExportSettings(nsIPrintSettings *aNSSettings); michael@0: michael@0: private: michael@0: GtkWidget* dialog; michael@0: GtkWidget* radio_as_laid_out; michael@0: GtkWidget* radio_selected_frame; michael@0: GtkWidget* radio_separate_frames; michael@0: GtkWidget* shrink_to_fit_toggle; michael@0: GtkWidget* print_bg_colors_toggle; michael@0: GtkWidget* print_bg_images_toggle; michael@0: GtkWidget* selection_only_toggle; michael@0: GtkWidget* header_dropdown[3]; // {left, center, right} michael@0: GtkWidget* footer_dropdown[3]; michael@0: michael@0: nsCOMPtr printBundle; michael@0: michael@0: bool useNativeSelection; michael@0: michael@0: GtkWidget* ConstructHeaderFooterDropdown(const char16_t *currentString); michael@0: const char* OptionWidgetToString(GtkWidget *dropdown); michael@0: michael@0: /* Code to copy between GTK and NS print settings structures. michael@0: * In the following, michael@0: * "Import" means to copy from NS to GTK michael@0: * "Export" means to copy from GTK to NS michael@0: */ michael@0: void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings); michael@0: void ExportHeaderFooter(nsIPrintSettings *aNS); michael@0: }; michael@0: michael@0: nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aSettings) michael@0: { michael@0: nsCOMPtr widget = WidgetUtils::DOMWindowToWidget(aParent); michael@0: NS_ASSERTION(widget, "Need a widget for dialog to be modal."); michael@0: GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget); michael@0: NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal."); michael@0: michael@0: nsCOMPtr bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); michael@0: bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle)); michael@0: michael@0: dialog = gtk_print_unix_dialog_new(GetUTF8FromBundle("printTitleGTK").get(), gtkParent); michael@0: michael@0: gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog), michael@0: GtkPrintCapabilities( michael@0: GTK_PRINT_CAPABILITY_PAGE_SET michael@0: | GTK_PRINT_CAPABILITY_COPIES michael@0: | GTK_PRINT_CAPABILITY_COLLATE michael@0: | GTK_PRINT_CAPABILITY_REVERSE michael@0: | GTK_PRINT_CAPABILITY_SCALE michael@0: | GTK_PRINT_CAPABILITY_GENERATE_PDF michael@0: | GTK_PRINT_CAPABILITY_GENERATE_PS michael@0: ) michael@0: ); michael@0: michael@0: // The vast majority of magic numbers in this widget construction are padding. e.g. for michael@0: // the set_border_width below, 12px matches that of just about every other window. michael@0: GtkWidget* custom_options_tab = gtk_vbox_new(FALSE, 0); michael@0: gtk_container_set_border_width(GTK_CONTAINER(custom_options_tab), 12); michael@0: GtkWidget* tab_label = gtk_label_new(GetUTF8FromBundle("optionsTabLabelGTK").get()); michael@0: michael@0: int16_t frameUIFlag; michael@0: aSettings->GetHowToEnableFrameUI(&frameUIFlag); michael@0: radio_as_laid_out = gtk_radio_button_new_with_mnemonic(nullptr, GetUTF8FromBundle("asLaidOut").get()); michael@0: if (frameUIFlag == nsIPrintSettings::kFrameEnableNone) michael@0: gtk_widget_set_sensitive(radio_as_laid_out, FALSE); michael@0: michael@0: radio_selected_frame = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out), michael@0: GetUTF8FromBundle("selectedFrame").get()); michael@0: if (frameUIFlag == nsIPrintSettings::kFrameEnableNone || michael@0: frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach) michael@0: gtk_widget_set_sensitive(radio_selected_frame, FALSE); michael@0: michael@0: radio_separate_frames = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out), michael@0: GetUTF8FromBundle("separateFrames").get()); michael@0: if (frameUIFlag == nsIPrintSettings::kFrameEnableNone) michael@0: gtk_widget_set_sensitive(radio_separate_frames, FALSE); michael@0: michael@0: // "Print Frames" options label, bold and center-aligned michael@0: GtkWidget* print_frames_label = gtk_label_new(nullptr); michael@0: char* pangoMarkup = g_markup_printf_escaped("%s", GetUTF8FromBundle("printFramesTitleGTK").get()); michael@0: gtk_label_set_markup(GTK_LABEL(print_frames_label), pangoMarkup); michael@0: g_free(pangoMarkup); michael@0: gtk_misc_set_alignment(GTK_MISC(print_frames_label), 0, 0); michael@0: michael@0: // Align the radio buttons slightly so they appear to fall under the aforementioned label as per the GNOME HIG michael@0: GtkWidget* frames_radio_container = gtk_alignment_new(0, 0, 0, 0); michael@0: gtk_alignment_set_padding(GTK_ALIGNMENT(frames_radio_container), 8, 0, 12, 0); michael@0: michael@0: // Radio buttons for the print frames options michael@0: GtkWidget* frames_radio_list = gtk_vbox_new(TRUE, 2); michael@0: gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_as_laid_out, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_selected_frame, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_separate_frames, FALSE, FALSE, 0); michael@0: gtk_container_add(GTK_CONTAINER(frames_radio_container), frames_radio_list); michael@0: michael@0: // Check buttons for shrink-to-fit and print selection michael@0: GtkWidget* check_buttons_container = gtk_vbox_new(TRUE, 2); michael@0: shrink_to_fit_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("shrinkToFit").get()); michael@0: gtk_box_pack_start(GTK_BOX(check_buttons_container), shrink_to_fit_toggle, FALSE, FALSE, 0); michael@0: michael@0: // GTK+2.18 and above allow us to add a "Selection" option to the main settings screen, michael@0: // rather than adding an option on a custom tab like we must do on older versions. michael@0: bool canSelectText; michael@0: aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &canSelectText); michael@0: if (gtk_major_version > 2 || michael@0: (gtk_major_version == 2 && gtk_minor_version >= 18)) { michael@0: useNativeSelection = true; michael@0: g_object_set(dialog, michael@0: "support-selection", TRUE, michael@0: "has-selection", canSelectText, michael@0: "embed-page-setup", TRUE, michael@0: nullptr); michael@0: } else { michael@0: useNativeSelection = false; michael@0: selection_only_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("selectionOnly").get()); michael@0: gtk_widget_set_sensitive(selection_only_toggle, canSelectText); michael@0: gtk_box_pack_start(GTK_BOX(check_buttons_container), selection_only_toggle, FALSE, FALSE, 0); michael@0: } michael@0: michael@0: // Check buttons for printing background michael@0: GtkWidget* appearance_buttons_container = gtk_vbox_new(TRUE, 2); michael@0: print_bg_colors_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGColors").get()); michael@0: print_bg_images_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGImages").get()); michael@0: gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_colors_toggle, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_images_toggle, FALSE, FALSE, 0); michael@0: michael@0: // "Appearance" options label, bold and center-aligned michael@0: GtkWidget* appearance_label = gtk_label_new(nullptr); michael@0: pangoMarkup = g_markup_printf_escaped("%s", GetUTF8FromBundle("printBGOptions").get()); michael@0: gtk_label_set_markup(GTK_LABEL(appearance_label), pangoMarkup); michael@0: g_free(pangoMarkup); michael@0: gtk_misc_set_alignment(GTK_MISC(appearance_label), 0, 0); michael@0: michael@0: GtkWidget* appearance_container = gtk_alignment_new(0, 0, 0, 0); michael@0: gtk_alignment_set_padding(GTK_ALIGNMENT(appearance_container), 8, 0, 12, 0); michael@0: gtk_container_add(GTK_CONTAINER(appearance_container), appearance_buttons_container); michael@0: michael@0: GtkWidget* appearance_vertical_squasher = gtk_vbox_new(FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_label, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_container, FALSE, FALSE, 0); michael@0: michael@0: // "Header & Footer" options label, bold and center-aligned michael@0: GtkWidget* header_footer_label = gtk_label_new(nullptr); michael@0: pangoMarkup = g_markup_printf_escaped("%s", GetUTF8FromBundle("headerFooter").get()); michael@0: gtk_label_set_markup(GTK_LABEL(header_footer_label), pangoMarkup); michael@0: g_free(pangoMarkup); michael@0: gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0); michael@0: michael@0: GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0); michael@0: gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0); michael@0: michael@0: michael@0: // --- Table for making the header and footer options --- michael@0: GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table michael@0: nsXPIDLString header_footer_str[3]; michael@0: michael@0: aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0])); michael@0: aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1])); michael@0: aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2])); michael@0: michael@0: for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) { michael@0: header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get()); michael@0: // Those 4 magic numbers in the middle provide the position in the table. michael@0: // The last two numbers mean 2 px padding on every side. michael@0: gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1), michael@0: 0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2); michael@0: } michael@0: michael@0: const char labelKeys[][7] = {"left", "center", "right"}; michael@0: for (unsigned int i = 0; i < ArrayLength(labelKeys); i++) { michael@0: gtk_table_attach(GTK_TABLE(header_footer_table), michael@0: gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()), michael@0: i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2); michael@0: } michael@0: michael@0: aSettings->GetFooterStrLeft(getter_Copies(header_footer_str[0])); michael@0: aSettings->GetFooterStrCenter(getter_Copies(header_footer_str[1])); michael@0: aSettings->GetFooterStrRight(getter_Copies(header_footer_str[2])); michael@0: michael@0: for (unsigned int i = 0; i < ArrayLength(footer_dropdown); i++) { michael@0: footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get()); michael@0: gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1), michael@0: 2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2); michael@0: } michael@0: // --- michael@0: michael@0: gtk_container_add(GTK_CONTAINER(header_footer_container), header_footer_table); michael@0: michael@0: GtkWidget* header_footer_vertical_squasher = gtk_vbox_new(FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_label, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_container, FALSE, FALSE, 0); michael@0: michael@0: // Construction of everything michael@0: gtk_box_pack_start(GTK_BOX(custom_options_tab), print_frames_label, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(custom_options_tab), frames_radio_container, FALSE, FALSE, 0); michael@0: gtk_box_pack_start(GTK_BOX(custom_options_tab), check_buttons_container, FALSE, FALSE, 10); // 10px padding michael@0: gtk_box_pack_start(GTK_BOX(custom_options_tab), appearance_vertical_squasher, FALSE, FALSE, 10); michael@0: gtk_box_pack_start(GTK_BOX(custom_options_tab), header_footer_vertical_squasher, FALSE, FALSE, 0); michael@0: michael@0: gtk_print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(dialog), custom_options_tab, tab_label); michael@0: gtk_widget_show_all(custom_options_tab); michael@0: } michael@0: michael@0: NS_ConvertUTF16toUTF8 michael@0: nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey) michael@0: { michael@0: nsXPIDLString intlString; michael@0: printBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aKey).get(), getter_Copies(intlString)); michael@0: return NS_ConvertUTF16toUTF8(intlString); // Return the actual object so we don't lose reference michael@0: } michael@0: michael@0: const char* michael@0: nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown) michael@0: { michael@0: gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(dropdown)); michael@0: michael@0: NS_ASSERTION(index <= CUSTOM_VALUE_INDEX, "Index of dropdown is higher than expected!"); michael@0: michael@0: if (index == CUSTOM_VALUE_INDEX) michael@0: return (const char*) g_object_get_data(G_OBJECT(dropdown), "custom-text"); michael@0: else michael@0: return header_footer_tags[index]; michael@0: } michael@0: michael@0: const gint michael@0: nsPrintDialogWidgetGTK::Run() michael@0: { michael@0: const gint response = gtk_dialog_run(GTK_DIALOG(dialog)); michael@0: gtk_widget_hide(dialog); michael@0: return response; michael@0: } michael@0: michael@0: void michael@0: nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings) michael@0: { michael@0: if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_as_laid_out))) michael@0: aNS->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); michael@0: else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_selected_frame))) michael@0: aNS->SetPrintFrameType(nsIPrintSettings::kSelectedFrame); michael@0: else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_separate_frames))) michael@0: aNS->SetPrintFrameType(nsIPrintSettings::kEachFrameSep); michael@0: else michael@0: aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames); michael@0: } michael@0: michael@0: void michael@0: nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS) michael@0: { michael@0: const char* header_footer_str; michael@0: header_footer_str = OptionWidgetToString(header_dropdown[0]); michael@0: aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: michael@0: header_footer_str = OptionWidgetToString(header_dropdown[1]); michael@0: aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: michael@0: header_footer_str = OptionWidgetToString(header_dropdown[2]); michael@0: aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: michael@0: header_footer_str = OptionWidgetToString(footer_dropdown[0]); michael@0: aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: michael@0: header_footer_str = OptionWidgetToString(footer_dropdown[1]); michael@0: aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: michael@0: header_footer_str = OptionWidgetToString(footer_dropdown[2]); michael@0: aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get()); michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings) michael@0: { michael@0: NS_PRECONDITION(aNSSettings, "aSettings must not be null"); michael@0: NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr aNSSettingsGTK(do_QueryInterface(aNSSettings)); michael@0: if (!aNSSettingsGTK) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: GtkPrintSettings* settings = aNSSettingsGTK->GetGtkPrintSettings(); michael@0: GtkPageSetup* setup = aNSSettingsGTK->GetGtkPageSetup(); michael@0: michael@0: bool geckoBool; michael@0: aNSSettings->GetShrinkToFit(&geckoBool); michael@0: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle), geckoBool); michael@0: michael@0: aNSSettings->GetPrintBGColors(&geckoBool); michael@0: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle), geckoBool); michael@0: michael@0: aNSSettings->GetPrintBGImages(&geckoBool); michael@0: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle), geckoBool); michael@0: michael@0: gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog), settings); michael@0: gtk_print_unix_dialog_set_page_setup(GTK_PRINT_UNIX_DIALOG(dialog), setup); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings) michael@0: { michael@0: NS_PRECONDITION(aNSSettings, "aSettings must not be null"); michael@0: NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE); michael@0: michael@0: GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog)); michael@0: GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog)); michael@0: GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dialog)); michael@0: if (settings && setup && printer) { michael@0: ExportFramePrinting(aNSSettings, settings); michael@0: ExportHeaderFooter(aNSSettings); michael@0: michael@0: aNSSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatNative); michael@0: michael@0: // Print-to-file is true by default. This must be turned off or else printing won't occur! michael@0: // (We manually copy the spool file when this flag is set, because we love our embedders) michael@0: // Even if it is print-to-file in GTK's case, GTK does The Right Thing when we send the job. michael@0: aNSSettings->SetPrintToFile(false); michael@0: michael@0: aNSSettings->SetShrinkToFit(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle))); michael@0: michael@0: aNSSettings->SetPrintBGColors(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle))); michael@0: aNSSettings->SetPrintBGImages(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle))); michael@0: michael@0: // Try to save native settings in the session object michael@0: nsCOMPtr aNSSettingsGTK(do_QueryInterface(aNSSettings)); michael@0: if (aNSSettingsGTK) { michael@0: aNSSettingsGTK->SetGtkPrintSettings(settings); michael@0: aNSSettingsGTK->SetGtkPageSetup(setup); michael@0: aNSSettingsGTK->SetGtkPrinter(printer); michael@0: bool printSelectionOnly; michael@0: if (useNativeSelection) { michael@0: _GtkPrintPages pageSetting = (_GtkPrintPages)gtk_print_settings_get_print_pages(settings); michael@0: printSelectionOnly = (pageSetting == _GTK_PRINT_PAGES_SELECTION); michael@0: } else { michael@0: printSelectionOnly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selection_only_toggle)); michael@0: } michael@0: aNSSettingsGTK->SetForcePrintSelectionOnly(printSelectionOnly); michael@0: } michael@0: } michael@0: michael@0: if (settings) michael@0: g_object_unref(settings); michael@0: return NS_OK; michael@0: } michael@0: michael@0: GtkWidget* michael@0: nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const char16_t *currentString) michael@0: { michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: GtkWidget* dropdown = gtk_combo_box_new_text(); michael@0: #else michael@0: GtkWidget* dropdown = gtk_combo_box_text_new(); michael@0: #endif michael@0: const char hf_options[][22] = {"headerFooterBlank", "headerFooterTitle", michael@0: "headerFooterURL", "headerFooterDate", michael@0: "headerFooterPage", "headerFooterPageTotal", michael@0: "headerFooterCustom"}; michael@0: michael@0: for (unsigned int i = 0; i < ArrayLength(hf_options); i++) { michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: gtk_combo_box_append_text(GTK_COMBO_BOX(dropdown), GetUTF8FromBundle(hf_options[i]).get()); michael@0: #else michael@0: gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(dropdown), nullptr, michael@0: GetUTF8FromBundle(hf_options[i]).get()); michael@0: #endif michael@0: } michael@0: michael@0: bool shouldBeCustom = true; michael@0: NS_ConvertUTF16toUTF8 currentStringUTF8(currentString); michael@0: michael@0: for (unsigned int i = 0; i < ArrayLength(header_footer_tags); i++) { michael@0: if (!strcmp(currentStringUTF8.get(), header_footer_tags[i])) { michael@0: gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), i); michael@0: g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(i)); michael@0: shouldBeCustom = false; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (shouldBeCustom) { michael@0: gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), CUSTOM_VALUE_INDEX); michael@0: g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX)); michael@0: char* custom_string = strdup(currentStringUTF8.get()); michael@0: g_object_set_data_full(G_OBJECT(dropdown), "custom-text", custom_string, (GDestroyNotify) free); michael@0: } michael@0: michael@0: g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, dialog); michael@0: return dropdown; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPrintDialogServiceGTK, nsIPrintDialogService) michael@0: michael@0: nsPrintDialogServiceGTK::nsPrintDialogServiceGTK() michael@0: { michael@0: } michael@0: michael@0: nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintDialogServiceGTK::Init() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintDialogServiceGTK::Show(nsIDOMWindow *aParent, nsIPrintSettings *aSettings, michael@0: nsIWebBrowserPrint *aWebBrowserPrint) michael@0: { michael@0: NS_PRECONDITION(aParent, "aParent must not be null"); michael@0: NS_PRECONDITION(aSettings, "aSettings must not be null"); michael@0: michael@0: nsPrintDialogWidgetGTK printDialog(aParent, aSettings); michael@0: nsresult rv = printDialog.ImportSettings(aSettings); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: const gint response = printDialog.Run(); michael@0: michael@0: // Handle the result michael@0: switch (response) { michael@0: case GTK_RESPONSE_OK: // Proceed michael@0: rv = printDialog.ExportSettings(aSettings); michael@0: break; michael@0: michael@0: case GTK_RESPONSE_CANCEL: michael@0: case GTK_RESPONSE_CLOSE: michael@0: case GTK_RESPONSE_DELETE_EVENT: michael@0: case GTK_RESPONSE_NONE: michael@0: rv = NS_ERROR_ABORT; michael@0: break; michael@0: michael@0: case GTK_RESPONSE_APPLY: // Print preview michael@0: default: michael@0: NS_WARNING("Unexpected response"); michael@0: rv = NS_ERROR_ABORT; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintDialogServiceGTK::ShowPageSetup(nsIDOMWindow *aParent, michael@0: nsIPrintSettings *aNSSettings) michael@0: { michael@0: NS_PRECONDITION(aParent, "aParent must not be null"); michael@0: NS_PRECONDITION(aNSSettings, "aSettings must not be null"); michael@0: NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr widget = WidgetUtils::DOMWindowToWidget(aParent); michael@0: NS_ASSERTION(widget, "Need a widget for dialog to be modal."); michael@0: GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget); michael@0: NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal."); michael@0: michael@0: nsCOMPtr aNSSettingsGTK(do_QueryInterface(aNSSettings)); michael@0: if (!aNSSettingsGTK) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word michael@0: nsCOMPtr psService = do_GetService("@mozilla.org/gfx/printsettings-service;1"); michael@0: if (psService) { michael@0: nsXPIDLString printName; michael@0: aNSSettings->GetPrinterName(getter_Copies(printName)); michael@0: if (!printName) { michael@0: psService->GetDefaultPrinterName(getter_Copies(printName)); michael@0: aNSSettings->SetPrinterName(printName.get()); michael@0: } michael@0: psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll); michael@0: } michael@0: michael@0: GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings(); michael@0: GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup(); michael@0: michael@0: GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(gtkParent, oldPageSetup, gtkSettings); michael@0: michael@0: aNSSettingsGTK->SetGtkPageSetup(newPageSetup); michael@0: michael@0: // Now newPageSetup has a refcount of 2 (SetGtkPageSetup will addref), put it to 1 so if michael@0: // this gets replaced we don't leak. michael@0: g_object_unref(newPageSetup); michael@0: michael@0: if (psService) michael@0: psService->SavePrintSettingsToPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll); michael@0: michael@0: return NS_OK; michael@0: }