1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <o3tl/safeint.hxx>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
23 #include <rtl/ustrbuf.hxx>
24 #include <unotools/localedatawrapper.hxx>
25 #include <officecfg/Office/Common.hxx>
28 #include <vcl/QueueInfo.hxx>
29 #include <vcl/commandevent.hxx>
30 #include <vcl/decoview.hxx>
31 #include <vcl/help.hxx>
32 #include <vcl/naturalsort.hxx>
33 #include <vcl/print.hxx>
34 #include <vcl/printer/Options.hxx>
35 #include <vcl/settings.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/wall.hxx>
39 #include <vcl/weldutils.hxx>
40 #include <vcl/windowstate.hxx>
42 #include <bitmaps.hlst>
43 #include <configsettings.hxx>
44 #include <printdlg.hxx>
45 #include <strings.hrc>
48 #include <com/sun/star/beans/PropertyValue.hpp>
51 using namespace com::sun::star
;
52 using namespace com::sun::star::uno
;
53 using namespace com::sun::star::lang
;
54 using namespace com::sun::star::container
;
55 using namespace com::sun::star::beans
;
59 ORIENTATION_AUTOMATIC
,
65 bool lcl_ListBoxCompare( const OUString
& rStr1
, const OUString
& rStr2
)
67 return vcl::NaturalSortCompare( rStr1
, rStr2
) < 0;
71 PrintDialog::PrintPreviewWindow::PrintPreviewWindow(PrintDialog
* pDialog
)
73 , maOrigSize( 10, 10 )
74 , mnDPIX(Application::GetDefaultDevice()->GetDPIX())
75 , mnDPIY(Application::GetDefaultDevice()->GetDPIY())
76 , mbGreyscale( false )
80 PrintDialog::PrintPreviewWindow::~PrintPreviewWindow()
84 void PrintDialog::PrintPreviewWindow::Resize()
86 Size
aNewSize(GetOutputSizePixel());
87 tools::Long nTextHeight
= GetDrawingArea()->get_text_height();
88 // leave small space for decoration
89 aNewSize
.AdjustWidth( -(nTextHeight
+ 2) );
90 aNewSize
.AdjustHeight( -(nTextHeight
+ 2) );
94 // #i106435# catch corner case of Size(0,0)
95 Size
aOrigSize( maOrigSize
);
96 if( aOrigSize
.Width() < 1 )
97 aOrigSize
.setWidth( aNewSize
.Width() );
98 if( aOrigSize
.Height() < 1 )
99 aOrigSize
.setHeight( aNewSize
.Height() );
100 if( aOrigSize
.Width() > aOrigSize
.Height() )
102 aScaledSize
= Size( aNewSize
.Width(), aNewSize
.Width() * aOrigSize
.Height() / aOrigSize
.Width() );
103 if( aScaledSize
.Height() > aNewSize
.Height() )
104 fScale
= double(aNewSize
.Height())/double(aScaledSize
.Height());
108 aScaledSize
= Size( aNewSize
.Height() * aOrigSize
.Width() / aOrigSize
.Height(), aNewSize
.Height() );
109 if( aScaledSize
.Width() > aNewSize
.Width() )
110 fScale
= double(aNewSize
.Width())/double(aScaledSize
.Width());
112 aScaledSize
.setWidth( tools::Long(aScaledSize
.Width()*fScale
) );
113 aScaledSize
.setHeight( tools::Long(aScaledSize
.Height()*fScale
) );
115 maPreviewSize
= aScaledSize
;
117 // check and evtl. recreate preview bitmap
118 preparePreviewBitmap();
121 void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
123 rRenderContext
.Push();
124 weld::SetPointFont(rRenderContext
, rRenderContext
.GetSettings().GetStyleSettings().GetLabelFont());
126 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
127 rRenderContext
.Erase();
129 auto nTextHeight
= rRenderContext
.GetTextHeight();
130 Size
aSize(GetOutputSizePixel());
131 Point
aOffset((aSize
.Width() - maPreviewSize
.Width() + nTextHeight
) / 2,
132 (aSize
.Height() - maPreviewSize
.Height() + nTextHeight
) / 2);
136 auto nWidth
= rRenderContext
.GetTextWidth(maHorzText
);
138 auto nStart
= aOffset
.X() + (maPreviewSize
.Width() - nWidth
) / 2;
139 rRenderContext
.DrawText(Point(nStart
, aOffset
.Y() - nTextHeight
), maHorzText
, 0, maHorzText
.getLength());
141 DecorationView
aDecoView(&rRenderContext
);
142 auto nTop
= aOffset
.Y() - (nTextHeight
/ 2);
143 aDecoView
.DrawSeparator(Point(aOffset
.X(), nTop
), Point(nStart
- 2, nTop
), false);
144 aDecoView
.DrawSeparator(Point(nStart
+ nWidth
+ 2, nTop
), Point(aOffset
.X() + maPreviewSize
.Width(), nTop
), false);
149 rRenderContext
.Push(PushFlags::FONT
);
150 vcl::Font
aFont(rRenderContext
.GetFont());
151 aFont
.SetOrientation(900_deg10
);
152 rRenderContext
.SetFont(aFont
);
154 auto nLeft
= aOffset
.X() - nTextHeight
;
156 auto nWidth
= rRenderContext
.GetTextWidth(maVertText
);
157 auto nStart
= aOffset
.Y() + (maPreviewSize
.Height() + nWidth
) / 2;
159 rRenderContext
.DrawText(Point(nLeft
, nStart
), maVertText
, 0, maVertText
.getLength());
161 DecorationView
aDecoView(&rRenderContext
);
162 nLeft
= aOffset
.X() - (nTextHeight
/ 2);
163 aDecoView
.DrawSeparator(Point(nLeft
, aOffset
.Y()), Point(nLeft
, nStart
- nWidth
- 2), true);
164 aDecoView
.DrawSeparator(Point(nLeft
, nStart
+ 2), Point(nLeft
, aOffset
.Y() + maPreviewSize
.Height()), true);
166 rRenderContext
.Pop();
169 if (!maReplacementString
.isEmpty())
171 // replacement is active
172 tools::Rectangle
aTextRect(aOffset
+ Point(2, 2), Size(maPreviewSize
.Width() - 4, maPreviewSize
.Height() - 4));
173 rRenderContext
.DrawText(aTextRect
, maReplacementString
,
174 DrawTextFlags::Center
| DrawTextFlags::VCenter
|
175 DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
179 BitmapEx
aPreviewBitmap(maPreviewBitmap
);
181 // This explicit force-to-scale allows us to get the
182 // mentioned best quality here. Unfortunately this is
183 // currently not sure when using just ::DrawBitmap with
184 // a defined size or ::DrawOutDev
185 aPreviewBitmap
.Scale(maPreviewSize
, BmpScaleFlag::BestQuality
);
186 rRenderContext
.DrawBitmapEx(aOffset
, aPreviewBitmap
);
189 tools::Rectangle
aFrameRect(aOffset
+ Point(-1, -1), Size(maPreviewSize
.Width() + 2, maPreviewSize
.Height() + 2));
190 DecorationView
aDecorationView(&rRenderContext
);
191 aDecorationView
.DrawFrame(aFrameRect
, DrawFrameStyle::Group
);
193 rRenderContext
.Pop();
196 bool PrintDialog::PrintPreviewWindow::Command( const CommandEvent
& rEvt
)
198 if( rEvt
.GetCommand() == CommandEventId::Wheel
)
200 const CommandWheelData
* pWheelData
= rEvt
.GetWheelData();
201 if(pWheelData
->GetDelta() > 0)
202 mpDialog
->previewForward();
203 else if (pWheelData
->GetDelta() < 0)
204 mpDialog
->previewBackward();
207 return CustomWidgetController::Command(rEvt
);
210 void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile
& i_rNewPreview
,
211 const Size
& i_rOrigSize
,
212 std::u16string_view i_rPaperName
,
213 const OUString
& i_rReplacement
,
219 maMtf
= i_rNewPreview
;
222 maOrigSize
= i_rOrigSize
;
223 maReplacementString
= i_rReplacement
;
224 mbGreyscale
= i_bGreyscale
;
226 // use correct measurements
227 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
228 o3tl::Length eUnit
= o3tl::Length::mm
;
230 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
232 eUnit
= o3tl::Length::in100
;
235 Size
aLogicPaperSize(o3tl::convert(i_rOrigSize
, o3tl::Length::mm100
, eUnit
));
236 OUString
aNumText( rLocWrap
.getNum( aLogicPaperSize
.Width(), nDigits
) );
237 OUStringBuffer
aBuf( aNumText
+ " " );
238 aBuf
.appendAscii( eUnit
== o3tl::Length::mm
? "mm" : "in" );
239 if( !i_rPaperName
.empty() )
241 aBuf
.append( OUString::Concat(" (") + i_rPaperName
+ ")" );
243 maHorzText
= aBuf
.makeStringAndClear();
245 aNumText
= rLocWrap
.getNum( aLogicPaperSize
.Height(), nDigits
);
246 aBuf
.append( aNumText
+ " " );
247 aBuf
.appendAscii( eUnit
== o3tl::Length::mm
? "mm" : "in" );
248 maVertText
= aBuf
.makeStringAndClear();
250 // We have a new Metafile and evtl. a new page, so we need to reset
251 // the PreviewBitmap to force new creation
252 maPreviewBitmap
= Bitmap();
254 // sets/calculates e.g. maPreviewSize
255 // also triggers preparePreviewBitmap()
261 void PrintDialog::PrintPreviewWindow::preparePreviewBitmap()
263 if(maPreviewSize
.IsEmpty())
265 // not yet fully initialized, no need to prepare anything
269 // define an allowed number of pixels, also see
270 // defaults for primitive renderers and similar. This
271 // might be centralized and made dependent of 32/64bit
272 const sal_uInt32
nMaxSquarePixels(500000);
274 // check how big (squarePixels) the preview is currently (with
275 // max value of MaxSquarePixels)
276 const sal_uInt32
nCurrentSquarePixels(
279 static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getWidth())
280 * static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getHeight())));
282 // check how big (squarePixels) the preview needs to be (with
283 // max value of MaxSquarePixels)
284 const sal_uInt32
nRequiredSquarePixels(
287 static_cast<sal_uInt32
>(maPreviewSize
.getWidth())
288 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight())));
290 // check if preview is big enough. Use a scaling value in
291 // the comparison to not get bigger at the last possible moment
292 // what may look awkward and pixelated (again). This means
293 // to use a percentage value - if we have at least
294 // that value of required pixels, we are good.
295 static const double fPreventAwkwardFactor(1.35); // 35%
296 if(nCurrentSquarePixels
>= static_cast<sal_uInt32
>(nRequiredSquarePixels
* fPreventAwkwardFactor
))
298 // at this place we also could add a mechanism to let the preview
299 // bitmap 'shrink' again if it is currently 'too big' -> bigger
300 // than required. I think this is not necessary for now.
302 // already sufficient, done.
306 // check if we have enough square pixels e.g for 8x8 pixels
307 if(nRequiredSquarePixels
< 64)
309 // too small preview - let it empty
313 // Calculate nPlannedSquarePixels which is the required size
314 // expanded by a percentage (with max value of MaxSquarePixels)
315 static const double fExtraSpaceFactor(1.65); // 65%
316 const sal_uInt32
nPlannedSquarePixels(
319 static_cast<sal_uInt32
>(maPreviewSize
.getWidth() * fExtraSpaceFactor
)
320 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight() * fExtraSpaceFactor
)));
322 // calculate back new width and height - it might have been
323 // truncated by MaxSquarePixels.
324 // We know that w*h == nPlannedSquarePixels and w/h == ratio
325 const double fRatio(static_cast<double>(maPreviewSize
.getWidth()) / static_cast<double>(maPreviewSize
.getHeight()));
326 const double fNewWidth(sqrt(static_cast<double>(nPlannedSquarePixels
) * fRatio
));
327 const double fNewHeight(sqrt(static_cast<double>(nPlannedSquarePixels
) / fRatio
));
328 const Size
aScaledSize(basegfx::fround(fNewWidth
), basegfx::fround(fNewHeight
));
330 // check if this eventual maximum is already reached
331 // due to having hit the MaxSquarePixels. Due to using
332 // an integer AspectRatio, we cannot make a numeric exact
333 // comparison - we need to compare if we are close
334 const double fScaledSizeSquare(static_cast<double>(aScaledSize
.getWidth() * aScaledSize
.getHeight()));
335 const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap
.GetSizePixel().getWidth() * maPreviewBitmap
.GetSizePixel().getHeight()));
337 // test as equal up to 0.1% (0.001)
338 if(fPreviewSizeSquare
!= 0.0 && fabs((fScaledSizeSquare
/ fPreviewSizeSquare
) - 1.0) < 0.001)
340 // maximum is reached, avoid bigger scaling
344 // create temporary VDev with requested Size and DPI.
345 // CAUTION: DPI *is* important here - it DIFFERS from 75x75, usually 600x600 is used
346 ScopedVclPtrInstance
<VirtualDevice
> pPrerenderVDev(*Application::GetDefaultDevice());
347 pPrerenderVDev
->SetOutputSizePixel(aScaledSize
, false);
348 pPrerenderVDev
->SetReferenceDevice( mnDPIX
, mnDPIY
);
350 // calculate needed Scale for Metafile (using Size and DPI from VDev)
351 Size
aLogicSize( pPrerenderVDev
->PixelToLogic( pPrerenderVDev
->GetOutputSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
352 Size
aOrigSize( maOrigSize
);
353 if( aOrigSize
.Width() < 1 )
354 aOrigSize
.setWidth( aLogicSize
.Width() );
355 if( aOrigSize
.Height() < 1 )
356 aOrigSize
.setHeight( aLogicSize
.Height() );
357 double fScale
= double(aLogicSize
.Width())/double(aOrigSize
.Width());
360 // The display quality of the Preview is pretty ugly when
361 // FormControls are used. I made a deep-dive why this happens,
362 // and in principle the reason is the Mteafile::Scale used
363 // below. Since Metafile actions are integer, that floating point
364 // scale leads to rounding errors that make the lines painting
365 // the FormControls disappear in the surrounding ClipRegions.
366 // That Scale cannot be avoided since the Metafile contains it's
367 // own SetMapMode commands which *will* be executed on ::Play,
368 // so the ::Scale is the only possibility fr Metafile currently:
369 // Giving a Size as parameter in ::Play will *not* work due to
370 // the relativeMapMode that gets created will fail on
371 // ::SetMapMode actions in the Metafile - and FormControls DO
372 // use ::SetMapMode(MapPixel).
373 // This can only be solved better in the future using Primitives
374 // which would allow any scale by embedding to a Transformation,
375 // but that would be a bigger rework.
376 // Until then, use this little 'trick' to improve quality.
377 // It uses the fact to empirically having tested that the quality
378 // gets really bad for FormControls starting by a scale factor
379 // smaller than 0.2 - that makes the ClipRegion overlap start.
380 // So - for now - try not to go below that.
381 static const double fMinimumScale(0.2);
383 if(fScale
< fMinimumScale
)
385 fFactor
= fMinimumScale
/ fScale
;
386 fScale
= fMinimumScale
;
388 double fWidth(aScaledSize
.getWidth() * fFactor
);
389 double fHeight(aScaledSize
.getHeight() * fFactor
);
390 const double fNewNeededPixels(fWidth
* fHeight
);
392 // to not risk using too big bitmaps and running into
393 // memory problems, still limit to a useful factor is
394 // necessary, also empirically estimated to
395 // avoid the quality from collapsing (using a direct
396 // in-between , ceil'd result)
397 static const double fMaximumQualitySquare(1396221.0);
399 if(fNewNeededPixels
> fMaximumQualitySquare
)
401 const double fCorrection(fMaximumQualitySquare
/fNewNeededPixels
);
402 fWidth
*= fCorrection
;
403 fHeight
*= fCorrection
;
404 fScale
*= fCorrection
;
407 const Size
aScaledSize2(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
408 pPrerenderVDev
->SetOutputSizePixel(aScaledSize2
, false);
409 aLogicSize
= pPrerenderVDev
->PixelToLogic( aScaledSize2
, MapMode( MapUnit::Map100thMM
) );
412 pPrerenderVDev
->EnableOutput();
413 pPrerenderVDev
->SetBackground( Wallpaper(COL_WHITE
) );
414 pPrerenderVDev
->Erase();
415 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
417 pPrerenderVDev
->SetDrawMode( pPrerenderVDev
->GetDrawMode() |
418 ( DrawModeFlags::GrayLine
| DrawModeFlags::GrayFill
| DrawModeFlags::GrayText
|
419 DrawModeFlags::GrayBitmap
| DrawModeFlags::GrayGradient
) );
421 // Copy, Scale and Paint Metafile
422 GDIMetaFile
aMtf( maMtf
);
424 aMtf
.Scale( fScale
, fScale
);
426 aMtf
.Play(*pPrerenderVDev
, Point(0, 0), aLogicSize
);
428 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
429 maPreviewBitmap
= pPrerenderVDev
->GetBitmapEx(Point(0, 0), pPrerenderVDev
->GetOutputSizePixel());
433 // Correct to needed size, BmpScaleFlag::Interpolate is acceptable,
434 // but BmpScaleFlag::BestQuality is just better. In case of time
435 // constraints, change to Interpolate would be possible
436 maPreviewBitmap
.Scale(aScaledSize
, BmpScaleFlag::BestQuality
);
440 PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow()
441 : mnOrderMode( NupOrderType::LRTB
)
447 void PrintDialog::ShowNupOrderWindow::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
450 pDrawingArea
->set_size_request(aSize
.Width(), aSize
.Height());
451 CustomWidgetController::SetDrawingArea(pDrawingArea
);
452 SetOutputSizePixel(aSize
);
455 void PrintDialog::ShowNupOrderWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& /*i_rRect*/)
457 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
458 rRenderContext
.SetTextColor(rRenderContext
.GetSettings().GetStyleSettings().GetFieldTextColor());
459 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFieldColor()));
460 rRenderContext
.Erase();
462 int nPages
= mnRows
* mnColumns
;
463 Font
aFont(rRenderContext
.GetSettings().GetStyleSettings().GetFieldFont());
464 aFont
.SetFontSize(Size(0, 24));
465 rRenderContext
.SetFont(aFont
);
466 Size
aSampleTextSize(rRenderContext
.GetTextWidth(OUString::number(nPages
+ 1)), rRenderContext
.GetTextHeight());
467 Size
aOutSize(GetOutputSizePixel());
468 Size
aSubSize(aOutSize
.Width() / mnColumns
, aOutSize
.Height() / mnRows
);
469 // calculate font size: shrink the sample text so it fits
470 double fX
= double(aSubSize
.Width()) / double(aSampleTextSize
.Width());
471 double fY
= double(aSubSize
.Height()) / double(aSampleTextSize
.Height());
472 double fScale
= (fX
< fY
) ? fX
: fY
;
473 tools::Long nFontHeight
= tools::Long(24.0 * fScale
) - 3;
476 aFont
.SetFontSize(Size( 0, nFontHeight
));
477 rRenderContext
.SetFont(aFont
);
478 tools::Long nTextHeight
= rRenderContext
.GetTextHeight();
479 for (int i
= 0; i
< nPages
; i
++)
481 OUString
aPageText(OUString::number(i
+ 1));
485 case NupOrderType::LRTB
:
486 nX
= (i
% mnColumns
);
487 nY
= (i
/ mnColumns
);
489 case NupOrderType::TBLR
:
493 case NupOrderType::RLTB
:
494 nX
= mnColumns
- 1 - (i
% mnColumns
);
495 nY
= (i
/ mnColumns
);
497 case NupOrderType::TBRL
:
498 nX
= mnColumns
- 1 - (i
/ mnRows
);
502 Size
aTextSize(rRenderContext
.GetTextWidth(aPageText
), nTextHeight
);
503 int nDeltaX
= (aSubSize
.Width() - aTextSize
.Width()) / 2;
504 int nDeltaY
= (aSubSize
.Height() - aTextSize
.Height()) / 2;
505 rRenderContext
.DrawText(Point(nX
* aSubSize
.Width() + nDeltaX
,
506 nY
* aSubSize
.Height() + nDeltaY
), aPageText
);
508 DecorationView
aDecorationView(&rRenderContext
);
509 aDecorationView
.DrawFrame(tools::Rectangle(Point(0, 0), aOutSize
), DrawFrameStyle::Group
);
512 Size
const & PrintDialog::getJobPageSize()
514 if( maFirstPageSize
.IsEmpty() )
516 maFirstPageSize
= maNupPortraitSize
;
518 if( maPController
->getPageCountProtected() > 0 )
520 PrinterController::PageSize aPageSize
= maPController
->getPageFile( 0, aMtf
, true );
521 maFirstPageSize
= aPageSize
.aSize
;
524 return maFirstPageSize
;
527 PrintDialog::PrintDialog(weld::Window
* i_pWindow
, std::shared_ptr
<PrinterController
> i_xController
)
528 : GenericDialogController(i_pWindow
, "vcl/ui/printdialog.ui", "PrintDialog")
529 , maPController(std::move( i_xController
))
530 , mxTabCtrl(m_xBuilder
->weld_notebook("tabcontrol"))
531 , mxScrolledWindow(m_xBuilder
->weld_scrolled_window("scrolledwindow"))
532 , mxPageLayoutFrame(m_xBuilder
->weld_frame("layoutframe"))
533 , mxPrinters(m_xBuilder
->weld_combo_box("printersbox"))
534 , mxStatusTxt(m_xBuilder
->weld_label("status"))
535 , mxSetupButton(m_xBuilder
->weld_button("setup"))
536 , mxCopyCountField(m_xBuilder
->weld_spin_button("copycount"))
537 , mxCollateBox(m_xBuilder
->weld_check_button("collate"))
538 , mxCollateImage(m_xBuilder
->weld_image("collateimage"))
539 , mxPageRangeEdit(m_xBuilder
->weld_entry("pagerange"))
540 , mxPageRangesRadioButton(m_xBuilder
->weld_radio_button("rbRangePages"))
541 , mxPaperSidesBox(m_xBuilder
->weld_combo_box("sidesbox"))
542 , mxSingleJobsBox(m_xBuilder
->weld_check_button("singlejobs"))
543 , mxReverseOrderBox(m_xBuilder
->weld_check_button("reverseorder"))
544 , mxOKButton(m_xBuilder
->weld_button("ok"))
545 , mxCancelButton(m_xBuilder
->weld_button("cancel"))
546 , mxHelpButton(m_xBuilder
->weld_button("help"))
547 , mxBackwardBtn(m_xBuilder
->weld_button("backward"))
548 , mxForwardBtn(m_xBuilder
->weld_button("forward"))
549 , mxFirstBtn(m_xBuilder
->weld_button("btnFirst"))
550 , mxLastBtn(m_xBuilder
->weld_button("btnLast"))
551 , mxPreviewBox(m_xBuilder
->weld_check_button("previewbox"))
552 , mxNumPagesText(m_xBuilder
->weld_label("totalnumpages"))
553 , mxPreview(new PrintPreviewWindow(this))
554 , mxPreviewWindow(new weld::CustomWeld(*m_xBuilder
, "preview", *mxPreview
))
555 , mxPageEdit(m_xBuilder
->weld_entry("pageedit"))
556 , mxPagesBtn(m_xBuilder
->weld_radio_button("pagespersheetbtn"))
557 , mxBrochureBtn(m_xBuilder
->weld_radio_button("brochure"))
558 , mxPagesBoxTitleTxt(m_xBuilder
->weld_label("pagespersheettxt"))
559 , mxNupPagesBox(m_xBuilder
->weld_combo_box("pagespersheetbox"))
560 , mxNupNumPagesTxt(m_xBuilder
->weld_label("pagestxt"))
561 , mxNupColEdt(m_xBuilder
->weld_spin_button("pagecols"))
562 , mxNupTimesTxt(m_xBuilder
->weld_label("by"))
563 , mxNupRowsEdt(m_xBuilder
->weld_spin_button("pagerows"))
564 , mxPageMarginTxt1(m_xBuilder
->weld_label("pagemargintxt1"))
565 , mxPageMarginEdt(m_xBuilder
->weld_metric_spin_button("pagemarginsb", FieldUnit::MM
))
566 , mxPageMarginTxt2(m_xBuilder
->weld_label("pagemargintxt2"))
567 , mxSheetMarginTxt1(m_xBuilder
->weld_label("sheetmargintxt1"))
568 , mxSheetMarginEdt(m_xBuilder
->weld_metric_spin_button("sheetmarginsb", FieldUnit::MM
))
569 , mxSheetMarginTxt2(m_xBuilder
->weld_label("sheetmargintxt2"))
570 , mxPaperSizeBox(m_xBuilder
->weld_combo_box("papersizebox"))
571 , mxOrientationBox(m_xBuilder
->weld_combo_box("pageorientationbox"))
572 , mxNupOrderTxt(m_xBuilder
->weld_label("labelorder"))
573 , mxNupOrderBox(m_xBuilder
->weld_combo_box("orderbox"))
574 , mxNupOrder(new ShowNupOrderWindow
)
575 , mxNupOrderWin(new weld::CustomWeld(*m_xBuilder
, "orderpreview", *mxNupOrder
))
576 , mxBorderCB(m_xBuilder
->weld_check_button("bordercb"))
577 , mxRangeExpander(m_xBuilder
->weld_expander("exRangeExpander"))
578 , mxLayoutExpander(m_xBuilder
->weld_expander("exLayoutExpander"))
579 , mxCustom(m_xBuilder
->weld_widget("customcontents"))
580 , maPrintToFileText( VclResId( SV_PRINT_TOFILE_TXT
) )
581 , maDefPrtText( VclResId( SV_PRINT_DEFPRT_TXT
) )
582 , maNoPageStr( VclResId( SV_PRINT_NOPAGES
) )
583 , maNoPreviewStr( VclResId( SV_PRINT_NOPREVIEW
) )
586 , mbCollateAlwaysOff(false)
587 , mbShowLayoutFrame( true )
588 , maUpdatePreviewIdle("Print Dialog Update Preview Idle")
589 , maUpdatePreviewNoCacheIdle("Print Dialog Update Preview (no cache) Idle")
591 // save printbutton text, gets exchanged occasionally with print to file
592 maPrintText
= mxOKButton
->get_label();
594 maPageStr
= mxNumPagesText
->get_label();
596 Printer::updatePrinters();
598 mxPrinters
->append_text(maPrintToFileText
);
599 // fill printer listbox
600 std::vector
< OUString
> rQueues( Printer::GetPrinterQueues() );
601 std::sort( rQueues
.begin(), rQueues
.end(), lcl_ListBoxCompare
);
602 for( const auto& rQueue
: rQueues
)
604 mxPrinters
->append_text(rQueue
);
606 // select current printer
607 if (mxPrinters
->find_text(maPController
->getPrinter()->GetName()) != -1)
608 mxPrinters
->set_active_text(maPController
->getPrinter()->GetName());
611 // fall back to last printer
612 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
613 OUString
aValue( pItem
->getValue( "PrintDialog",
615 if (mxPrinters
->find_text(aValue
) != -1)
617 mxPrinters
->set_active_text(aValue
);
618 maPController
->setPrinter( VclPtrInstance
<Printer
>( aValue
) );
622 // fall back to default printer
623 mxPrinters
->set_active_text(Printer::GetDefaultPrinterName());
624 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
628 // not printing to file
629 maPController
->resetPrinterOptions( false );
631 // update the text fields for the printer
634 // setup dependencies
635 checkControlDependencies();
637 // setup paper sides box
638 setupPaperSidesBox();
640 // set initial focus to "Number of copies"
641 mxCopyCountField
->grab_focus();
642 mxCopyCountField
->select_region(0, -1);
644 // setup sizes for N-Up
645 Size
aNupSize( maPController
->getPrinter()->PixelToLogic(
646 maPController
->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
647 if( maPController
->getPrinter()->GetOrientation() == Orientation::Landscape
)
649 maNupLandscapeSize
= aNupSize
;
650 // coverity[swapped_arguments : FALSE] - this is in the correct order
651 maNupPortraitSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
655 maNupPortraitSize
= aNupSize
;
656 // coverity[swapped_arguments : FALSE] - this is in the correct order
657 maNupLandscapeSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
660 maUpdatePreviewIdle
.SetPriority(TaskPriority::POST_PAINT
);
661 maUpdatePreviewIdle
.SetInvokeHandler(LINK( this, PrintDialog
, updatePreviewIdle
));
662 maUpdatePreviewNoCacheIdle
.SetPriority(TaskPriority::POST_PAINT
);
663 maUpdatePreviewNoCacheIdle
.SetInvokeHandler(LINK(this, PrintDialog
, updatePreviewNoCacheIdle
));
665 initFromMultiPageSetup( maPController
->getMultipage() );
667 // setup optional UI options set by application
670 // hide layout frame if unwanted
671 mxPageLayoutFrame
->set_visible(mbShowLayoutFrame
);
673 // restore settings from last run
677 mxOKButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
678 mxCancelButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
679 mxHelpButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
680 mxSetupButton
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
681 mxBackwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
682 mxForwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
683 mxFirstBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
684 mxLastBtn
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
687 mxReverseOrderBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
688 mxCollateBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
689 mxSingleJobsBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
690 mxBrochureBtn
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
691 mxPreviewBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
692 mxBorderCB
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
695 mxPrinters
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
696 mxPaperSidesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
697 mxNupPagesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
698 mxOrientationBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
699 mxNupOrderBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
700 mxPaperSizeBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
703 mxPageEdit
->connect_activate( LINK( this, PrintDialog
, ActivateHdl
) );
704 mxPageEdit
->connect_focus_out( LINK( this, PrintDialog
, FocusOutHdl
) );
705 mxCopyCountField
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
706 mxNupColEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
707 mxNupRowsEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
708 mxPageMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
709 mxSheetMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
711 updateNupFromPages();
713 // tdf#129180 Delay setting the default value in the Paper Size list
714 // set paper sizes listbox
717 mxRangeExpander
->set_expanded(
718 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::get());
719 mxLayoutExpander
->set_expanded(
720 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::get());
722 // lock the dialog height, regardless of later expander state
723 mxScrolledWindow
->set_size_request(
724 mxScrolledWindow
->get_preferred_size().Width() + mxScrolledWindow
->get_scroll_thickness(),
727 m_xDialog
->set_centered_on_parent(true);
730 PrintDialog::~PrintDialog()
732 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
733 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::set(mxRangeExpander
->get_expanded(), batch
);
734 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::set(mxLayoutExpander
->get_expanded(), batch
);
738 void PrintDialog::setupPaperSidesBox()
740 DuplexMode eDuplex
= maPController
->getPrinter()->GetDuplexMode();
742 if ( eDuplex
== DuplexMode::Unknown
|| isPrintToFile() )
744 mxPaperSidesBox
->set_active( 0 );
745 mxPaperSidesBox
->set_sensitive( false );
749 mxPaperSidesBox
->set_active( static_cast<sal_Int32
>(eDuplex
) - 1 );
750 mxPaperSidesBox
->set_sensitive( true );
754 void PrintDialog::storeToSettings()
756 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
758 pItem
->setValue( "PrintDialog",
760 isPrintToFile() ? Printer::GetDefaultPrinterName()
761 : mxPrinters
->get_active_text() );
763 pItem
->setValue( "PrintDialog",
765 mxTabCtrl
->get_tab_label_text(mxTabCtrl
->get_current_page_ident()));
767 pItem
->setValue( "PrintDialog",
769 m_xDialog
->get_window_state(vcl::WindowDataMask::All
) );
771 pItem
->setValue( "PrintDialog",
773 mxCopyCountField
->get_text() );
775 pItem
->setValue( "PrintDialog",
777 mxCollateBox
->get_active() ? OUString("true") :
780 pItem
->setValue( "PrintDialog",
782 mxSingleJobsBox
->get_active() ? OUString("true") :
785 pItem
->setValue( "PrintDialog",
787 hasPreview() ? OUString("true") :
793 void PrintDialog::readFromSettings()
795 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
797 // read last selected tab page; if it exists, activate it
798 OUString aValue
= pItem
->getValue( "PrintDialog",
800 sal_uInt16 nCount
= mxTabCtrl
->get_n_pages();
801 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
803 OUString sPageId
= mxTabCtrl
->get_page_ident(i
);
804 if (aValue
== mxTabCtrl
->get_tab_label_text(sPageId
))
806 mxTabCtrl
->set_current_page(sPageId
);
811 // persistent window state
812 aValue
= pItem
->getValue( "PrintDialog",
814 if (!aValue
.isEmpty())
815 m_xDialog
->set_window_state(aValue
);
818 aValue
= pItem
->getValue( "PrintDialog",
820 if( aValue
.equalsIgnoreAsciiCase("alwaysoff") )
822 mbCollateAlwaysOff
= true;
823 mxCollateBox
->set_active( false );
824 mxCollateBox
->set_sensitive( false );
828 mbCollateAlwaysOff
= false;
829 aValue
= pItem
->getValue( "PrintDialog",
831 mxCollateBox
->set_active( aValue
.equalsIgnoreAsciiCase("true") );
834 // collate single jobs
835 aValue
= pItem
->getValue( "PrintDialog",
836 "CollateSingleJobs" );
837 mxSingleJobsBox
->set_active(aValue
.equalsIgnoreAsciiCase("true"));
840 aValue
= pItem
->getValue( "PrintDialog",
842 if ( aValue
.equalsIgnoreAsciiCase("false") )
843 mxPreviewBox
->set_active( false );
845 mxPreviewBox
->set_active( true );
849 void PrintDialog::setPaperSizes()
851 mxPaperSizeBox
->clear();
853 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
854 mePaper
= aPrt
->GetPaper();
856 if ( isPrintToFile() )
858 mxPaperSizeBox
->set_sensitive( false );
862 Size aSizeOfPaper
= aPrt
->GetSizeOfPaper();
863 PaperInfo
aPaperInfo(aSizeOfPaper
.getWidth(), aSizeOfPaper
.getHeight());
864 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
865 o3tl::Length eUnit
= o3tl::Length::mm
;
867 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
869 eUnit
= o3tl::Length::in100
;
872 for (int nPaper
= 0; nPaper
< aPrt
->GetPaperInfoCount(); nPaper
++)
874 PaperInfo aInfo
= aPrt
->GetPaperInfo( nPaper
);
875 aInfo
.doSloppyFit(true);
876 Paper ePaper
= aInfo
.getPaper();
878 Size aSize
= aPrt
->GetPaperSize( nPaper
);
879 Size
aLogicPaperSize( o3tl::convert(aSize
, o3tl::Length::mm100
, eUnit
) );
881 OUString
aWidth( rLocWrap
.getNum( aLogicPaperSize
.Width(), nDigits
) );
882 OUString
aHeight( rLocWrap
.getNum( aLogicPaperSize
.Height(), nDigits
) );
883 OUString aUnit
= eUnit
== o3tl::Length::mm
? OUString("mm") : OUString("in");
886 // Paper sizes that we don't know of but the system printer driver lists are not "User
887 // Defined". Displaying them as such is just confusing.
888 if (ePaper
!= PAPER_USER
)
889 aPaperName
= Printer::GetPaperName( ePaper
) + " ";
891 aPaperName
+= aWidth
+ aUnit
+ " x " + aHeight
+ aUnit
;
893 mxPaperSizeBox
->append_text(aPaperName
);
895 if ( (ePaper
!= PAPER_USER
&& ePaper
== mePaper
) ||
896 (ePaper
== PAPER_USER
&& aInfo
.sloppyEqual(aPaperInfo
) ) )
897 mxPaperSizeBox
->set_active( nPaper
);
900 mxPaperSizeBox
->set_sensitive( true );
904 void PrintDialog::updatePrinterText()
906 const OUString
aDefPrt( Printer::GetDefaultPrinterName() );
907 const QueueInfo
* pInfo
= Printer::GetQueueInfo( mxPrinters
->get_active_text(), true );
910 // FIXME: status text
912 if( aDefPrt
== pInfo
->GetPrinterName() )
913 aStatus
= maDefPrtText
;
914 mxStatusTxt
->set_label( aStatus
);
918 mxStatusTxt
->set_label( OUString() );
922 void PrintDialog::setPreviewText()
924 OUString
aNewText( maPageStr
.replaceFirst( "%n", OUString::number( mnCachedPages
) ) );
925 mxNumPagesText
->set_label( aNewText
);
928 IMPL_LINK_NOARG(PrintDialog
, updatePreviewIdle
, Timer
*, void)
930 preparePreview(true);
933 IMPL_LINK_NOARG(PrintDialog
, updatePreviewNoCacheIdle
, Timer
*, void)
935 preparePreview(false);
938 void PrintDialog::preparePreview( bool i_bMayUseCache
)
940 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
941 Size aCurPageSize
= aPrt
->PixelToLogic( aPrt
->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) );
942 // tdf#123076 Get paper size for the preview top label
943 mePaper
= aPrt
->GetPaper();
946 // page range may have changed depending on options
947 sal_Int32 nPages
= maPController
->getFilteredPageCount();
948 mnCachedPages
= nPages
;
954 mxPreview
->setPreview( aMtf
, aCurPageSize
,
955 Printer::GetPaperName( mePaper
),
957 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
958 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
961 mxForwardBtn
->set_sensitive( false );
962 mxBackwardBtn
->set_sensitive( false );
963 mxFirstBtn
->set_sensitive( false );
964 mxLastBtn
->set_sensitive( false );
966 mxPageEdit
->set_sensitive( false );
971 if( mnCurPage
>= nPages
)
972 mnCurPage
= nPages
-1;
975 mxPageEdit
->set_text(OUString::number(mnCurPage
+ 1));
979 PrinterController::PageSize aPageSize
=
980 maPController
->getFilteredPageFile( mnCurPage
, aMtf
, i_bMayUseCache
);
981 aCurPageSize
= aPrt
->PixelToLogic(aPrt
->GetPaperSizePixel(), MapMode(MapUnit::Map100thMM
));
982 if( ! aPageSize
.bFullPaper
)
984 const MapMode
aMapMode( MapUnit::Map100thMM
);
985 Point
aOff( aPrt
->PixelToLogic( aPrt
->GetPageOffsetPixel(), aMapMode
) );
986 aMtf
.Move( aOff
.X(), aOff
.Y() );
988 // tdf#150561: page size may have changed so sync mePaper with it
989 mePaper
= aPrt
->GetPaper();
992 mxPreview
->setPreview( aMtf
, aCurPageSize
,
993 Printer::GetPaperName( mePaper
),
994 nPages
> 0 ? OUString() : maNoPageStr
,
995 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
996 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
999 mxForwardBtn
->set_sensitive( mnCurPage
< nPages
-1 );
1000 mxBackwardBtn
->set_sensitive( mnCurPage
!= 0 );
1001 mxFirstBtn
->set_sensitive( mnCurPage
!= 0 );
1002 mxLastBtn
->set_sensitive( mnCurPage
< nPages
-1 );
1003 mxPageEdit
->set_sensitive( nPages
> 1 );
1006 void PrintDialog::updateOrientationBox( const bool bAutomatic
)
1010 Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1011 mxOrientationBox
->set_active( static_cast<sal_Int32
>(eOrientation
) + 1 );
1013 else if ( hasOrientationChanged() )
1015 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1019 bool PrintDialog::hasOrientationChanged() const
1021 const int nOrientation
= mxOrientationBox
->get_active();
1022 const Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1024 return (nOrientation
== ORIENTATION_LANDSCAPE
&& eOrientation
== Orientation::Portrait
)
1025 || (nOrientation
== ORIENTATION_PORTRAIT
&& eOrientation
== Orientation::Landscape
);
1028 // Always use this function to set paper orientation to make sure everything behaves well
1029 void PrintDialog::setPaperOrientation( Orientation eOrientation
, bool fromUser
)
1031 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1032 aPrt
->SetOrientation( eOrientation
);
1033 maPController
->setOrientationFromUser( eOrientation
, fromUser
);
1036 void PrintDialog::checkControlDependencies()
1038 if (mxCopyCountField
->get_value() > 1)
1040 mxCollateBox
->set_sensitive( !mbCollateAlwaysOff
);
1041 mxSingleJobsBox
->set_sensitive( mxCollateBox
->get_active() );
1045 mxCollateBox
->set_sensitive( false );
1046 mxSingleJobsBox
->set_sensitive( false );
1049 OUString
aImg(mxCollateBox
->get_active() ? OUString(SV_PRINT_COLLATE_BMP
) : OUString(SV_PRINT_NOCOLLATE_BMP
));
1051 mxCollateImage
->set_from_icon_name(aImg
);
1053 // enable setup button only for printers that can be setup
1054 bool bHaveSetup
= maPController
->getPrinter()->HasSupport( PrinterSupport::SetupDialog
);
1055 mxSetupButton
->set_sensitive(bHaveSetup
);
1058 void PrintDialog::checkOptionalControlDependencies()
1060 for( const auto& rEntry
: maControlToPropertyMap
)
1062 bool bShouldbeEnabled
= maPController
->isUIOptionEnabled( rEntry
.second
);
1064 if (bShouldbeEnabled
&& dynamic_cast<weld::RadioButton
*>(rEntry
.first
))
1066 auto r_it
= maControlToNumValMap
.find( rEntry
.first
);
1067 if( r_it
!= maControlToNumValMap
.end() )
1069 bShouldbeEnabled
= maPController
->isUIChoiceEnabled( rEntry
.second
, r_it
->second
);
1073 bool bIsEnabled
= rEntry
.first
->get_sensitive();
1074 // Enable does not do a change check first, so can be less cheap than expected
1075 if (bShouldbeEnabled
!= bIsEnabled
)
1076 rEntry
.first
->set_sensitive( bShouldbeEnabled
);
1080 void PrintDialog::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup
& i_rMPS
)
1082 mxNupOrderWin
->show();
1083 mxPagesBtn
->set_active(true);
1084 mxBrochureBtn
->hide();
1086 // setup field units for metric fields
1087 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
1088 FieldUnit eUnit
= FieldUnit::MM
;
1089 sal_uInt16 nDigits
= 0;
1090 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
1092 eUnit
= FieldUnit::INCH
;
1096 mxPageMarginEdt
->set_unit( eUnit
);
1097 mxSheetMarginEdt
->set_unit( eUnit
);
1100 mxPageMarginEdt
->set_digits( nDigits
);
1101 mxSheetMarginEdt
->set_digits( nDigits
);
1103 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( i_rMPS
.nLeftMargin
), FieldUnit::MM_100TH
);
1104 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( i_rMPS
.nHorizontalSpacing
), FieldUnit::MM_100TH
);
1105 mxBorderCB
->set_active( i_rMPS
.bDrawBorder
);
1106 mxNupRowsEdt
->set_value( i_rMPS
.nRows
);
1107 mxNupColEdt
->set_value( i_rMPS
.nColumns
);
1108 mxNupOrderBox
->set_active( static_cast<sal_Int32
>(i_rMPS
.nOrder
) );
1109 if( i_rMPS
.nRows
!= 1 || i_rMPS
.nColumns
!= 1 )
1111 mxNupPagesBox
->set_active( mxNupPagesBox
->get_count()-1 );
1112 showAdvancedControls( true );
1113 mxNupOrder
->setValues( i_rMPS
.nOrder
, i_rMPS
.nColumns
, i_rMPS
.nRows
);
1117 void PrintDialog::updateNup( bool i_bMayUseCache
)
1119 int nRows
= mxNupRowsEdt
->get_value();
1120 int nCols
= mxNupColEdt
->get_value();
1121 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1122 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1124 PrinterController::MultiPageSetup aMPS
;
1126 aMPS
.nColumns
= nCols
;
1130 aMPS
.nBottomMargin
= nSheetMargin
;
1132 aMPS
.nHorizontalSpacing
=
1133 aMPS
.nVerticalSpacing
= nPageMargin
;
1135 aMPS
.bDrawBorder
= mxBorderCB
->get_active();
1137 aMPS
.nOrder
= static_cast<NupOrderType
>(mxNupOrderBox
->get_active());
1139 int nOrientationMode
= mxOrientationBox
->get_active();
1140 if( nOrientationMode
== ORIENTATION_LANDSCAPE
)
1141 aMPS
.aPaperSize
= maNupLandscapeSize
;
1142 else if( nOrientationMode
== ORIENTATION_PORTRAIT
)
1143 aMPS
.aPaperSize
= maNupPortraitSize
;
1144 else // automatic mode
1146 // get size of first real page to see if it is portrait or landscape
1147 // we assume same page sizes for all the pages for this
1148 Size aPageSize
= getJobPageSize();
1150 Size
aMultiSize( aPageSize
.Width() * nCols
, aPageSize
.Height() * nRows
);
1151 if( aMultiSize
.Width() > aMultiSize
.Height() ) // fits better on landscape
1153 aMPS
.aPaperSize
= maNupLandscapeSize
;
1154 setPaperOrientation( Orientation::Landscape
, false );
1158 aMPS
.aPaperSize
= maNupPortraitSize
;
1159 setPaperOrientation( Orientation::Portrait
, false );
1163 maPController
->setMultipage( aMPS
);
1165 mxNupOrder
->setValues( aMPS
.nOrder
, nCols
, nRows
);
1168 maUpdatePreviewIdle
.Start();
1170 maUpdatePreviewNoCacheIdle
.Start();
1173 void PrintDialog::updateNupFromPages( bool i_bMayUseCache
)
1175 int nPages
= mxNupPagesBox
->get_active_id().toInt32();
1176 int nRows
= mxNupRowsEdt
->get_value();
1177 int nCols
= mxNupColEdt
->get_value();
1178 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1179 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1180 bool bCustom
= false;
1188 else if( nPages
== 2 || nPages
== 4 || nPages
== 6 || nPages
== 9 || nPages
== 16 )
1190 Size
aJobPageSize( getJobPageSize() );
1191 bool bPortrait
= aJobPageSize
.Width() < aJobPageSize
.Height();
1205 else if( nPages
== 4 )
1207 else if( nPages
== 6 )
1220 else if( nPages
== 9 )
1222 else if( nPages
== 16 )
1232 // set upper limits for margins based on job page size and rows/columns
1233 Size
aSize( getJobPageSize() );
1235 // maximum sheet distance: 1/2 sheet
1236 tools::Long nHorzMax
= aSize
.Width()/2;
1237 tools::Long nVertMax
= aSize
.Height()/2;
1238 if( nSheetMargin
> nHorzMax
)
1239 nSheetMargin
= nHorzMax
;
1240 if( nSheetMargin
> nVertMax
)
1241 nSheetMargin
= nVertMax
;
1243 mxSheetMarginEdt
->set_max(
1244 mxSheetMarginEdt
->normalize(
1245 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1247 // maximum page distance
1248 nHorzMax
= (aSize
.Width() - 2*nSheetMargin
);
1250 nHorzMax
/= (nCols
-1);
1251 nVertMax
= (aSize
.Height() - 2*nSheetMargin
);
1253 nHorzMax
/= (nRows
-1);
1255 if( nPageMargin
> nHorzMax
)
1256 nPageMargin
= nHorzMax
;
1257 if( nPageMargin
> nVertMax
)
1258 nPageMargin
= nVertMax
;
1260 mxPageMarginEdt
->set_max(
1261 mxSheetMarginEdt
->normalize(
1262 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1265 mxNupRowsEdt
->set_value( nRows
);
1266 mxNupColEdt
->set_value( nCols
);
1267 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( nPageMargin
), FieldUnit::MM_100TH
);
1268 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( nSheetMargin
), FieldUnit::MM_100TH
);
1270 showAdvancedControls( bCustom
);
1271 updateNup( i_bMayUseCache
);
1274 void PrintDialog::enableNupControls( bool bEnable
)
1276 mxNupPagesBox
->set_sensitive( bEnable
);
1277 mxNupNumPagesTxt
->set_sensitive( bEnable
);
1278 mxNupColEdt
->set_sensitive( bEnable
);
1279 mxNupTimesTxt
->set_sensitive( bEnable
);
1280 mxNupRowsEdt
->set_sensitive( bEnable
);
1281 mxPageMarginTxt1
->set_sensitive( bEnable
);
1282 mxPageMarginEdt
->set_sensitive( bEnable
);
1283 mxPageMarginTxt2
->set_sensitive( bEnable
);
1284 mxSheetMarginTxt1
->set_sensitive( bEnable
);
1285 mxSheetMarginEdt
->set_sensitive( bEnable
);
1286 mxSheetMarginTxt2
->set_sensitive( bEnable
);
1287 mxNupOrderTxt
->set_sensitive( bEnable
);
1288 mxNupOrderBox
->set_sensitive( bEnable
);
1289 mxNupOrderWin
->set_sensitive( bEnable
);
1290 mxBorderCB
->set_sensitive( bEnable
);
1293 void PrintDialog::showAdvancedControls( bool i_bShow
)
1295 mxNupNumPagesTxt
->set_visible( i_bShow
);
1296 mxNupColEdt
->set_visible( i_bShow
);
1297 mxNupTimesTxt
->set_visible( i_bShow
);
1298 mxNupRowsEdt
->set_visible( i_bShow
);
1299 mxPageMarginTxt1
->set_visible( i_bShow
);
1300 mxPageMarginEdt
->set_visible( i_bShow
);
1301 mxPageMarginTxt2
->set_visible( i_bShow
);
1302 mxSheetMarginTxt1
->set_visible( i_bShow
);
1303 mxSheetMarginEdt
->set_visible( i_bShow
);
1304 mxSheetMarginTxt2
->set_visible( i_bShow
);
1309 void setHelpId( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpIds
, sal_Int32 i_nIndex
)
1311 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpIds
.getLength() )
1312 i_pWindow
->set_help_id( i_rHelpIds
.getConstArray()[i_nIndex
] );
1315 void setHelpText( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpTexts
, sal_Int32 i_nIndex
)
1317 // without a help text set and the correct smartID,
1318 // help texts will be retrieved from the online help system
1319 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpTexts
.getLength() )
1320 i_pWindow
->set_tooltip_text(i_rHelpTexts
.getConstArray()[i_nIndex
]);
1324 void PrintDialog::setupOptionalUI()
1326 const Sequence
< PropertyValue
>& rOptions( maPController
->getUIOptions() );
1327 for( const auto& rOption
: rOptions
)
1329 if (rOption
.Name
== "OptionsUIFile")
1331 OUString sOptionsUIFile
;
1332 rOption
.Value
>>= sOptionsUIFile
;
1333 mxCustomOptionsUIBuilder
= Application::CreateBuilder(mxCustom
.get(), sOptionsUIFile
);
1334 std::unique_ptr
<weld::Container
> xWindow
= mxCustomOptionsUIBuilder
->weld_container("box");
1339 Sequence
< beans::PropertyValue
> aOptProp
;
1340 rOption
.Value
>>= aOptProp
;
1342 // extract ui element
1346 OUString aPropertyName
;
1347 Sequence
< OUString
> aChoices
;
1348 Sequence
< sal_Bool
> aChoicesDisabled
;
1349 Sequence
< OUString
> aHelpTexts
;
1350 Sequence
< OUString
> aIDs
;
1351 Sequence
< OUString
> aHelpIds
;
1352 sal_Int64 nMinValue
= 0, nMaxValue
= 0;
1353 OUString aGroupingHint
;
1355 for( const beans::PropertyValue
& rEntry
: std::as_const(aOptProp
) )
1357 if ( rEntry
.Name
== "ID" )
1359 rEntry
.Value
>>= aIDs
;
1362 if ( rEntry
.Name
== "Text" )
1364 rEntry
.Value
>>= aText
;
1366 else if ( rEntry
.Name
== "ControlType" )
1368 rEntry
.Value
>>= aCtrlType
;
1370 else if ( rEntry
.Name
== "Choices" )
1372 rEntry
.Value
>>= aChoices
;
1374 else if ( rEntry
.Name
== "ChoicesDisabled" )
1376 rEntry
.Value
>>= aChoicesDisabled
;
1378 else if ( rEntry
.Name
== "Property" )
1381 rEntry
.Value
>>= aVal
;
1382 aPropertyName
= aVal
.Name
;
1384 else if ( rEntry
.Name
== "Enabled" )
1387 else if ( rEntry
.Name
== "GroupingHint" )
1389 rEntry
.Value
>>= aGroupingHint
;
1391 else if ( rEntry
.Name
== "DependsOnName" )
1394 else if ( rEntry
.Name
== "DependsOnEntry" )
1397 else if ( rEntry
.Name
== "AttachToDependency" )
1400 else if ( rEntry
.Name
== "MinValue" )
1402 rEntry
.Value
>>= nMinValue
;
1404 else if ( rEntry
.Name
== "MaxValue" )
1406 rEntry
.Value
>>= nMaxValue
;
1408 else if ( rEntry
.Name
== "HelpText" )
1410 if( ! (rEntry
.Value
>>= aHelpTexts
) )
1413 if( rEntry
.Value
>>= aHelpText
)
1415 aHelpTexts
.realloc( 1 );
1416 *aHelpTexts
.getArray() = aHelpText
;
1420 else if ( rEntry
.Name
== "HelpId" )
1422 if( ! (rEntry
.Value
>>= aHelpIds
) )
1425 if( rEntry
.Value
>>= aHelpId
)
1427 aHelpIds
.realloc( 1 );
1428 *aHelpIds
.getArray() = aHelpId
;
1432 else if ( rEntry
.Name
== "HintNoLayoutPage" )
1434 bool bHasLayoutFrame
= false;
1435 rEntry
.Value
>>= bHasLayoutFrame
;
1436 mbShowLayoutFrame
= !bHasLayoutFrame
;
1440 if (aCtrlType
== "Group")
1444 weld::Container
* pPage
= mxTabCtrl
->get_page(aID
);
1448 mxTabCtrl
->set_tab_label_text(aID
, aText
);
1451 if (aHelpIds
.hasElements())
1452 pPage
->set_help_id(aHelpIds
[0]);
1455 if (aHelpTexts
.hasElements())
1456 pPage
->set_tooltip_text(aHelpTexts
[0]);
1460 else if (aCtrlType
== "Subgroup" && !aID
.isEmpty())
1462 std::unique_ptr
<weld::Widget
> xWidget
;
1463 // since 'New Print Dialog Design' fromwhich in calc is not a frame anymore
1464 if (aID
== "fromwhich")
1466 std::unique_ptr
<weld::Label
> xLabel
= m_xBuilder
->weld_label(aID
);
1467 xLabel
->set_label(aText
);
1468 xWidget
= std::move(xLabel
);
1472 std::unique_ptr
<weld::Frame
> xFrame
= m_xBuilder
->weld_frame(aID
);
1473 if (!xFrame
&& mxCustomOptionsUIBuilder
)
1474 xFrame
= mxCustomOptionsUIBuilder
->weld_frame(aID
);
1477 xFrame
->set_label(aText
);
1478 xWidget
= std::move(xFrame
);
1486 setHelpId(xWidget
.get(), aHelpIds
, 0);
1488 setHelpText(xWidget
.get(), aHelpTexts
, 0);
1493 else if( aCtrlType
== "Bool" && aGroupingHint
== "LayoutPage" && aPropertyName
== "PrintProspect" )
1495 mxBrochureBtn
->set_label(aText
);
1496 mxBrochureBtn
->show();
1499 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1501 pVal
->Value
>>= bVal
;
1502 mxBrochureBtn
->set_active( bVal
);
1503 mxBrochureBtn
->set_sensitive( maPController
->isUIOptionEnabled( aPropertyName
) && pVal
!= nullptr );
1505 maPropertyToWindowMap
[aPropertyName
].emplace_back(mxBrochureBtn
.get());
1506 maControlToPropertyMap
[mxBrochureBtn
.get()] = aPropertyName
;
1509 setHelpId( mxBrochureBtn
.get(), aHelpIds
, 0 );
1511 setHelpText( mxBrochureBtn
.get(), aHelpTexts
, 0 );
1513 else if (aCtrlType
== "Bool")
1516 std::unique_ptr
<weld::CheckButton
> xNewBox
= m_xBuilder
->weld_check_button(aID
);
1517 if (!xNewBox
&& mxCustomOptionsUIBuilder
)
1518 xNewBox
= mxCustomOptionsUIBuilder
->weld_check_button(aID
);
1522 xNewBox
->set_label( aText
);
1526 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1528 pVal
->Value
>>= bVal
;
1529 xNewBox
->set_active( bVal
);
1530 xNewBox
->connect_toggled( LINK( this, PrintDialog
, UIOption_CheckHdl
) );
1532 maExtraControls
.emplace_back(std::move(xNewBox
));
1534 weld::Widget
* pWidget
= maExtraControls
.back().get();
1536 maPropertyToWindowMap
[aPropertyName
].emplace_back(pWidget
);
1537 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1540 setHelpId(pWidget
, aHelpIds
, 0);
1542 setHelpText(pWidget
, aHelpTexts
, 0);
1544 else if (aCtrlType
== "Radio")
1546 sal_Int32 nCurHelpText
= 0;
1549 sal_Int32 nSelectVal
= 0;
1550 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1551 if( pVal
&& pVal
->Value
.hasValue() )
1552 pVal
->Value
>>= nSelectVal
;
1553 for( sal_Int32 m
= 0; m
< aChoices
.getLength(); m
++ )
1556 std::unique_ptr
<weld::RadioButton
> xBtn
= m_xBuilder
->weld_radio_button(aID
);
1557 if (!xBtn
&& mxCustomOptionsUIBuilder
)
1558 xBtn
= mxCustomOptionsUIBuilder
->weld_radio_button(aID
);
1562 xBtn
->set_label( aChoices
[m
] );
1563 xBtn
->set_active( m
== nSelectVal
);
1564 xBtn
->connect_toggled( LINK( this, PrintDialog
, UIOption_RadioHdl
) );
1565 if( aChoicesDisabled
.getLength() > m
&& aChoicesDisabled
[m
] )
1566 xBtn
->set_sensitive( false );
1569 maExtraControls
.emplace_back(std::move(xBtn
));
1571 weld::Widget
* pWidget
= maExtraControls
.back().get();
1573 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1574 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1575 maControlToNumValMap
[pWidget
] = m
;
1578 setHelpId( pWidget
, aHelpIds
, nCurHelpText
);
1580 setHelpText( pWidget
, aHelpTexts
, nCurHelpText
);
1584 else if ( aCtrlType
== "List" )
1586 std::unique_ptr
<weld::ComboBox
> xList
= m_xBuilder
->weld_combo_box(aID
);
1587 if (!xList
&& mxCustomOptionsUIBuilder
)
1588 xList
= mxCustomOptionsUIBuilder
->weld_combo_box(aID
);
1593 for( const auto& rChoice
: std::as_const(aChoices
) )
1594 xList
->append_text(rChoice
);
1596 sal_Int32 nSelectVal
= 0;
1597 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1598 if( pVal
&& pVal
->Value
.hasValue() )
1599 pVal
->Value
>>= nSelectVal
;
1600 xList
->set_active(nSelectVal
);
1601 xList
->connect_changed( LINK( this, PrintDialog
, UIOption_SelectHdl
) );
1604 maExtraControls
.emplace_back(std::move(xList
));
1606 weld::Widget
* pWidget
= maExtraControls
.back().get();
1608 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1609 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1612 setHelpId( pWidget
, aHelpIds
, 0 );
1614 setHelpText( pWidget
, aHelpTexts
, 0 );
1616 else if ( aCtrlType
== "Range" )
1618 std::unique_ptr
<weld::SpinButton
> xField
= m_xBuilder
->weld_spin_button(aID
);
1619 if (!xField
&& mxCustomOptionsUIBuilder
)
1620 xField
= mxCustomOptionsUIBuilder
->weld_spin_button(aID
);
1624 // set min/max and current value
1625 if(nMinValue
!= nMaxValue
)
1626 xField
->set_range(nMinValue
, nMaxValue
);
1628 sal_Int64 nCurVal
= 0;
1629 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1630 if( pVal
&& pVal
->Value
.hasValue() )
1631 pVal
->Value
>>= nCurVal
;
1632 xField
->set_value( nCurVal
);
1633 xField
->connect_value_changed( LINK( this, PrintDialog
, UIOption_SpinModifyHdl
) );
1636 maExtraControls
.emplace_back(std::move(xField
));
1638 weld::Widget
* pWidget
= maExtraControls
.back().get();
1640 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1641 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1644 setHelpId( pWidget
, aHelpIds
, 0 );
1646 setHelpText( pWidget
, aHelpTexts
, 0 );
1648 else if (aCtrlType
== "Edit")
1650 std::unique_ptr
<weld::Entry
> xField
= m_xBuilder
->weld_entry(aID
);
1651 if (!xField
&& mxCustomOptionsUIBuilder
)
1652 xField
= mxCustomOptionsUIBuilder
->weld_entry(aID
);
1657 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1658 if( pVal
&& pVal
->Value
.hasValue() )
1659 pVal
->Value
>>= aCurVal
;
1660 xField
->set_text( aCurVal
);
1661 xField
->connect_changed( LINK( this, PrintDialog
, UIOption_EntryModifyHdl
) );
1664 maExtraControls
.emplace_back(std::move(xField
));
1666 weld::Widget
* pWidget
= maExtraControls
.back().get();
1668 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1669 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1672 setHelpId( pWidget
, aHelpIds
, 0 );
1674 setHelpText( pWidget
, aHelpTexts
, 0 );
1678 SAL_WARN( "vcl", "Unsupported UI option: \"" << aCtrlType
<< '"');
1682 // #i106506# if no brochure button, then the singular Pages radio button
1683 // makes no sense, so replace it by a FixedText label
1684 if (!mxBrochureBtn
->get_visible() && mxPagesBtn
->get_visible())
1686 mxPagesBoxTitleTxt
->set_label(mxPagesBtn
->get_label());
1687 mxPagesBoxTitleTxt
->show();
1690 mxNupPagesBox
->set_accessible_relation_labeled_by(mxPagesBoxTitleTxt
.get());
1693 // update enable states
1694 checkOptionalControlDependencies();
1696 // print range not shown (currently math only) -> hide spacer line and reverse order
1697 if (!mxPageRangeEdit
->get_visible())
1699 mxReverseOrderBox
->hide();
1702 if (!mxCustomOptionsUIBuilder
)
1703 mxTabCtrl
->remove_page(mxTabCtrl
->get_page_ident(1));
1706 void PrintDialog::makeEnabled( weld::Widget
* i_pWindow
)
1708 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1709 if( it
!= maControlToPropertyMap
.end() )
1711 OUString
aDependency( maPController
->makeEnabled( it
->second
) );
1712 if( !aDependency
.isEmpty() )
1713 updateWindowFromProperty( aDependency
);
1717 void PrintDialog::updateWindowFromProperty( const OUString
& i_rProperty
)
1719 beans::PropertyValue
* pValue
= maPController
->getValue( i_rProperty
);
1720 auto it
= maPropertyToWindowMap
.find( i_rProperty
);
1721 if( !(pValue
&& it
!= maPropertyToWindowMap
.end()) )
1724 const auto& rWindows( it
->second
);
1725 if( rWindows
.empty() )
1729 sal_Int32 nVal
= -1;
1730 if( pValue
->Value
>>= bVal
)
1732 // we should have a CheckBox for this one
1733 weld::CheckButton
* pBox
= dynamic_cast<weld::CheckButton
*>(rWindows
.front());
1736 pBox
->set_active( bVal
);
1738 else if ( i_rProperty
== "PrintProspect" )
1740 // EVIL special case
1742 mxBrochureBtn
->set_active(true);
1744 mxPagesBtn
->set_active(true);
1748 SAL_WARN( "vcl", "missing a checkbox" );
1751 else if( pValue
->Value
>>= nVal
)
1753 // this could be a ListBox or a RadioButtonGroup
1754 weld::ComboBox
* pList
= dynamic_cast<weld::ComboBox
*>(rWindows
.front());
1757 pList
->set_active( static_cast< sal_uInt16
>(nVal
) );
1759 else if( nVal
>= 0 && o3tl::make_unsigned(nVal
) < rWindows
.size() )
1761 weld::RadioButton
* pBtn
= dynamic_cast<weld::RadioButton
*>(rWindows
[nVal
]);
1762 SAL_WARN_IF( !pBtn
, "vcl", "unexpected control for property" );
1764 pBtn
->set_active(true);
1769 bool PrintDialog::isPrintToFile() const
1771 return ( mxPrinters
->get_active() == 0 );
1774 bool PrintDialog::isCollate() const
1776 return mxCopyCountField
->get_value() > 1 && mxCollateBox
->get_active();
1779 bool PrintDialog::isSingleJobs() const
1781 return mxSingleJobsBox
->get_active();
1784 bool PrintDialog::hasPreview() const
1786 return mxPreviewBox
->get_active();
1789 PropertyValue
* PrintDialog::getValueForWindow( weld::Widget
* i_pWindow
) const
1791 PropertyValue
* pVal
= nullptr;
1792 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1793 if( it
!= maControlToPropertyMap
.end() )
1795 pVal
= maPController
->getValue( it
->second
);
1796 SAL_WARN_IF( !pVal
, "vcl", "property value not found" );
1800 OSL_FAIL( "changed control not in property map" );
1805 IMPL_LINK(PrintDialog
, ToggleHdl
, weld::Toggleable
&, rButton
, void)
1807 if (&rButton
== mxPreviewBox
.get())
1809 maUpdatePreviewIdle
.Start();
1811 else if( &rButton
== mxBorderCB
.get() )
1815 else if (&rButton
== mxSingleJobsBox
.get())
1817 maPController
->setValue( "SinglePrintJobs",
1818 Any( isSingleJobs() ) );
1819 checkControlDependencies();
1821 else if( &rButton
== mxCollateBox
.get() )
1823 maPController
->setValue( "Collate",
1824 Any( isCollate() ) );
1825 checkControlDependencies();
1827 else if( &rButton
== mxReverseOrderBox
.get() )
1829 bool bChecked
= mxReverseOrderBox
->get_active();
1830 maPController
->setReversePrint( bChecked
);
1831 maPController
->setValue( "PrintReverse",
1833 maUpdatePreviewIdle
.Start();
1835 else if (&rButton
== mxBrochureBtn
.get())
1837 PropertyValue
* pVal
= getValueForWindow(mxBrochureBtn
.get());
1840 bool bVal
= mxBrochureBtn
->get_active();
1841 pVal
->Value
<<= bVal
;
1843 checkOptionalControlDependencies();
1845 // update preview and page settings
1846 maUpdatePreviewNoCacheIdle
.Start();
1848 if (mxBrochureBtn
->get_active())
1850 mxOrientationBox
->set_sensitive( false );
1851 mxOrientationBox
->set_active( ORIENTATION_LANDSCAPE
);
1852 mxNupPagesBox
->set_active( 0 );
1853 updateNupFromPages();
1854 showAdvancedControls( false );
1855 enableNupControls( false );
1859 mxOrientationBox
->set_sensitive( true );
1860 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1861 enableNupControls( true );
1862 updateNupFromPages();
1868 IMPL_LINK(PrintDialog
, ClickHdl
, weld::Button
&, rButton
, void)
1870 if (&rButton
== mxOKButton
.get() || &rButton
== mxCancelButton
.get())
1873 m_xDialog
->response(&rButton
== mxOKButton
.get() ? RET_OK
: RET_CANCEL
);
1875 else if( &rButton
== mxHelpButton
.get() )
1877 // start help system
1878 Help
* pHelp
= Application::GetHelp();
1881 pHelp
->Start("vcl/ui/printdialog/PrintDialog", mxOKButton
.get());
1884 else if( &rButton
== mxForwardBtn
.get() )
1888 else if( &rButton
== mxBackwardBtn
.get() )
1892 else if( &rButton
== mxFirstBtn
.get() )
1896 else if( &rButton
== mxLastBtn
.get() )
1902 if( &rButton
== mxSetupButton
.get() )
1904 maPController
->setupPrinter(m_xDialog
.get());
1906 if ( !isPrintToFile() )
1908 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1909 mePaper
= aPrt
->GetPaper();
1911 for (int nPaper
= 0; nPaper
< aPrt
->GetPaperInfoCount(); nPaper
++ )
1913 PaperInfo aInfo
= aPrt
->GetPaperInfo( nPaper
);
1914 aInfo
.doSloppyFit(true);
1915 Paper ePaper
= aInfo
.getPaper();
1917 if ( mePaper
== ePaper
)
1919 mxPaperSizeBox
->set_active( nPaper
);
1925 updateOrientationBox( false );
1926 setupPaperSidesBox();
1928 // tdf#63905 don't use cache: page size may change
1929 maUpdatePreviewNoCacheIdle
.Start();
1931 checkControlDependencies();
1936 IMPL_LINK( PrintDialog
, SelectHdl
, weld::ComboBox
&, rBox
, void )
1938 if (&rBox
== mxPrinters
.get())
1940 if ( !isPrintToFile() )
1942 OUString
aNewPrinter(rBox
.get_active_text());
1944 maPController
->setPrinter( VclPtrInstance
<Printer
>( aNewPrinter
) );
1945 maPController
->resetPrinterOptions( false );
1947 updateOrientationBox();
1949 // update text fields
1950 mxOKButton
->set_label(maPrintText
);
1951 updatePrinterText();
1953 maUpdatePreviewIdle
.Start();
1955 else // print to file
1957 // use the default printer or FIXME: the last used one?
1958 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
1959 mxOKButton
->set_label(maPrintToFileText
);
1960 maPController
->resetPrinterOptions( true );
1963 updateOrientationBox();
1964 maUpdatePreviewIdle
.Start();
1967 setupPaperSidesBox();
1969 else if ( &rBox
== mxPaperSidesBox
.get() )
1971 DuplexMode eDuplex
= static_cast<DuplexMode
>(mxPaperSidesBox
->get_active() + 1);
1972 maPController
->getPrinter()->SetDuplexMode( eDuplex
);
1974 else if( &rBox
== mxOrientationBox
.get() )
1976 int nOrientation
= mxOrientationBox
->get_active();
1977 if ( nOrientation
!= ORIENTATION_AUTOMATIC
)
1978 setPaperOrientation( static_cast<Orientation
>( nOrientation
- 1 ), true );
1982 else if ( &rBox
== mxNupOrderBox
.get() )
1986 else if( &rBox
== mxNupPagesBox
.get() )
1988 if( !mxPagesBtn
->get_active() )
1989 mxPagesBtn
->set_active(true);
1990 updateNupFromPages( false );
1992 else if ( &rBox
== mxPaperSizeBox
.get() )
1994 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1995 PaperInfo aInfo
= aPrt
->GetPaperInfo( rBox
.get_active() );
1996 aInfo
.doSloppyFit(true);
1997 mePaper
= aInfo
.getPaper();
1999 if ( mePaper
== PAPER_USER
)
2000 aPrt
->SetPaperSizeUser( Size( aInfo
.getWidth(), aInfo
.getHeight() ) );
2002 aPrt
->SetPaper( mePaper
);
2004 maPController
->setPaperSizeFromUser( Size( aInfo
.getWidth(), aInfo
.getHeight() ) );
2006 maUpdatePreviewIdle
.Start();
2010 IMPL_LINK_NOARG(PrintDialog
, MetricSpinModifyHdl
, weld::MetricSpinButton
&, void)
2012 checkControlDependencies();
2013 updateNupFromPages();
2016 IMPL_LINK_NOARG(PrintDialog
, FocusOutHdl
, weld::Widget
&, void)
2018 ActivateHdl(*mxPageEdit
);
2021 IMPL_LINK_NOARG(PrintDialog
, ActivateHdl
, weld::Entry
&, bool)
2023 sal_Int32 nPage
= mxPageEdit
->get_text().toInt32();
2027 mxPageEdit
->set_text("1");
2029 else if (nPage
> mnCachedPages
)
2031 nPage
= mnCachedPages
;
2032 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2034 int nNewCurPage
= nPage
- 1;
2035 if (nNewCurPage
!= mnCurPage
)
2037 mnCurPage
= nNewCurPage
;
2038 maUpdatePreviewIdle
.Start();
2043 IMPL_LINK( PrintDialog
, SpinModifyHdl
, weld::SpinButton
&, rEdit
, void )
2045 checkControlDependencies();
2046 if (&rEdit
== mxNupRowsEdt
.get() || &rEdit
== mxNupColEdt
.get())
2048 updateNupFromPages();
2050 else if( &rEdit
== mxCopyCountField
.get() )
2052 maPController
->setValue( "CopyCount",
2053 Any( sal_Int32(mxCopyCountField
->get_value()) ) );
2054 maPController
->setValue( "Collate",
2055 Any( isCollate() ) );
2059 IMPL_LINK( PrintDialog
, UIOption_CheckHdl
, weld::Toggleable
&, i_rBox
, void )
2061 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2064 makeEnabled( &i_rBox
);
2066 bool bVal
= i_rBox
.get_active();
2067 pVal
->Value
<<= bVal
;
2069 checkOptionalControlDependencies();
2071 // update preview and page settings
2072 maUpdatePreviewNoCacheIdle
.Start();
2076 IMPL_LINK( PrintDialog
, UIOption_RadioHdl
, weld::Toggleable
&, i_rBtn
, void )
2078 // this handler gets called for all radiobuttons that get unchecked, too
2079 // however we only want one notification for the new value (that is for
2080 // the button that gets checked)
2081 if( !i_rBtn
.get_active() )
2084 PropertyValue
* pVal
= getValueForWindow( &i_rBtn
);
2085 auto it
= maControlToNumValMap
.find( &i_rBtn
);
2086 if( !(pVal
&& it
!= maControlToNumValMap
.end()) )
2089 makeEnabled( &i_rBtn
);
2091 sal_Int32 nVal
= it
->second
;
2092 pVal
->Value
<<= nVal
;
2094 updateOrientationBox();
2096 checkOptionalControlDependencies();
2098 // tdf#41205 give focus to the page range edit if the corresponding radio button was selected
2099 if (pVal
->Name
== "PrintContent" && mxPageRangesRadioButton
->get_active())
2100 mxPageRangeEdit
->grab_focus();
2102 // update preview and page settings
2103 maUpdatePreviewNoCacheIdle
.Start();
2106 IMPL_LINK( PrintDialog
, UIOption_SelectHdl
, weld::ComboBox
&, i_rBox
, void )
2108 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2112 makeEnabled( &i_rBox
);
2114 sal_Int32
nVal( i_rBox
.get_active() );
2115 pVal
->Value
<<= nVal
;
2117 //If we are in impress we start in print slides mode and get a
2118 //maFirstPageSize for slides which are usually landscape mode, if we
2119 //change to notes which are usually in portrait mode, and then visit
2120 //n-up print, we will assume notes are in landscape unless we throw
2121 //away maFirstPageSize when we change page content type
2122 if (pVal
->Name
== "PageContentType")
2123 maFirstPageSize
= Size();
2125 checkOptionalControlDependencies();
2127 // update preview and page settings
2128 maUpdatePreviewNoCacheIdle
.Start();
2131 IMPL_LINK( PrintDialog
, UIOption_SpinModifyHdl
, weld::SpinButton
&, i_rBox
, void )
2133 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2136 makeEnabled( &i_rBox
);
2138 sal_Int64 nVal
= i_rBox
.get_value();
2139 pVal
->Value
<<= nVal
;
2141 checkOptionalControlDependencies();
2143 // update preview and page settings
2144 maUpdatePreviewNoCacheIdle
.Start();
2148 IMPL_LINK( PrintDialog
, UIOption_EntryModifyHdl
, weld::Entry
&, i_rBox
, void )
2150 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2153 makeEnabled( &i_rBox
);
2155 OUString
aVal( i_rBox
.get_text() );
2156 pVal
->Value
<<= aVal
;
2158 checkOptionalControlDependencies();
2160 // update preview and page settings
2161 maUpdatePreviewNoCacheIdle
.Start();
2165 void PrintDialog::previewForward()
2167 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() + 1;
2168 if (nValue
<= mnCachedPages
)
2170 mxPageEdit
->set_text(OUString::number(nValue
));
2171 ActivateHdl(*mxPageEdit
);
2175 void PrintDialog::previewBackward()
2177 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() - 1;
2180 mxPageEdit
->set_text(OUString::number(nValue
));
2181 ActivateHdl(*mxPageEdit
);
2185 void PrintDialog::previewFirst()
2187 mxPageEdit
->set_text("1");
2188 ActivateHdl(*mxPageEdit
);
2191 void PrintDialog::previewLast()
2193 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2194 ActivateHdl(*mxPageEdit
);
2198 static OUString
getNewLabel(const OUString
& aLabel
, int i_nCurr
, int i_nMax
)
2200 OUString
aNewText( aLabel
.replaceFirst( "%p", OUString::number( i_nCurr
) ) );
2201 aNewText
= aNewText
.replaceFirst( "%n", OUString::number( i_nMax
) );
2206 // PrintProgressDialog
2207 PrintProgressDialog::PrintProgressDialog(weld::Window
* i_pParent
, int i_nMax
)
2208 : GenericDialogController(i_pParent
, "vcl/ui/printprogressdialog.ui", "PrintProgressDialog")
2212 , mxText(m_xBuilder
->weld_label("label"))
2213 , mxProgress(m_xBuilder
->weld_progress_bar("progressbar"))
2214 , mxButton(m_xBuilder
->weld_button("cancel"))
2219 maStr
= mxText
->get_label();
2221 //just multiply largest value by 10 and take the width of that string as
2222 //the max size we will want
2223 mxText
->set_label(getNewLabel(maStr
, mnMax
* 10, mnMax
* 10));
2224 mxText
->set_size_request(mxText
->get_preferred_size().Width(), -1);
2226 //Pick a useful max width
2227 mxProgress
->set_size_request(mxProgress
->get_approximate_digit_width() * 25, -1);
2229 mxButton
->connect_clicked( LINK( this, PrintProgressDialog
, ClickHdl
) );
2231 // after this patch f7157f04fab298423e2c4f6a7e5f8e361164b15f, we have seen the calc Max string (sometimes) look above
2232 // now init to the right start values
2233 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2236 PrintProgressDialog::~PrintProgressDialog()
2240 IMPL_LINK_NOARG(PrintProgressDialog
, ClickHdl
, weld::Button
&, void)
2245 void PrintProgressDialog::setProgress( int i_nCurrent
)
2252 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2254 // here view the dialog, with the right label
2255 mxProgress
->set_percentage(mnCur
*100/mnMax
);
2258 void PrintProgressDialog::tick()
2261 setProgress( ++mnCur
);
2264 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */