1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla GTK2 print dialog interface.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Kenneth Herron <kherron@fmailbox.com>
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Michael Ventnor <m.ventnor@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include <gtk/gtk.h>
40 : #include <gtk/gtkprintunixdialog.h>
41 : #include <stdlib.h>
42 :
43 : #include "mozilla/Util.h"
44 :
45 : #include "mozcontainer.h"
46 : #include "nsIPrintSettings.h"
47 : #include "nsIWidget.h"
48 : #include "nsPrintDialogGTK.h"
49 : #include "nsPrintSettingsGTK.h"
50 : #include "nsString.h"
51 : #include "nsReadableUtils.h"
52 : #include "nsILocalFile.h"
53 : #include "nsNetUtil.h"
54 : #include "nsIStringBundle.h"
55 : #include "nsIPrintSettingsService.h"
56 : #include "nsIDOMWindow.h"
57 : #include "nsPIDOMWindow.h"
58 : #include "nsIBaseWindow.h"
59 : #include "nsIDocShellTreeItem.h"
60 : #include "nsIDocShell.h"
61 : #include "WidgetUtils.h"
62 :
63 : using namespace mozilla;
64 : using namespace mozilla::widget;
65 :
66 : static const char header_footer_tags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
67 :
68 : #define CUSTOM_VALUE_INDEX ArrayLength(header_footer_tags)
69 :
70 : // XXXdholbert Duplicated from widget/gtk2/nsFilePicker.cpp
71 : // Needs to be unified in some generic utility class.
72 : static GtkWindow *
73 0 : get_gtk_window_for_nsiwidget(nsIWidget *widget)
74 : {
75 : // Get native GdkWindow
76 0 : GdkWindow *gdk_win = GDK_WINDOW(widget->GetNativeData(NS_NATIVE_WIDGET));
77 0 : if (!gdk_win)
78 0 : return NULL;
79 :
80 : // Get the container
81 0 : gpointer user_data = NULL;
82 0 : gdk_window_get_user_data(gdk_win, &user_data);
83 0 : if (!user_data)
84 0 : return NULL;
85 :
86 : // Make sure its really a container
87 0 : MozContainer *parent_container = MOZ_CONTAINER(user_data);
88 0 : if (!parent_container)
89 0 : return NULL;
90 :
91 : // Get its toplevel
92 0 : return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(parent_container)));
93 : }
94 :
95 : static void
96 0 : ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data)
97 : {
98 0 : if (gtk_combo_box_get_active(changed_box) != CUSTOM_VALUE_INDEX) {
99 0 : g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(gtk_combo_box_get_active(changed_box)));
100 0 : return;
101 : }
102 :
103 0 : GtkWindow* printDialog = GTK_WINDOW(user_data);
104 : nsCOMPtr<nsIStringBundleService> bundleSvc =
105 0 : do_GetService(NS_STRINGBUNDLE_CONTRACTID);
106 :
107 0 : nsCOMPtr<nsIStringBundle> printBundle;
108 0 : bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
109 0 : nsXPIDLString intlString;
110 :
111 0 : printBundle->GetStringFromName(NS_LITERAL_STRING("headerFooterCustom").get(), getter_Copies(intlString));
112 0 : GtkWidget* prompt_dialog = gtk_dialog_new_with_buttons(NS_ConvertUTF16toUTF8(intlString).get(), printDialog,
113 : (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
114 : GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
115 : GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
116 0 : NULL);
117 0 : gtk_dialog_set_default_response(GTK_DIALOG(prompt_dialog), GTK_RESPONSE_ACCEPT);
118 0 : gtk_dialog_set_alternative_button_order(GTK_DIALOG(prompt_dialog),
119 : GTK_RESPONSE_ACCEPT,
120 : GTK_RESPONSE_REJECT,
121 0 : -1);
122 :
123 0 : printBundle->GetStringFromName(NS_LITERAL_STRING("customHeaderFooterPrompt").get(), getter_Copies(intlString));
124 0 : GtkWidget* custom_label = gtk_label_new(NS_ConvertUTF16toUTF8(intlString).get());
125 0 : GtkWidget* custom_entry = gtk_entry_new();
126 0 : GtkWidget* question_icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
127 :
128 : // To be convenient, prefill the textbox with the existing value, if any, and select it all so they can easily
129 : // both edit it and type in a new one.
130 0 : const char* current_text = (const char*) g_object_get_data(G_OBJECT(changed_box), "custom-text");
131 0 : if (current_text) {
132 0 : gtk_entry_set_text(GTK_ENTRY(custom_entry), current_text);
133 0 : gtk_editable_select_region(GTK_EDITABLE(custom_entry), 0, -1);
134 : }
135 0 : gtk_entry_set_activates_default(GTK_ENTRY(custom_entry), TRUE);
136 :
137 0 : GtkWidget* custom_vbox = gtk_vbox_new(TRUE, 2);
138 0 : gtk_box_pack_start(GTK_BOX(custom_vbox), custom_label, FALSE, FALSE, 0);
139 0 : gtk_box_pack_start(GTK_BOX(custom_vbox), custom_entry, FALSE, FALSE, 5); // Make entry 5px underneath label
140 0 : GtkWidget* custom_hbox = gtk_hbox_new(FALSE, 2);
141 0 : gtk_box_pack_start(GTK_BOX(custom_hbox), question_icon, FALSE, FALSE, 0);
142 0 : gtk_box_pack_start(GTK_BOX(custom_hbox), custom_vbox, FALSE, FALSE, 10); // Make question icon 10px away from content
143 0 : gtk_container_set_border_width(GTK_CONTAINER(custom_hbox), 2);
144 0 : gtk_widget_show_all(custom_hbox);
145 :
146 0 : gtk_box_pack_start(GTK_BOX(GTK_DIALOG(prompt_dialog)->vbox), custom_hbox, FALSE, FALSE, 0);
147 0 : gint diag_response = gtk_dialog_run(GTK_DIALOG(prompt_dialog));
148 :
149 0 : if (diag_response == GTK_RESPONSE_ACCEPT) {
150 0 : const gchar* response_text = gtk_entry_get_text(GTK_ENTRY(custom_entry));
151 0 : g_object_set_data_full(G_OBJECT(changed_box), "custom-text", strdup(response_text), (GDestroyNotify) free);
152 0 : g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
153 : } else {
154 : // Go back to the previous index
155 0 : gint previous_active = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(changed_box), "previous-active"));
156 0 : gtk_combo_box_set_active(changed_box, previous_active);
157 : }
158 :
159 0 : gtk_widget_destroy(prompt_dialog);
160 : }
161 :
162 : class nsPrintDialogWidgetGTK {
163 : public:
164 : nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aPrintSettings);
165 0 : ~nsPrintDialogWidgetGTK() { gtk_widget_destroy(dialog); }
166 : NS_ConvertUTF16toUTF8 GetUTF8FromBundle(const char* aKey);
167 : const gint Run();
168 :
169 : nsresult ImportSettings(nsIPrintSettings *aNSSettings);
170 : nsresult ExportSettings(nsIPrintSettings *aNSSettings);
171 :
172 : private:
173 : GtkWidget* dialog;
174 : GtkWidget* radio_as_laid_out;
175 : GtkWidget* radio_selected_frame;
176 : GtkWidget* radio_separate_frames;
177 : GtkWidget* shrink_to_fit_toggle;
178 : GtkWidget* print_bg_colors_toggle;
179 : GtkWidget* print_bg_images_toggle;
180 : GtkWidget* selection_only_toggle;
181 : GtkWidget* header_dropdown[3]; // {left, center, right}
182 : GtkWidget* footer_dropdown[3];
183 :
184 : nsCOMPtr<nsIStringBundle> printBundle;
185 :
186 : bool useNativeSelection;
187 :
188 : GtkWidget* ConstructHeaderFooterDropdown(const PRUnichar *currentString);
189 : const char* OptionWidgetToString(GtkWidget *dropdown);
190 :
191 : /* Code to copy between GTK and NS print settings structures.
192 : * In the following,
193 : * "Import" means to copy from NS to GTK
194 : * "Export" means to copy from GTK to NS
195 : */
196 : void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings);
197 : void ExportHeaderFooter(nsIPrintSettings *aNS);
198 : };
199 :
200 0 : nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aSettings)
201 : {
202 0 : nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
203 0 : NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
204 0 : GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
205 0 : NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
206 :
207 0 : nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
208 0 : bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
209 :
210 0 : dialog = gtk_print_unix_dialog_new(GetUTF8FromBundle("printTitleGTK").get(), gtkParent);
211 :
212 0 : gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog),
213 : GtkPrintCapabilities(
214 : GTK_PRINT_CAPABILITY_PAGE_SET
215 : | GTK_PRINT_CAPABILITY_COPIES
216 : | GTK_PRINT_CAPABILITY_COLLATE
217 : | GTK_PRINT_CAPABILITY_REVERSE
218 : | GTK_PRINT_CAPABILITY_SCALE
219 : | GTK_PRINT_CAPABILITY_GENERATE_PDF
220 : | GTK_PRINT_CAPABILITY_GENERATE_PS
221 : )
222 0 : );
223 :
224 : // The vast majority of magic numbers in this widget construction are padding. e.g. for
225 : // the set_border_width below, 12px matches that of just about every other window.
226 0 : GtkWidget* custom_options_tab = gtk_vbox_new(FALSE, 0);
227 0 : gtk_container_set_border_width(GTK_CONTAINER(custom_options_tab), 12);
228 0 : GtkWidget* tab_label = gtk_label_new(GetUTF8FromBundle("optionsTabLabelGTK").get());
229 :
230 : PRInt16 frameUIFlag;
231 0 : aSettings->GetHowToEnableFrameUI(&frameUIFlag);
232 0 : radio_as_laid_out = gtk_radio_button_new_with_mnemonic(NULL, GetUTF8FromBundle("asLaidOut").get());
233 0 : if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
234 0 : gtk_widget_set_sensitive(radio_as_laid_out, FALSE);
235 :
236 0 : radio_selected_frame = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
237 0 : GetUTF8FromBundle("selectedFrame").get());
238 0 : if (frameUIFlag == nsIPrintSettings::kFrameEnableNone ||
239 : frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach)
240 0 : gtk_widget_set_sensitive(radio_selected_frame, FALSE);
241 :
242 0 : radio_separate_frames = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
243 0 : GetUTF8FromBundle("separateFrames").get());
244 0 : if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
245 0 : gtk_widget_set_sensitive(radio_separate_frames, FALSE);
246 :
247 : // "Print Frames" options label, bold and center-aligned
248 0 : GtkWidget* print_frames_label = gtk_label_new(NULL);
249 0 : char* pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printFramesTitleGTK").get());
250 0 : gtk_label_set_markup(GTK_LABEL(print_frames_label), pangoMarkup);
251 0 : g_free(pangoMarkup);
252 0 : gtk_misc_set_alignment(GTK_MISC(print_frames_label), 0, 0);
253 :
254 : // Align the radio buttons slightly so they appear to fall under the aforementioned label as per the GNOME HIG
255 0 : GtkWidget* frames_radio_container = gtk_alignment_new(0, 0, 0, 0);
256 0 : gtk_alignment_set_padding(GTK_ALIGNMENT(frames_radio_container), 8, 0, 12, 0);
257 :
258 : // Radio buttons for the print frames options
259 0 : GtkWidget* frames_radio_list = gtk_vbox_new(TRUE, 2);
260 0 : gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_as_laid_out, FALSE, FALSE, 0);
261 0 : gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_selected_frame, FALSE, FALSE, 0);
262 0 : gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_separate_frames, FALSE, FALSE, 0);
263 0 : gtk_container_add(GTK_CONTAINER(frames_radio_container), frames_radio_list);
264 :
265 : // Check buttons for shrink-to-fit and print selection
266 0 : GtkWidget* check_buttons_container = gtk_vbox_new(TRUE, 2);
267 0 : shrink_to_fit_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("shrinkToFit").get());
268 0 : gtk_box_pack_start(GTK_BOX(check_buttons_container), shrink_to_fit_toggle, FALSE, FALSE, 0);
269 :
270 : // GTK+2.18 and above allow us to add a "Selection" option to the main settings screen,
271 : // rather than adding an option on a custom tab like we must do on older versions.
272 : bool canSelectText;
273 0 : aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &canSelectText);
274 0 : if (gtk_major_version > 2 ||
275 : (gtk_major_version == 2 && gtk_minor_version >= 18)) {
276 0 : useNativeSelection = true;
277 : g_object_set(dialog,
278 : "support-selection", TRUE,
279 : "has-selection", canSelectText,
280 : "embed-page-setup", TRUE,
281 0 : NULL);
282 : } else {
283 0 : useNativeSelection = false;
284 0 : selection_only_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("selectionOnly").get());
285 0 : gtk_widget_set_sensitive(selection_only_toggle, canSelectText);
286 0 : gtk_box_pack_start(GTK_BOX(check_buttons_container), selection_only_toggle, FALSE, FALSE, 0);
287 : }
288 :
289 : // Check buttons for printing background
290 0 : GtkWidget* appearance_buttons_container = gtk_vbox_new(TRUE, 2);
291 0 : print_bg_colors_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGColors").get());
292 0 : print_bg_images_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGImages").get());
293 0 : gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_colors_toggle, FALSE, FALSE, 0);
294 0 : gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_images_toggle, FALSE, FALSE, 0);
295 :
296 : // "Appearance" options label, bold and center-aligned
297 0 : GtkWidget* appearance_label = gtk_label_new(NULL);
298 0 : pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printBGOptions").get());
299 0 : gtk_label_set_markup(GTK_LABEL(appearance_label), pangoMarkup);
300 0 : g_free(pangoMarkup);
301 0 : gtk_misc_set_alignment(GTK_MISC(appearance_label), 0, 0);
302 :
303 0 : GtkWidget* appearance_container = gtk_alignment_new(0, 0, 0, 0);
304 0 : gtk_alignment_set_padding(GTK_ALIGNMENT(appearance_container), 8, 0, 12, 0);
305 0 : gtk_container_add(GTK_CONTAINER(appearance_container), appearance_buttons_container);
306 :
307 0 : GtkWidget* appearance_vertical_squasher = gtk_vbox_new(FALSE, 0);
308 0 : gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_label, FALSE, FALSE, 0);
309 0 : gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_container, FALSE, FALSE, 0);
310 :
311 : // "Header & Footer" options label, bold and center-aligned
312 0 : GtkWidget* header_footer_label = gtk_label_new(NULL);
313 0 : pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("headerFooter").get());
314 0 : gtk_label_set_markup(GTK_LABEL(header_footer_label), pangoMarkup);
315 0 : g_free(pangoMarkup);
316 0 : gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0);
317 :
318 0 : GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
319 0 : gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
320 :
321 :
322 : // --- Table for making the header and footer options ---
323 0 : GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
324 0 : nsXPIDLString header_footer_str[3];
325 :
326 0 : aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0]));
327 0 : aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1]));
328 0 : aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2]));
329 :
330 0 : for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) {
331 0 : header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
332 : // Those 4 magic numbers in the middle provide the position in the table.
333 : // The last two numbers mean 2 px padding on every side.
334 0 : gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1),
335 0 : 0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
336 : }
337 :
338 0 : const char labelKeys[][7] = {"left", "center", "right"};
339 0 : for (unsigned int i = 0; i < ArrayLength(labelKeys); i++) {
340 0 : gtk_table_attach(GTK_TABLE(header_footer_table),
341 0 : gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()),
342 0 : i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
343 : }
344 :
345 0 : aSettings->GetFooterStrLeft(getter_Copies(header_footer_str[0]));
346 0 : aSettings->GetFooterStrCenter(getter_Copies(header_footer_str[1]));
347 0 : aSettings->GetFooterStrRight(getter_Copies(header_footer_str[2]));
348 :
349 0 : for (unsigned int i = 0; i < ArrayLength(footer_dropdown); i++) {
350 0 : footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
351 0 : gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1),
352 0 : 2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
353 : }
354 : // ---
355 :
356 0 : gtk_container_add(GTK_CONTAINER(header_footer_container), header_footer_table);
357 :
358 0 : GtkWidget* header_footer_vertical_squasher = gtk_vbox_new(FALSE, 0);
359 0 : gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_label, FALSE, FALSE, 0);
360 0 : gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_container, FALSE, FALSE, 0);
361 :
362 : // Construction of everything
363 0 : gtk_box_pack_start(GTK_BOX(custom_options_tab), print_frames_label, FALSE, FALSE, 0);
364 0 : gtk_box_pack_start(GTK_BOX(custom_options_tab), frames_radio_container, FALSE, FALSE, 0);
365 0 : gtk_box_pack_start(GTK_BOX(custom_options_tab), check_buttons_container, FALSE, FALSE, 10); // 10px padding
366 0 : gtk_box_pack_start(GTK_BOX(custom_options_tab), appearance_vertical_squasher, FALSE, FALSE, 10);
367 0 : gtk_box_pack_start(GTK_BOX(custom_options_tab), header_footer_vertical_squasher, FALSE, FALSE, 0);
368 :
369 0 : gtk_print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(dialog), custom_options_tab, tab_label);
370 0 : gtk_widget_show_all(custom_options_tab);
371 0 : }
372 :
373 : NS_ConvertUTF16toUTF8
374 0 : nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey)
375 : {
376 0 : nsXPIDLString intlString;
377 0 : printBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aKey).get(), getter_Copies(intlString));
378 0 : return NS_ConvertUTF16toUTF8(intlString); // Return the actual object so we don't lose reference
379 : }
380 :
381 : const char*
382 0 : nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown)
383 : {
384 0 : gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(dropdown));
385 :
386 0 : NS_ASSERTION(index <= CUSTOM_VALUE_INDEX, "Index of dropdown is higher than expected!");
387 :
388 0 : if (index == CUSTOM_VALUE_INDEX)
389 0 : return (const char*) g_object_get_data(G_OBJECT(dropdown), "custom-text");
390 : else
391 0 : return header_footer_tags[index];
392 : }
393 :
394 : const gint
395 0 : nsPrintDialogWidgetGTK::Run()
396 : {
397 0 : const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
398 0 : gtk_widget_hide(dialog);
399 0 : return response;
400 : }
401 :
402 : void
403 0 : nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings)
404 : {
405 0 : if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_as_laid_out)))
406 0 : aNS->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
407 0 : else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_selected_frame)))
408 0 : aNS->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
409 0 : else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_separate_frames)))
410 0 : aNS->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
411 : else
412 0 : aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames);
413 0 : }
414 :
415 : void
416 0 : nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
417 : {
418 : const char* header_footer_str;
419 0 : header_footer_str = OptionWidgetToString(header_dropdown[0]);
420 0 : aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
421 :
422 0 : header_footer_str = OptionWidgetToString(header_dropdown[1]);
423 0 : aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
424 :
425 0 : header_footer_str = OptionWidgetToString(header_dropdown[2]);
426 0 : aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
427 :
428 0 : header_footer_str = OptionWidgetToString(footer_dropdown[0]);
429 0 : aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
430 :
431 0 : header_footer_str = OptionWidgetToString(footer_dropdown[1]);
432 0 : aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
433 :
434 0 : header_footer_str = OptionWidgetToString(footer_dropdown[2]);
435 0 : aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
436 0 : }
437 :
438 : nsresult
439 0 : nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
440 : {
441 0 : NS_PRECONDITION(aNSSettings, "aSettings must not be null");
442 0 : NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
443 :
444 0 : nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
445 0 : if (!aNSSettingsGTK)
446 0 : return NS_ERROR_FAILURE;
447 :
448 0 : GtkPrintSettings* settings = aNSSettingsGTK->GetGtkPrintSettings();
449 0 : GtkPageSetup* setup = aNSSettingsGTK->GetGtkPageSetup();
450 :
451 : bool geckoBool;
452 0 : aNSSettings->GetShrinkToFit(&geckoBool);
453 0 : gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle), geckoBool);
454 :
455 0 : aNSSettings->GetPrintBGColors(&geckoBool);
456 0 : gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle), geckoBool);
457 :
458 0 : aNSSettings->GetPrintBGImages(&geckoBool);
459 0 : gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle), geckoBool);
460 :
461 0 : gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog), settings);
462 0 : gtk_print_unix_dialog_set_page_setup(GTK_PRINT_UNIX_DIALOG(dialog), setup);
463 :
464 0 : return NS_OK;
465 : }
466 :
467 : nsresult
468 0 : nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
469 : {
470 0 : NS_PRECONDITION(aNSSettings, "aSettings must not be null");
471 0 : NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
472 :
473 0 : GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
474 0 : GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog));
475 0 : GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dialog));
476 0 : if (settings && setup && printer) {
477 0 : ExportFramePrinting(aNSSettings, settings);
478 0 : ExportHeaderFooter(aNSSettings);
479 :
480 0 : aNSSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
481 :
482 : // Print-to-file is true by default. This must be turned off or else printing won't occur!
483 : // (We manually copy the spool file when this flag is set, because we love our embedders)
484 : // Even if it is print-to-file in GTK's case, GTK does The Right Thing when we send the job.
485 0 : aNSSettings->SetPrintToFile(false);
486 :
487 0 : aNSSettings->SetShrinkToFit(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle)));
488 :
489 0 : aNSSettings->SetPrintBGColors(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle)));
490 0 : aNSSettings->SetPrintBGImages(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle)));
491 :
492 : // Try to save native settings in the session object
493 0 : nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
494 0 : if (aNSSettingsGTK) {
495 0 : aNSSettingsGTK->SetGtkPrintSettings(settings);
496 0 : aNSSettingsGTK->SetGtkPageSetup(setup);
497 0 : aNSSettingsGTK->SetGtkPrinter(printer);
498 : bool printSelectionOnly;
499 0 : if (useNativeSelection) {
500 0 : _GtkPrintPages pageSetting = (_GtkPrintPages)gtk_print_settings_get_print_pages(settings);
501 0 : printSelectionOnly = (pageSetting == _GTK_PRINT_PAGES_SELECTION);
502 : } else {
503 0 : printSelectionOnly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selection_only_toggle));
504 : }
505 0 : aNSSettingsGTK->SetForcePrintSelectionOnly(printSelectionOnly);
506 : }
507 : }
508 :
509 0 : if (settings)
510 0 : g_object_unref(settings);
511 0 : return NS_OK;
512 : }
513 :
514 : GtkWidget*
515 0 : nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const PRUnichar *currentString)
516 : {
517 0 : GtkWidget* dropdown = gtk_combo_box_new_text();
518 : const char hf_options[][22] = {"headerFooterBlank", "headerFooterTitle",
519 : "headerFooterURL", "headerFooterDate",
520 : "headerFooterPage", "headerFooterPageTotal",
521 0 : "headerFooterCustom"};
522 :
523 0 : for (unsigned int i = 0; i < ArrayLength(hf_options); i++) {
524 0 : gtk_combo_box_append_text(GTK_COMBO_BOX(dropdown), GetUTF8FromBundle(hf_options[i]).get());
525 : }
526 :
527 0 : bool shouldBeCustom = true;
528 0 : NS_ConvertUTF16toUTF8 currentStringUTF8(currentString);
529 :
530 0 : for (unsigned int i = 0; i < ArrayLength(header_footer_tags); i++) {
531 0 : if (!strcmp(currentStringUTF8.get(), header_footer_tags[i])) {
532 0 : gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), i);
533 0 : g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(i));
534 0 : shouldBeCustom = false;
535 0 : break;
536 : }
537 : }
538 :
539 0 : if (shouldBeCustom) {
540 0 : gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), CUSTOM_VALUE_INDEX);
541 0 : g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
542 0 : char* custom_string = strdup(currentStringUTF8.get());
543 0 : g_object_set_data_full(G_OBJECT(dropdown), "custom-text", custom_string, (GDestroyNotify) free);
544 : }
545 :
546 0 : g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, dialog);
547 0 : return dropdown;
548 : }
549 :
550 0 : NS_IMPL_ISUPPORTS1(nsPrintDialogServiceGTK, nsIPrintDialogService)
551 :
552 0 : nsPrintDialogServiceGTK::nsPrintDialogServiceGTK()
553 : {
554 0 : }
555 :
556 0 : nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK()
557 : {
558 0 : }
559 :
560 : NS_IMETHODIMP
561 0 : nsPrintDialogServiceGTK::Init()
562 : {
563 0 : return NS_OK;
564 : }
565 :
566 : NS_IMETHODIMP
567 0 : nsPrintDialogServiceGTK::Show(nsIDOMWindow *aParent, nsIPrintSettings *aSettings,
568 : nsIWebBrowserPrint *aWebBrowserPrint)
569 : {
570 0 : NS_PRECONDITION(aParent, "aParent must not be null");
571 0 : NS_PRECONDITION(aSettings, "aSettings must not be null");
572 :
573 0 : nsPrintDialogWidgetGTK printDialog(aParent, aSettings);
574 0 : nsresult rv = printDialog.ImportSettings(aSettings);
575 :
576 0 : NS_ENSURE_SUCCESS(rv, rv);
577 :
578 0 : const gint response = printDialog.Run();
579 :
580 : // Handle the result
581 0 : switch (response) {
582 : case GTK_RESPONSE_OK: // Proceed
583 0 : rv = printDialog.ExportSettings(aSettings);
584 0 : break;
585 :
586 : case GTK_RESPONSE_CANCEL:
587 : case GTK_RESPONSE_CLOSE:
588 : case GTK_RESPONSE_DELETE_EVENT:
589 : case GTK_RESPONSE_NONE:
590 0 : rv = NS_ERROR_ABORT;
591 0 : break;
592 :
593 : case GTK_RESPONSE_APPLY: // Print preview
594 : default:
595 0 : NS_WARNING("Unexpected response");
596 0 : rv = NS_ERROR_ABORT;
597 : }
598 0 : return rv;
599 : }
600 :
601 : NS_IMETHODIMP
602 0 : nsPrintDialogServiceGTK::ShowPageSetup(nsIDOMWindow *aParent,
603 : nsIPrintSettings *aNSSettings)
604 : {
605 0 : NS_PRECONDITION(aParent, "aParent must not be null");
606 0 : NS_PRECONDITION(aNSSettings, "aSettings must not be null");
607 0 : NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
608 :
609 0 : nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
610 0 : NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
611 0 : GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
612 0 : NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
613 :
614 0 : nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
615 0 : if (!aNSSettingsGTK)
616 0 : return NS_ERROR_FAILURE;
617 :
618 : // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
619 0 : nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
620 0 : if (psService) {
621 0 : nsXPIDLString printName;
622 0 : aNSSettings->GetPrinterName(getter_Copies(printName));
623 0 : if (!printName) {
624 0 : psService->GetDefaultPrinterName(getter_Copies(printName));
625 0 : aNSSettings->SetPrinterName(printName.get());
626 : }
627 0 : psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
628 : }
629 :
630 0 : GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
631 0 : GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
632 :
633 0 : GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(gtkParent, oldPageSetup, gtkSettings);
634 :
635 0 : aNSSettingsGTK->SetGtkPageSetup(newPageSetup);
636 :
637 : // Now newPageSetup has a refcount of 2 (SetGtkPageSetup will addref), put it to 1 so if
638 : // this gets replaced we don't leak.
639 0 : g_object_unref(newPageSetup);
640 :
641 0 : if (psService)
642 0 : psService->SavePrintSettingsToPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
643 :
644 0 : return NS_OK;
645 : }
|