Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / unx / gtk3 / gtk3salprn-gtk.cxx
blob7d214a70afcc1f919e5b2da5b55f12c3ab183445
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <unx/gtk/gtkprintwrapper.hxx>
12 #include <unx/gtk/gtkdata.hxx>
13 #include <unx/gtk/gtkframe.hxx>
14 #include <unx/gtk/gtkinst.hxx>
15 #include <unx/gtk/gtkprn.hxx>
17 #include <vcl/configsettings.hxx>
18 #include <vcl/help.hxx>
19 #include <vcl/print.hxx>
20 #include <vcl/svapp.hxx>
21 #include <vcl/window.hxx>
23 #include <gtk/gtk.h>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/view/PrintableState.hpp>
28 #include <officecfg/Office/Common.hxx>
30 #include <rtl/ustring.hxx>
31 #include <sal/log.hxx>
33 #include <cstring>
34 #include <map>
36 namespace beans = com::sun::star::beans;
37 namespace uno = com::sun::star::uno;
38 namespace view = com::sun::star::view;
40 using vcl::unx::GtkPrintWrapper;
42 using uno::UNO_QUERY;
44 class GtkPrintDialog
46 public:
47 explicit GtkPrintDialog(vcl::PrinterController& io_rController);
48 bool run();
49 GtkPrinter* getPrinter() const
51 return m_xWrapper->print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(m_pDialog));
53 GtkPrintSettings* getSettings() const
55 return m_xWrapper->print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(m_pDialog));
57 void updateControllerPrintRange();
59 ~GtkPrintDialog();
61 static void UIOption_CheckHdl(GtkWidget* i_pWidget, GtkPrintDialog* io_pThis)
63 io_pThis->impl_UIOption_CheckHdl(i_pWidget);
65 static void UIOption_RadioHdl(GtkWidget* i_pWidget, GtkPrintDialog* io_pThis)
67 io_pThis->impl_UIOption_RadioHdl(i_pWidget);
69 static void UIOption_SelectHdl(GtkWidget* i_pWidget, GtkPrintDialog* io_pThis)
71 io_pThis->impl_UIOption_SelectHdl(i_pWidget);
74 private:
75 beans::PropertyValue* impl_queryPropertyValue(GtkWidget* i_pWidget) const;
76 void impl_checkOptionalControlDependencies();
78 void impl_UIOption_CheckHdl(GtkWidget* i_pWidget);
79 void impl_UIOption_RadioHdl(GtkWidget* i_pWidget);
80 void impl_UIOption_SelectHdl(GtkWidget* i_pWidget);
82 void impl_initDialog();
83 void impl_initCustomTab();
84 void impl_initPrintContent(uno::Sequence<sal_Bool> const& i_rDisabled);
86 void impl_readFromSettings();
87 void impl_storeToSettings() const;
89 private:
90 GtkWidget* m_pDialog;
91 vcl::PrinterController& m_rController;
92 std::map<GtkWidget*, OUString> m_aControlToPropertyMap;
93 std::map<GtkWidget*, sal_Int32> m_aControlToNumValMap;
94 std::shared_ptr<GtkPrintWrapper> m_xWrapper;
97 struct GtkSalPrinter_Impl
99 OString m_sSpoolFile;
100 OUString m_sJobName;
101 GtkPrinter* m_pPrinter;
102 GtkPrintSettings* m_pSettings;
104 GtkSalPrinter_Impl();
105 ~GtkSalPrinter_Impl();
108 GtkSalPrinter_Impl::GtkSalPrinter_Impl()
109 : m_pPrinter(nullptr)
110 , m_pSettings(nullptr)
114 GtkSalPrinter_Impl::~GtkSalPrinter_Impl()
116 if (m_pPrinter)
118 g_object_unref(G_OBJECT(m_pPrinter));
119 m_pPrinter = nullptr;
121 if (m_pSettings)
123 g_object_unref(G_OBJECT(m_pSettings));
124 m_pSettings = nullptr;
128 namespace
131 GtkInstance const&
132 lcl_getGtkSalInstance()
134 // we _know_ this is GtkInstance
135 return *static_cast<GtkInstance*>(GetGtkSalData()->m_pInstance);
138 bool
139 lcl_useSystemPrintDialog()
141 return officecfg::Office::Common::Misc::UseSystemPrintDialog::get()
142 && officecfg::Office::Common::Misc::ExperimentalMode::get()
143 && lcl_getGtkSalInstance().getPrintWrapper()->supportsPrinting();
148 GtkSalPrinter::GtkSalPrinter(SalInfoPrinter* const i_pInfoPrinter)
149 : PspSalPrinter(i_pInfoPrinter)
153 GtkSalPrinter::~GtkSalPrinter() = default;
155 bool
156 GtkSalPrinter::impl_doJob(
157 const OUString* const i_pFileName,
158 const OUString& i_rJobName,
159 const OUString& i_rAppName,
160 ImplJobSetup* const io_pSetupData,
161 const bool i_bCollate,
162 vcl::PrinterController& io_rController)
164 io_rController.setJobState(view::PrintableState_JOB_STARTED);
165 io_rController.jobStarted();
166 const bool bJobStarted(
167 PspSalPrinter::StartJob(i_pFileName, i_rJobName, i_rAppName,
168 1/*i_nCopies*/, i_bCollate, true, io_pSetupData))
171 if (bJobStarted)
173 io_rController.createProgressDialog();
174 const int nPages(io_rController.getFilteredPageCount());
175 for (int nPage(0); nPage != nPages; ++nPage)
177 if (nPage == nPages - 1)
178 io_rController.setLastPage(true);
179 io_rController.printFilteredPage(nPage);
181 io_rController.setJobState(view::PrintableState_JOB_COMPLETED);
184 return bJobStarted;
187 bool
188 GtkSalPrinter::StartJob(
189 const OUString* const i_pFileName,
190 const OUString& i_rJobName,
191 const OUString& i_rAppName,
192 ImplJobSetup* io_pSetupData,
193 vcl::PrinterController& io_rController)
195 if (!lcl_useSystemPrintDialog())
196 return PspSalPrinter::StartJob(i_pFileName, i_rJobName, i_rAppName, io_pSetupData, io_rController);
198 assert(!m_xImpl);
200 m_xImpl.reset(new GtkSalPrinter_Impl());
201 m_xImpl->m_sJobName = i_rJobName;
203 OString sFileName;
204 if (i_pFileName)
205 sFileName = OUStringToOString(*i_pFileName, osl_getThreadTextEncoding());
207 GtkPrintDialog aDialog(io_rController);
208 if (!aDialog.run())
210 io_rController.abortJob();
211 return false;
213 aDialog.updateControllerPrintRange();
214 m_xImpl->m_pPrinter = aDialog.getPrinter();
215 m_xImpl->m_pSettings = aDialog.getSettings();
217 //To-Do proper name, watch for encodings
218 sFileName = OString("/tmp/hacking.ps");
219 m_xImpl->m_sSpoolFile = sFileName;
221 OUString aFileName = OStringToOUString(sFileName, osl_getThreadTextEncoding());
223 //To-Do, swap ps/pdf for gtk_printer_accepts_ps()/gtk_printer_accepts_pdf() ?
225 return impl_doJob(&aFileName, i_rJobName, i_rAppName, io_pSetupData, /*bCollate*/false, io_rController);
228 bool
229 GtkSalPrinter::EndJob()
231 bool bRet = PspSalPrinter::EndJob();
233 if (!lcl_useSystemPrintDialog())
234 return bRet;
236 assert(m_xImpl);
238 if (!bRet || m_xImpl->m_sSpoolFile.isEmpty())
239 return bRet;
241 std::shared_ptr<GtkPrintWrapper> const xWrapper(lcl_getGtkSalInstance().getPrintWrapper());
243 GtkPageSetup* pPageSetup = xWrapper->page_setup_new();
245 GtkPrintJob* const pJob = xWrapper->print_job_new(
246 OUStringToOString(m_xImpl->m_sJobName, RTL_TEXTENCODING_UTF8).getStr(),
247 m_xImpl->m_pPrinter, m_xImpl->m_pSettings, pPageSetup);
249 GError* error = nullptr;
250 bRet = xWrapper->print_job_set_source_file(pJob, m_xImpl->m_sSpoolFile.getStr(), &error);
251 if (bRet)
252 xWrapper->print_job_send(pJob, nullptr, nullptr, nullptr);
253 else
255 //To-Do, do something with this
256 fprintf(stderr, "error was %s\n", error->message);
257 g_error_free(error);
260 g_object_unref(pPageSetup);
261 m_xImpl.reset();
263 //To-Do, remove temp spool file
265 return bRet;
268 namespace
271 void
272 lcl_setHelpText(
273 GtkWidget* const io_pWidget,
274 const uno::Sequence<OUString>& i_rHelpTexts,
275 const sal_Int32 i_nIndex)
277 if (i_nIndex >= 0 && i_nIndex < i_rHelpTexts.getLength())
278 gtk_widget_set_tooltip_text(io_pWidget,
279 OUStringToOString(i_rHelpTexts.getConstArray()[i_nIndex], RTL_TEXTENCODING_UTF8).getStr());
282 GtkWidget*
283 lcl_makeFrame(
284 GtkWidget* const i_pChild,
285 const OUString &i_rText,
286 const uno::Sequence<OUString> &i_rHelpTexts,
287 sal_Int32* const io_pCurHelpText)
289 GtkWidget* const pLabel = gtk_label_new(nullptr);
290 lcl_setHelpText(pLabel, i_rHelpTexts, !io_pCurHelpText ? 0 : (*io_pCurHelpText)++);
291 gtk_misc_set_alignment(GTK_MISC(pLabel), 0.0, 0.5);
294 gchar* const pText = g_markup_printf_escaped("<b>%s</b>",
295 OUStringToOString(i_rText, RTL_TEXTENCODING_UTF8).getStr());
296 gtk_label_set_markup_with_mnemonic(GTK_LABEL(pLabel), pText);
297 g_free(pText);
300 GtkWidget* const pFrame = gtk_vbox_new(FALSE, 6);
301 gtk_box_pack_start(GTK_BOX(pFrame), pLabel, FALSE, FALSE, 0);
303 GtkWidget* const pAlignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
304 gtk_alignment_set_padding(GTK_ALIGNMENT(pAlignment), 0, 0, 12, 0);
305 gtk_box_pack_start(GTK_BOX(pFrame), pAlignment, FALSE, FALSE, 0);
307 gtk_container_add(GTK_CONTAINER(pAlignment), i_pChild);
308 return pFrame;
311 void
312 lcl_extractHelpTextsOrIds(
313 const beans::PropertyValue& rEntry,
314 uno::Sequence<OUString>& rHelpStrings)
316 if (!(rEntry.Value >>= rHelpStrings))
318 OUString aHelpString;
319 if (rEntry.Value >>= aHelpString)
321 rHelpStrings.realloc(1);
322 *rHelpStrings.getArray() = aHelpString;
327 GtkWidget*
328 lcl_combo_box_text_new()
330 return gtk_combo_box_text_new();
333 void
334 lcl_combo_box_text_append(GtkWidget* const pWidget, gchar const* const pText)
336 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(pWidget), pText);
341 GtkPrintDialog::GtkPrintDialog(vcl::PrinterController& io_rController)
342 : m_rController(io_rController)
343 , m_xWrapper(lcl_getGtkSalInstance().getPrintWrapper())
345 assert(m_xWrapper->supportsPrinting());
346 impl_initDialog();
347 impl_initCustomTab();
348 impl_readFromSettings();
351 void
352 GtkPrintDialog::impl_initDialog()
354 //To-Do, like fpicker, set UI language
355 m_pDialog = m_xWrapper->print_unix_dialog_new();
357 vcl::Window* const pTopWindow(Application::GetActiveTopWindow());
358 if (pTopWindow)
360 GtkSalFrame* const pFrame(dynamic_cast<GtkSalFrame*>(pTopWindow->ImplGetFrame()));
361 if (pFrame)
363 GtkWindow* const pParent(GTK_WINDOW(pFrame->getWindow()));
364 if (pParent)
365 gtk_window_set_transient_for(GTK_WINDOW(m_pDialog), pParent);
369 m_xWrapper->print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(m_pDialog),
370 GtkPrintCapabilities(GTK_PRINT_CAPABILITY_COPIES
371 | GTK_PRINT_CAPABILITY_COLLATE
372 | GTK_PRINT_CAPABILITY_REVERSE
373 | GTK_PRINT_CAPABILITY_GENERATE_PS
374 | GTK_PRINT_CAPABILITY_NUMBER_UP
375 | GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT
379 void
380 GtkPrintDialog::impl_initCustomTab()
382 typedef std::vector<std::pair<GtkWidget*, OUString> > CustomTabs_t;
384 const uno::Sequence<beans::PropertyValue>& rOptions(m_rController.getUIOptions());
385 std::map<OUString, GtkWidget*> aPropertyToDependencyRowMap;
386 CustomTabs_t aCustomTabs;
387 GtkWidget* pCurParent = nullptr;
388 GtkWidget* pCurTabPage = nullptr;
389 GtkWidget* pCurSubGroup = nullptr;
390 bool bIgnoreSubgroup = false;
391 for (const auto& rOption : rOptions)
393 uno::Sequence<beans::PropertyValue> aOptProp;
394 rOption.Value >>= aOptProp;
396 OUString aCtrlType;
397 OUString aText;
398 OUString aPropertyName;
399 uno::Sequence<OUString> aChoices;
400 uno::Sequence<sal_Bool> aChoicesDisabled;
401 uno::Sequence<OUString> aHelpTexts;
402 sal_Int64 nMinValue = 0, nMaxValue = 0;
403 sal_Int32 nCurHelpText = 0;
404 OUString aDependsOnName;
405 sal_Int32 nDependsOnValue = 0;
406 bool bUseDependencyRow = false;
407 bool bIgnore = false;
408 GtkWidget* pGroup = nullptr;
409 bool bGtkInternal = false;
411 //Fix fdo#69381
412 //Next options if this one is empty
413 if (!aOptProp.hasElements())
414 continue;
416 for (const beans::PropertyValue& rEntry : std::as_const(aOptProp))
418 if ( rEntry.Name == "Text" )
420 OUString aValue;
421 rEntry.Value >>= aValue;
422 aText = aValue.replace('~', '_');
424 else if ( rEntry.Name == "ControlType" )
425 rEntry.Value >>= aCtrlType;
426 else if ( rEntry.Name == "Choices" )
427 rEntry.Value >>= aChoices;
428 else if ( rEntry.Name == "ChoicesDisabled" )
429 rEntry.Value >>= aChoicesDisabled;
430 else if ( rEntry.Name == "Property" )
432 beans::PropertyValue aVal;
433 rEntry.Value >>= aVal;
434 aPropertyName = aVal.Name;
436 else if ( rEntry.Name == "DependsOnName" )
437 rEntry.Value >>= aDependsOnName;
438 else if ( rEntry.Name == "DependsOnEntry" )
439 rEntry.Value >>= nDependsOnValue;
440 else if ( rEntry.Name == "AttachToDependency" )
441 rEntry.Value >>= bUseDependencyRow;
442 else if ( rEntry.Name == "MinValue" )
443 rEntry.Value >>= nMinValue;
444 else if ( rEntry.Name == "MaxValue" )
445 rEntry.Value >>= nMaxValue;
446 else if ( rEntry.Name == "HelpId" )
448 uno::Sequence<OUString> aHelpIds;
449 lcl_extractHelpTextsOrIds(rEntry, aHelpIds);
450 Help* const pHelp = Application::GetHelp();
451 if (pHelp)
453 const int nLen = aHelpIds.getLength();
454 aHelpTexts.realloc(nLen);
455 std::transform(aHelpIds.begin(), aHelpIds.end(), aHelpTexts.begin(),
456 [&pHelp](const OUString& rHelpId) { return pHelp->GetHelpText(rHelpId, static_cast<weld::Widget*>(nullptr)); });
458 else // fallback
459 aHelpTexts = aHelpIds;
461 else if ( rEntry.Name == "HelpText" )
462 lcl_extractHelpTextsOrIds(rEntry, aHelpTexts);
463 else if ( rEntry.Name == "InternalUIOnly" )
464 rEntry.Value >>= bIgnore;
465 else if ( rEntry.Name == "Enabled" )
467 // Ignore this. We use UIControlOptions::isUIOptionEnabled
468 // to check whether a control should be enabled.
470 else if ( rEntry.Name == "GroupingHint" )
472 // Ignore this. We cannot add/modify controls to/on existing
473 // tabs of the Gtk print dialog.
475 else
477 SAL_INFO("vcl.gtk", "unhandled UI option entry: " << rEntry.Name);
481 if ( aPropertyName == "PrintContent" )
482 bGtkInternal = true;
484 if (aCtrlType == "Group" || !pCurParent)
486 pCurTabPage = gtk_vbox_new(FALSE, 12);
487 gtk_container_set_border_width(GTK_CONTAINER(pCurTabPage), 6);
488 lcl_setHelpText(pCurTabPage, aHelpTexts, 0);
490 pCurParent = pCurTabPage;
491 aCustomTabs.emplace_back(pCurTabPage, aText);
493 else if (aCtrlType == "Subgroup")
495 bIgnoreSubgroup = bIgnore;
496 if (bIgnore)
497 continue;
498 pCurParent = gtk_vbox_new(FALSE, 12);
499 gtk_container_set_border_width(GTK_CONTAINER(pCurParent), 0);
501 pCurSubGroup = lcl_makeFrame(pCurParent, aText, aHelpTexts, nullptr);
502 gtk_box_pack_start(GTK_BOX(pCurTabPage), pCurSubGroup, FALSE, FALSE, 0);
504 // special case: we need to map these to controls of the gtk print dialog
505 else if (bGtkInternal)
507 if ( aPropertyName == "PrintContent" )
509 // What to print? And, more importantly, is there a selection?
510 impl_initPrintContent(aChoicesDisabled);
513 else if (bIgnoreSubgroup || bIgnore)
514 continue;
515 else
517 // change handlers for all the controls set up in this block
518 // should be set _after_ the control has been made (in)active,
519 // because:
520 // 1. value of the property is _known_--we are using it to
521 // _set_ the control, right?--no need to change it back .-)
522 // 2. it may cause warning because the widget may not
523 // have been placed in m_aControlToPropertyMap yet
525 GtkWidget* pWidget = nullptr;
526 beans::PropertyValue* pVal = nullptr;
527 if (aCtrlType == "Bool" && pCurParent)
529 pWidget = gtk_check_button_new_with_mnemonic(
530 OUStringToOString(aText, RTL_TEXTENCODING_UTF8).getStr());
531 lcl_setHelpText(pWidget, aHelpTexts, 0);
532 m_aControlToPropertyMap[pWidget] = aPropertyName;
534 bool bVal = false;
535 pVal = m_rController.getValue(aPropertyName);
536 if (pVal)
537 pVal->Value >>= bVal;
538 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pWidget), bVal);
539 gtk_widget_set_sensitive(pWidget,
540 m_rController.isUIOptionEnabled(aPropertyName) && pVal != nullptr);
541 g_signal_connect(pWidget, "toggled", G_CALLBACK(GtkPrintDialog::UIOption_CheckHdl), this);
543 else if (aCtrlType == "Radio" && pCurParent)
545 GtkWidget* const pVbox = gtk_vbox_new(FALSE, 12);
546 gtk_container_set_border_width(GTK_CONTAINER(pVbox), 0);
548 if (!aText.isEmpty())
549 pGroup = lcl_makeFrame(pVbox, aText, aHelpTexts, &nCurHelpText);
551 sal_Int32 nSelectVal = 0;
552 pVal = m_rController.getValue(aPropertyName);
553 if (pVal && pVal->Value.hasValue())
554 pVal->Value >>= nSelectVal;
556 for (sal_Int32 m = 0; m != aChoices.getLength(); m++)
558 pWidget = gtk_radio_button_new_with_mnemonic_from_widget(
559 GTK_RADIO_BUTTON(m == 0 ? nullptr : pWidget),
560 OUStringToOString(aChoices[m].replace('~', '_'), RTL_TEXTENCODING_UTF8).getStr());
561 lcl_setHelpText(pWidget, aHelpTexts, nCurHelpText++);
562 m_aControlToPropertyMap[pWidget] = aPropertyName;
563 m_aControlToNumValMap[pWidget] = m;
564 GtkWidget* const pRow = gtk_hbox_new(FALSE, 12);
565 gtk_box_pack_start(GTK_BOX(pVbox), pRow, FALSE, FALSE, 0);
566 gtk_box_pack_start(GTK_BOX(pRow), pWidget, FALSE, FALSE, 0);
567 aPropertyToDependencyRowMap[aPropertyName + OUString::number(m)] = pRow;
568 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pWidget), m == nSelectVal);
569 gtk_widget_set_sensitive(pWidget,
570 m_rController.isUIOptionEnabled(aPropertyName) && pVal != nullptr);
571 g_signal_connect(pWidget, "toggled",
572 G_CALLBACK(GtkPrintDialog::UIOption_RadioHdl), this);
575 if (pGroup)
576 pWidget = pGroup;
577 else
578 pWidget = pVbox;
580 else if ((aCtrlType == "List" ||
581 aCtrlType == "Range" ||
582 aCtrlType == "Edit"
583 ) && pCurParent)
585 GtkWidget* const pHbox = gtk_hbox_new(FALSE, 12);
586 gtk_container_set_border_width(GTK_CONTAINER(pHbox), 0);
588 if ( aCtrlType == "List" )
590 pWidget = lcl_combo_box_text_new();
592 for (const auto& rChoice : std::as_const(aChoices))
594 lcl_combo_box_text_append(pWidget,
595 OUStringToOString(rChoice, RTL_TEXTENCODING_UTF8).getStr());
598 sal_Int32 nSelectVal = 0;
599 pVal = m_rController.getValue(aPropertyName);
600 if (pVal && pVal->Value.hasValue())
601 pVal->Value >>= nSelectVal;
602 gtk_combo_box_set_active(GTK_COMBO_BOX(pWidget), nSelectVal);
603 g_signal_connect(pWidget, "changed", G_CALLBACK(GtkPrintDialog::UIOption_SelectHdl), this);
605 else if (aCtrlType == "Edit" && pCurParent)
607 pWidget = gtk_entry_new();
609 OUString aCurVal;
610 pVal = m_rController.getValue(aPropertyName);
611 if (pVal && pVal->Value.hasValue())
612 pVal->Value >>= aCurVal;
613 gtk_entry_set_text(GTK_ENTRY(pWidget),
614 OUStringToOString(aCurVal, RTL_TEXTENCODING_UTF8).getStr());
616 else if (aCtrlType == "Range" && pCurParent)
618 pWidget = gtk_spin_button_new_with_range(nMinValue, nMaxValue, 1.0);
620 sal_Int64 nCurVal = 0;
621 pVal = m_rController.getValue(aPropertyName);
622 if (pVal && pVal->Value.hasValue())
623 pVal->Value >>= nCurVal;
624 gtk_spin_button_set_value(GTK_SPIN_BUTTON(pWidget), nCurVal);
627 lcl_setHelpText(pWidget, aHelpTexts, 0);
628 m_aControlToPropertyMap[pWidget] = aPropertyName;
630 gtk_widget_set_sensitive(pWidget,
631 m_rController.isUIOptionEnabled(aPropertyName) && pVal != nullptr);
633 if (!aText.isEmpty())
635 GtkWidget* const pLabel = gtk_label_new_with_mnemonic(
636 OUStringToOString(aText, RTL_TEXTENCODING_UTF8).getStr());
637 gtk_label_set_mnemonic_widget(GTK_LABEL(pLabel), pWidget);
638 gtk_box_pack_start(GTK_BOX(pHbox), pLabel, FALSE, FALSE, 0);
641 gtk_box_pack_start(GTK_BOX(pHbox), pWidget, FALSE, FALSE, 0);
643 pWidget = pHbox;
646 else
647 SAL_INFO("vcl.gtk", "unhandled option type: " << aCtrlType);
649 GtkWidget* pRow = nullptr;
650 if (pWidget)
652 if (bUseDependencyRow && !aDependsOnName.isEmpty())
654 pRow = aPropertyToDependencyRowMap[aDependsOnName + OUString::number(nDependsOnValue)];
655 if (!pRow)
657 gtk_widget_destroy(pWidget);
658 pWidget = nullptr;
662 if (pWidget)
664 if (!pRow)
666 pRow = gtk_hbox_new(FALSE, 12);
667 gtk_box_pack_start(GTK_BOX(pCurParent), pRow, FALSE, FALSE, 0);
669 if (!pGroup)
670 aPropertyToDependencyRowMap[aPropertyName + OUString::number(0)] = pRow;
671 gtk_box_pack_start(GTK_BOX(pRow), pWidget, FALSE, FALSE, 0);
676 CustomTabs_t::const_reverse_iterator aEnd = aCustomTabs.rend();
677 for (CustomTabs_t::const_reverse_iterator aI = aCustomTabs.rbegin(); aI != aEnd; ++aI)
679 gtk_widget_show_all(aI->first);
680 m_xWrapper->print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(m_pDialog), aI->first,
681 gtk_label_new(OUStringToOString(aI->second, RTL_TEXTENCODING_UTF8).getStr()));
685 void
686 GtkPrintDialog::impl_initPrintContent(uno::Sequence<sal_Bool> const& i_rDisabled)
688 SAL_WARN_IF(i_rDisabled.getLength() != 3, "vcl.gtk", "there is more choices than we expected");
689 if (i_rDisabled.getLength() != 3)
690 return;
692 GtkPrintUnixDialog* const pDialog(GTK_PRINT_UNIX_DIALOG(m_pDialog));
694 // XXX: This is a hack that depends on the number and the ordering of
695 // the controls in the rDisabled sequence (cf. the initialization of
696 // the "PrintContent" UI option in SwPrintUIOptions::SwPrintUIOptions,
697 // sw/source/core/view/printdata.cxx)
698 if (m_xWrapper->supportsPrintSelection() && !i_rDisabled[2])
700 m_xWrapper->print_unix_dialog_set_support_selection(pDialog, TRUE);
701 m_xWrapper->print_unix_dialog_set_has_selection(pDialog, TRUE);
704 beans::PropertyValue* const pPrintContent(
705 m_rController.getValue(OUString("PrintContent")));
707 if (pPrintContent)
709 sal_Int32 nSelectionType(0);
710 pPrintContent->Value >>= nSelectionType;
711 GtkPrintSettings* const pSettings(getSettings());
712 GtkPrintPages ePrintPages(GTK_PRINT_PAGES_ALL);
713 switch (nSelectionType)
715 case 0:
716 ePrintPages = GTK_PRINT_PAGES_ALL;
717 break;
718 case 1:
719 ePrintPages = GTK_PRINT_PAGES_RANGES;
720 break;
721 case 2:
722 if (m_xWrapper->supportsPrintSelection())
723 ePrintPages = GTK_PRINT_PAGES_SELECTION;
724 else
725 SAL_INFO("vcl.gtk", "the application wants to print a selection, but the present gtk version does not support it");
726 break;
727 default:
728 SAL_WARN("vcl.gtk", "unexpected selection type: " << nSelectionType);
730 m_xWrapper->print_settings_set_print_pages(pSettings, ePrintPages);
731 m_xWrapper->print_unix_dialog_set_settings(pDialog, pSettings);
732 g_object_unref(G_OBJECT(pSettings));
736 void
737 GtkPrintDialog::impl_checkOptionalControlDependencies()
739 for (auto& rEntry : m_aControlToPropertyMap)
741 gtk_widget_set_sensitive(rEntry.first, m_rController.isUIOptionEnabled(rEntry.second));
745 beans::PropertyValue*
746 GtkPrintDialog::impl_queryPropertyValue(GtkWidget* const i_pWidget) const
748 beans::PropertyValue* pVal(nullptr);
749 std::map<GtkWidget*, OUString>::const_iterator aIt(m_aControlToPropertyMap.find(i_pWidget));
750 if (aIt != m_aControlToPropertyMap.end())
752 pVal = m_rController.getValue(aIt->second);
753 SAL_WARN_IF(!pVal, "vcl.gtk", "property value not found");
755 else
757 SAL_WARN("vcl.gtk", "changed control not in property map");
759 return pVal;
762 void
763 GtkPrintDialog::impl_UIOption_CheckHdl(GtkWidget* const i_pWidget)
765 beans::PropertyValue* const pVal = impl_queryPropertyValue(i_pWidget);
766 if (pVal)
768 const bool bVal = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(i_pWidget));
769 pVal->Value <<= bVal;
771 impl_checkOptionalControlDependencies();
775 void
776 GtkPrintDialog::impl_UIOption_RadioHdl(GtkWidget* const i_pWidget)
778 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(i_pWidget)))
780 beans::PropertyValue* const pVal = impl_queryPropertyValue(i_pWidget);
781 std::map<GtkWidget*, sal_Int32>::const_iterator it = m_aControlToNumValMap.find(i_pWidget);
782 if (pVal && it != m_aControlToNumValMap.end())
785 const sal_Int32 nVal = it->second;
786 pVal->Value <<= nVal;
788 impl_checkOptionalControlDependencies();
793 void
794 GtkPrintDialog::impl_UIOption_SelectHdl(GtkWidget* const i_pWidget)
796 beans::PropertyValue* const pVal = impl_queryPropertyValue(i_pWidget);
797 if (pVal)
799 const sal_Int32 nVal(gtk_combo_box_get_active(GTK_COMBO_BOX(i_pWidget)));
800 pVal->Value <<= nVal;
802 impl_checkOptionalControlDependencies();
806 bool
807 GtkPrintDialog::run()
809 bool bDoJob = false;
810 bool bContinue = true;
811 while (bContinue)
813 bContinue = false;
814 const gint nStatus = gtk_dialog_run(GTK_DIALOG(m_pDialog));
815 switch (nStatus)
817 case GTK_RESPONSE_HELP:
818 fprintf(stderr, "To-Do: Help ?\n");
819 bContinue = true;
820 break;
821 case GTK_RESPONSE_OK:
822 bDoJob = true;
823 break;
824 default:
825 break;
828 gtk_widget_hide(m_pDialog);
829 impl_storeToSettings();
830 return bDoJob;
833 void
834 GtkPrintDialog::updateControllerPrintRange()
836 GtkPrintSettings* const pSettings(getSettings());
837 // TODO: use get_print_pages
838 if (const gchar* const pStr = m_xWrapper->print_settings_get(pSettings, GTK_PRINT_SETTINGS_PRINT_PAGES))
840 beans::PropertyValue* pVal = m_rController.getValue(OUString("PrintRange"));
841 if (!pVal)
842 pVal = m_rController.getValue(OUString("PrintContent"));
843 SAL_WARN_IF(!pVal, "vcl.gtk", "Nothing to map standard print options to!");
844 if (pVal)
846 sal_Int32 nVal = 0;
847 if (!strcmp(pStr, "all"))
848 nVal = 0;
849 else if (!strcmp(pStr, "ranges"))
850 nVal = 1;
851 else if (!strcmp(pStr, "selection"))
852 nVal = 2;
853 pVal->Value <<= nVal;
855 if (nVal == 1)
857 pVal = m_rController.getValue(OUString("PageRange"));
858 SAL_WARN_IF(!pVal, "vcl.gtk", "PageRange doesn't exist!");
859 if (pVal)
861 OUStringBuffer sBuf;
862 gint num_ranges;
863 const GtkPageRange* const pRanges = m_xWrapper->print_settings_get_page_ranges(pSettings, &num_ranges);
864 for (gint i = 0; i != num_ranges && pRanges; ++i)
866 sBuf.append(sal_Int32(pRanges[i].start+1));
867 if (pRanges[i].start != pRanges[i].end)
869 sBuf.append('-');
870 sBuf.append(sal_Int32(pRanges[i].end+1));
873 if (i != num_ranges-1)
874 sBuf.append(',');
876 pVal->Value <<= sBuf.makeStringAndClear();
881 g_object_unref(G_OBJECT(pSettings));
884 GtkPrintDialog::~GtkPrintDialog()
886 gtk_widget_destroy(m_pDialog);
889 void
890 GtkPrintDialog::impl_readFromSettings()
892 vcl::SettingsConfigItem* const pItem(vcl::SettingsConfigItem::get());
893 GtkPrintSettings* const pSettings(getSettings());
895 const OUString aPrintDialogStr("PrintDialog");
896 const OUString aCopyCount(pItem->getValue(aPrintDialogStr,
897 "CopyCount"));
898 const OUString aCollate(pItem->getValue(aPrintDialogStr,
899 "Collate"));
901 const gint nOldCopyCount(m_xWrapper->print_settings_get_n_copies(pSettings));
902 const sal_Int32 nCopyCount(aCopyCount.toInt32());
903 if (nCopyCount > 0 && nOldCopyCount != nCopyCount)
905 m_xWrapper->print_settings_set_n_copies(pSettings, sal::static_int_cast<gint>(nCopyCount));
908 const bool bOldCollate(m_xWrapper->print_settings_get_collate(pSettings));
909 const bool bCollate(aCollate.equalsIgnoreAsciiCase("true"));
910 if (bOldCollate != bCollate)
912 m_xWrapper->print_settings_set_collate(pSettings, bCollate);
915 m_xWrapper->print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(m_pDialog), pSettings);
916 g_object_unref(G_OBJECT(pSettings));
919 void
920 GtkPrintDialog::impl_storeToSettings()
921 const
923 vcl::SettingsConfigItem* const pItem(vcl::SettingsConfigItem::get());
924 GtkPrintSettings* const pSettings(getSettings());
926 const OUString aPrintDialogStr("PrintDialog");
927 pItem->setValue(aPrintDialogStr,
928 "CopyCount",
929 OUString::number(m_xWrapper->print_settings_get_n_copies(pSettings)));
930 pItem->setValue(aPrintDialogStr,
931 "Collate",
932 m_xWrapper->print_settings_get_collate(pSettings)
933 ? OUString("true")
934 : OUString("false"))
936 // pItem->setValue(aPrintDialog, OUString("ToFile"), );
937 g_object_unref(G_OBJECT(pSettings));
938 pItem->Commit();
941 sal_uInt32
942 GtkSalInfoPrinter::GetCapabilities(
943 const ImplJobSetup* const i_pSetupData,
944 const PrinterCapType i_nType)
946 if (i_nType == PrinterCapType::ExternalDialog && lcl_useSystemPrintDialog())
947 return 1;
948 return PspSalInfoPrinter::GetCapabilities(i_pSetupData, i_nType);
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */