1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <printdlg.hxx>
22 #include <strings.hrc>
23 #include <bitmaps.hlst>
24 #include <officecfg/Office/Common.hxx>
25 #include <vcl/windowstate.hxx>
27 #include <vcl/QueueInfo.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <vcl/naturalsort.hxx>
30 #include <vcl/print.hxx>
31 #include <vcl/wall.hxx>
32 #include <vcl/decoview.hxx>
33 #include <configsettings.hxx>
34 #include <vcl/help.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/settings.hxx>
37 #include <vcl/virdev.hxx>
39 #include <unotools/localedatawrapper.hxx>
41 #include <sal/log.hxx>
42 #include <osl/diagnose.h>
43 #include <rtl/ustrbuf.hxx>
45 #include <com/sun/star/beans/PropertyValue.hpp>
48 using namespace com::sun::star
;
49 using namespace com::sun::star::uno
;
50 using namespace com::sun::star::lang
;
51 using namespace com::sun::star::container
;
52 using namespace com::sun::star::beans
;
56 ORIENTATION_AUTOMATIC
,
62 bool lcl_ListBoxCompare( const OUString
& rStr1
, const OUString
& rStr2
)
64 return vcl::NaturalSortCompare( rStr1
, rStr2
) < 0;
68 PrintDialog::PrintPreviewWindow::PrintPreviewWindow(PrintDialog
* pDialog
)
71 , maOrigSize( 10, 10 )
73 , mnDPIX(Application::GetDefaultDevice()->GetDPIX())
74 , mnDPIY(Application::GetDefaultDevice()->GetDPIY())
76 , maReplacementString()
77 , mbGreyscale( false )
81 PrintDialog::PrintPreviewWindow::~PrintPreviewWindow()
85 void PrintDialog::PrintPreviewWindow::Resize()
87 Size
aNewSize(GetOutputSizePixel());
88 tools::Long nTextHeight
= GetDrawingArea()->get_text_height();
89 // leave small space for decoration
90 aNewSize
.AdjustWidth( -(nTextHeight
+ 2) );
91 aNewSize
.AdjustHeight( -(nTextHeight
+ 2) );
95 // #i106435# catch corner case of Size(0,0)
96 Size
aOrigSize( maOrigSize
);
97 if( aOrigSize
.Width() < 1 )
98 aOrigSize
.setWidth( aNewSize
.Width() );
99 if( aOrigSize
.Height() < 1 )
100 aOrigSize
.setHeight( aNewSize
.Height() );
101 if( aOrigSize
.Width() > aOrigSize
.Height() )
103 aScaledSize
= Size( aNewSize
.Width(), aNewSize
.Width() * aOrigSize
.Height() / aOrigSize
.Width() );
104 if( aScaledSize
.Height() > aNewSize
.Height() )
105 fScale
= double(aNewSize
.Height())/double(aScaledSize
.Height());
109 aScaledSize
= Size( aNewSize
.Height() * aOrigSize
.Width() / aOrigSize
.Height(), aNewSize
.Height() );
110 if( aScaledSize
.Width() > aNewSize
.Width() )
111 fScale
= double(aNewSize
.Width())/double(aScaledSize
.Width());
113 aScaledSize
.setWidth( tools::Long(aScaledSize
.Width()*fScale
) );
114 aScaledSize
.setHeight( tools::Long(aScaledSize
.Height()*fScale
) );
116 maPreviewSize
= aScaledSize
;
118 // check and evtl. recreate preview bitmap
119 preparePreviewBitmap();
122 void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
124 rRenderContext
.Push();
125 if (vcl::Window
* pDefaultDevice
= dynamic_cast<vcl::Window
*>(Application::GetDefaultDevice()))
127 Font
aFont(rRenderContext
.GetSettings().GetStyleSettings().GetLabelFont());
128 pDefaultDevice
->SetPointFont(rRenderContext
, aFont
);
131 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
132 rRenderContext
.Erase();
134 auto nTextHeight
= rRenderContext
.GetTextHeight();
135 Size
aSize(GetOutputSizePixel());
136 Point
aOffset((aSize
.Width() - maPreviewSize
.Width() + nTextHeight
) / 2,
137 (aSize
.Height() - maPreviewSize
.Height() + nTextHeight
) / 2);
141 auto nWidth
= rRenderContext
.GetTextWidth(maHorzText
);
143 auto nStart
= aOffset
.X() + (maPreviewSize
.Width() - nWidth
) / 2;
144 rRenderContext
.DrawText(Point(nStart
, aOffset
.Y() - nTextHeight
), maHorzText
, 0, maHorzText
.getLength());
146 DecorationView
aDecoView(&rRenderContext
);
147 auto nTop
= aOffset
.Y() - (nTextHeight
/ 2);
148 aDecoView
.DrawSeparator(Point(aOffset
.X(), nTop
), Point(nStart
- 2, nTop
), false);
149 aDecoView
.DrawSeparator(Point(nStart
+ nWidth
+ 2, nTop
), Point(aOffset
.X() + maPreviewSize
.Width(), nTop
), false);
154 rRenderContext
.Push(PushFlags::FONT
);
155 vcl::Font
aFont(rRenderContext
.GetFont());
156 aFont
.SetOrientation(Degree10(900));
157 rRenderContext
.SetFont(aFont
);
159 auto nLeft
= aOffset
.X() - nTextHeight
;
161 auto nWidth
= rRenderContext
.GetTextWidth(maVertText
);
162 auto nStart
= aOffset
.Y() + (maPreviewSize
.Height() + nWidth
) / 2;
164 rRenderContext
.DrawText(Point(nLeft
, nStart
), maVertText
, 0, maVertText
.getLength());
166 DecorationView
aDecoView(&rRenderContext
);
167 nLeft
= aOffset
.X() - (nTextHeight
/ 2);
168 aDecoView
.DrawSeparator(Point(nLeft
, aOffset
.Y()), Point(nLeft
, nStart
- nWidth
- 2), true);
169 aDecoView
.DrawSeparator(Point(nLeft
, nStart
+ 2), Point(nLeft
, aOffset
.Y() + maPreviewSize
.Height()), true);
171 rRenderContext
.Pop();
174 if (!maReplacementString
.isEmpty())
176 // replacement is active
177 tools::Rectangle
aTextRect(aOffset
+ Point(2, 2), Size(maPreviewSize
.Width() - 4, maPreviewSize
.Height() - 4));
178 rRenderContext
.DrawText(aTextRect
, maReplacementString
,
179 DrawTextFlags::Center
| DrawTextFlags::VCenter
|
180 DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
184 BitmapEx
aPreviewBitmap(maPreviewBitmap
);
186 // This explicit force-to-scale allows us to get the
187 // mentioned best quality here. Unfortunately this is
188 // currently not sure when using just ::DrawBitmap with
189 // a defined size or ::DrawOutDev
190 aPreviewBitmap
.Scale(maPreviewSize
, BmpScaleFlag::BestQuality
);
191 rRenderContext
.DrawBitmapEx(aOffset
, aPreviewBitmap
);
194 tools::Rectangle
aFrameRect(aOffset
+ Point(-1, -1), Size(maPreviewSize
.Width() + 2, maPreviewSize
.Height() + 2));
195 DecorationView
aDecorationView(&rRenderContext
);
196 aDecorationView
.DrawFrame(aFrameRect
, DrawFrameStyle::Group
);
198 rRenderContext
.Pop();
201 bool PrintDialog::PrintPreviewWindow::Command( const CommandEvent
& rEvt
)
203 if( rEvt
.GetCommand() == CommandEventId::Wheel
)
205 const CommandWheelData
* pWheelData
= rEvt
.GetWheelData();
206 if(pWheelData
->GetDelta() > 0)
207 mpDialog
->previewForward();
208 else if (pWheelData
->GetDelta() < 0)
209 mpDialog
->previewBackward();
212 return CustomWidgetController::Command(rEvt
);
215 void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile
& i_rNewPreview
,
216 const Size
& i_rOrigSize
,
217 const OUString
& i_rPaperName
,
218 const OUString
& i_rReplacement
,
224 maMtf
= i_rNewPreview
;
227 maOrigSize
= i_rOrigSize
;
228 maReplacementString
= i_rReplacement
;
229 mbGreyscale
= i_bGreyscale
;
231 // use correct measurements
232 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
233 MapUnit eUnit
= MapUnit::MapMM
;
235 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
237 eUnit
= MapUnit::Map100thInch
;
240 Size
aLogicPaperSize(OutputDevice::LogicToLogic(i_rOrigSize
, MapMode(MapUnit::Map100thMM
), MapMode(eUnit
)));
241 OUString
aNumText( rLocWrap
.getNum( aLogicPaperSize
.Width(), nDigits
) );
243 aBuf
.append( aNumText
)
245 aBuf
.appendAscii( eUnit
== MapUnit::MapMM
? "mm" : "in" );
246 if( !i_rPaperName
.isEmpty() )
249 aBuf
.append( i_rPaperName
);
252 maHorzText
= aBuf
.makeStringAndClear();
254 aNumText
= rLocWrap
.getNum( aLogicPaperSize
.Height(), nDigits
);
255 aBuf
.append( aNumText
)
257 aBuf
.appendAscii( eUnit
== MapUnit::MapMM
? "mm" : "in" );
258 maVertText
= aBuf
.makeStringAndClear();
260 // We have a new Metafile and evtl. a new page, so we need to reset
261 // the PreviewBitmap to force new creation
262 maPreviewBitmap
= Bitmap();
264 // sets/calculates e.g. maPreviewSize
265 // also triggers preparePreviewBitmap()
271 void PrintDialog::PrintPreviewWindow::preparePreviewBitmap()
273 if(maPreviewSize
.IsEmpty())
275 // not yet fully initialized, no need to prepare anything
279 // define an allowed number of pixels, also see
280 // defaults for primitive renderers and similar. This
281 // might be centralized and made dependent of 32/64bit
282 const sal_uInt32
nMaxSquarePixels(500000);
284 // check how big (squarePixels) the preview is currently (with
285 // max value of MaxSquarePixels)
286 const sal_uInt32
nCurrentSquarePixels(
289 static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getWidth())
290 * static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getHeight())));
292 // check how big (squarePixels) the preview needs to be (with
293 // max value of MaxSquarePixels)
294 const sal_uInt32
nRequiredSquarePixels(
297 static_cast<sal_uInt32
>(maPreviewSize
.getWidth())
298 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight())));
300 // check if preview is big enough. Use a scaling value in
301 // the comparison to not get bigger at the last possible moment
302 // what may look awkward and pixelated (again). This means
303 // to use a percentage value - if we have at least
304 // that value of required pixels, we are good.
305 static const double fPreventAwkwardFactor(1.35); // 35%
306 if(nCurrentSquarePixels
>= static_cast<sal_uInt32
>(nRequiredSquarePixels
* fPreventAwkwardFactor
))
308 // at this place we also could add a mechanism to let the preview
309 // bitmap 'shrink' again if it is currently 'too big' -> bigger
310 // than required. I think this is not necessary for now.
312 // already sufficient, done.
316 // check if we have enough square pixels e.g for 8x8 pixels
317 if(nRequiredSquarePixels
< 64)
319 // too small preview - let it empty
323 // Calculate nPlannedSquarePixels which is the required size
324 // expanded by a percentage (with max value of MaxSquarePixels)
325 static const double fExtraSpaceFactor(1.65); // 65%
326 const sal_uInt32
nPlannedSquarePixels(
329 static_cast<sal_uInt32
>(maPreviewSize
.getWidth() * fExtraSpaceFactor
)
330 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight() * fExtraSpaceFactor
)));
332 // calculate back new width and height - it might have been
333 // truncated by MaxSquarePixels.
334 // We know that w*h == nPlannedSquarePixels and w/h == ratio
335 const double fRatio(static_cast<double>(maPreviewSize
.getWidth()) / static_cast<double>(maPreviewSize
.getHeight()));
336 const double fNewWidth(sqrt(static_cast<double>(nPlannedSquarePixels
) * fRatio
));
337 const double fNewHeight(sqrt(static_cast<double>(nPlannedSquarePixels
) / fRatio
));
338 const Size
aScaledSize(basegfx::fround(fNewWidth
), basegfx::fround(fNewHeight
));
340 // check if this eventual maximum is already reached
341 // due to having hit the MaxSquarePixels. Due to using
342 // an integer AspectRatio, we cannot make a numeric exact
343 // comparison - we need to compare if we are close
344 const double fScaledSizeSquare(static_cast<double>(aScaledSize
.getWidth() * aScaledSize
.getHeight()));
345 const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap
.GetSizePixel().getWidth() * maPreviewBitmap
.GetSizePixel().getHeight()));
347 // test as equal up to 0.1% (0.001)
348 if(fPreviewSizeSquare
!= 0.0 && fabs((fScaledSizeSquare
/ fPreviewSizeSquare
) - 1.0) < 0.001)
350 // maximum is reached, avoid bigger scaling
354 // create temporary VDev with requested Size and DPI.
355 // CAUTION: DPI *is* important here - it DIFFRERS from 75x75, usually 600x600 is used
356 ScopedVclPtrInstance
<VirtualDevice
> pPrerenderVDev(*Application::GetDefaultDevice());
357 pPrerenderVDev
->SetOutputSizePixel(aScaledSize
, false);
358 pPrerenderVDev
->SetReferenceDevice( mnDPIX
, mnDPIY
);
360 // calculate needed Scale for Metafile (using Size and DPI from VDev)
361 Size
aLogicSize( pPrerenderVDev
->PixelToLogic( pPrerenderVDev
->GetOutputSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
362 Size
aOrigSize( maOrigSize
);
363 if( aOrigSize
.Width() < 1 )
364 aOrigSize
.setWidth( aLogicSize
.Width() );
365 if( aOrigSize
.Height() < 1 )
366 aOrigSize
.setHeight( aLogicSize
.Height() );
367 double fScale
= double(aLogicSize
.Width())/double(aOrigSize
.Width());
370 // The display quality of the Preview is pretty ugly when
371 // FormControls are used. I made a deep-dive why this happens,
372 // and in principle the reason is the Mteafile::Scale used
373 // below. Since Metafile actions are integer, that floating point
374 // scale leads to rounduing errors that make the lines painting
375 // the FormControls disappear in the surrounding ClipRegions.
376 // That Scale cannot be avoided since the Metafile contains it's
377 // own SetMapMode commands which *will* be executed on ::Play,
378 // so the ::Scale is the only possibility fr Metafile currently:
379 // Giving a Size as parameter in ::Play will *not* work due to
380 // the relativeMapMode that gets created will fail on
381 // ::SetMapMode actions in the Metafile - and FormControls DO
382 // use ::SetMapMode(MapPixel).
383 // This can only be solved better in the future using Primitives
384 // which would allow any scale by embedding to a Transformation,
385 // but that would be a bigger rework.
386 // Until then, use this little 'trick' to improve qulatity.
387 // It uses the fact to empirically having tested that the quality
388 // gets really bad for FormControls starting by a scale factor
389 // smaller than 0.2 - that makes the ClipRegion overlap start.
390 // So - for now - try not to go below that.
391 static double fMinimumScale(0.2);
393 if(fScale
< fMinimumScale
)
395 fFactor
= fMinimumScale
/ fScale
;
396 fScale
= fMinimumScale
;
398 double fWidth(aScaledSize
.getWidth() * fFactor
);
399 double fHeight(aScaledSize
.getHeight() * fFactor
);
400 const double fNewNeededPixels(fWidth
* fHeight
);
402 // to not risk using too big bitmaps and runninig into
403 // memory problems, still limit to a useful factor is
404 // necessary, also empirically estimated to
405 // avoid the quality from collapsing (using a direct
406 // in-between , ceil'd result)
407 static double fMaximumQualitySquare(1396221.0);
409 if(fNewNeededPixels
> fMaximumQualitySquare
)
411 const double fCorrection(fMaximumQualitySquare
/fNewNeededPixels
);
412 fWidth
*= fCorrection
;
413 fHeight
*= fCorrection
;
414 fScale
*= fCorrection
;
417 const Size
aScaledSize2(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
418 pPrerenderVDev
->SetOutputSizePixel(aScaledSize2
, false);
419 aLogicSize
= pPrerenderVDev
->PixelToLogic( aScaledSize2
, MapMode( MapUnit::Map100thMM
) );
422 pPrerenderVDev
->EnableOutput();
423 pPrerenderVDev
->SetBackground( Wallpaper(COL_WHITE
) );
424 pPrerenderVDev
->Erase();
425 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
427 pPrerenderVDev
->SetDrawMode( pPrerenderVDev
->GetDrawMode() |
428 ( DrawModeFlags::GrayLine
| DrawModeFlags::GrayFill
| DrawModeFlags::GrayText
|
429 DrawModeFlags::GrayBitmap
| DrawModeFlags::GrayGradient
) );
431 // Copy, Scale and Paint Metafile
432 GDIMetaFile
aMtf( maMtf
);
434 aMtf
.Scale( fScale
, fScale
);
436 aMtf
.Play( pPrerenderVDev
.get(), Point( 0, 0 ), aLogicSize
);
438 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
439 maPreviewBitmap
= pPrerenderVDev
->GetBitmapEx(Point(0, 0), pPrerenderVDev
->GetOutputSizePixel());
443 // Correct to needed size, BmpScaleFlag::Interpolate is acceptable,
444 // but BmpScaleFlag::BestQuality is just better. In case of time
445 // constraints, change to Interpolate would be possible
446 maPreviewBitmap
.Scale(aScaledSize
, BmpScaleFlag::BestQuality
);
450 PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow()
451 : mnOrderMode( NupOrderType::LRTB
)
457 void PrintDialog::ShowNupOrderWindow::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
460 pDrawingArea
->set_size_request(aSize
.Width(), aSize
.Height());
461 CustomWidgetController::SetDrawingArea(pDrawingArea
);
462 SetOutputSizePixel(aSize
);
465 void PrintDialog::ShowNupOrderWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& /*i_rRect*/)
467 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
468 rRenderContext
.SetTextColor(rRenderContext
.GetSettings().GetStyleSettings().GetFieldTextColor());
469 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFieldColor()));
470 rRenderContext
.Erase();
472 int nPages
= mnRows
* mnColumns
;
473 Font
aFont(rRenderContext
.GetSettings().GetStyleSettings().GetFieldFont());
474 aFont
.SetFontSize(Size(0, 24));
475 rRenderContext
.SetFont(aFont
);
476 Size
aSampleTextSize(rRenderContext
.GetTextWidth(OUString::number(nPages
+ 1)), rRenderContext
.GetTextHeight());
477 Size
aOutSize(GetOutputSizePixel());
478 Size
aSubSize(aOutSize
.Width() / mnColumns
, aOutSize
.Height() / mnRows
);
479 // calculate font size: shrink the sample text so it fits
480 double fX
= double(aSubSize
.Width()) / double(aSampleTextSize
.Width());
481 double fY
= double(aSubSize
.Height()) / double(aSampleTextSize
.Height());
482 double fScale
= (fX
< fY
) ? fX
: fY
;
483 tools::Long nFontHeight
= tools::Long(24.0 * fScale
) - 3;
486 aFont
.SetFontSize(Size( 0, nFontHeight
));
487 rRenderContext
.SetFont(aFont
);
488 tools::Long nTextHeight
= rRenderContext
.GetTextHeight();
489 for (int i
= 0; i
< nPages
; i
++)
491 OUString
aPageText(OUString::number(i
+ 1));
495 case NupOrderType::LRTB
:
496 nX
= (i
% mnColumns
);
497 nY
= (i
/ mnColumns
);
499 case NupOrderType::TBLR
:
503 case NupOrderType::RLTB
:
504 nX
= mnColumns
- 1 - (i
% mnColumns
);
505 nY
= (i
/ mnColumns
);
507 case NupOrderType::TBRL
:
508 nX
= mnColumns
- 1 - (i
/ mnRows
);
512 Size
aTextSize(rRenderContext
.GetTextWidth(aPageText
), nTextHeight
);
513 int nDeltaX
= (aSubSize
.Width() - aTextSize
.Width()) / 2;
514 int nDeltaY
= (aSubSize
.Height() - aTextSize
.Height()) / 2;
515 rRenderContext
.DrawText(Point(nX
* aSubSize
.Width() + nDeltaX
,
516 nY
* aSubSize
.Height() + nDeltaY
), aPageText
);
518 DecorationView
aDecorationView(&rRenderContext
);
519 aDecorationView
.DrawFrame(tools::Rectangle(Point(0, 0), aOutSize
), DrawFrameStyle::Group
);
522 Size
const & PrintDialog::getJobPageSize()
524 if( maFirstPageSize
.IsEmpty() )
526 maFirstPageSize
= maNupPortraitSize
;
528 if( maPController
->getPageCountProtected() > 0 )
530 PrinterController::PageSize aPageSize
= maPController
->getPageFile( 0, aMtf
, true );
531 maFirstPageSize
= aPageSize
.aSize
;
534 return maFirstPageSize
;
537 PrintDialog::PrintDialog(weld::Window
* i_pWindow
, const std::shared_ptr
<PrinterController
>& i_rController
)
538 : GenericDialogController(i_pWindow
, "vcl/ui/printdialog.ui", "PrintDialog")
539 , maPController( i_rController
)
540 , mxTabCtrl(m_xBuilder
->weld_notebook("tabcontrol"))
541 , mxScrolledWindow(m_xBuilder
->weld_scrolled_window("scrolledwindow"))
542 , mxPageLayoutFrame(m_xBuilder
->weld_frame("layoutframe"))
543 , mxPrinters(m_xBuilder
->weld_combo_box("printersbox"))
544 , mxStatusTxt(m_xBuilder
->weld_label("status"))
545 , mxSetupButton(m_xBuilder
->weld_button("setup"))
546 , mxCopyCountField(m_xBuilder
->weld_spin_button("copycount"))
547 , mxCollateBox(m_xBuilder
->weld_check_button("collate"))
548 , mxCollateImage(m_xBuilder
->weld_image("collateimage"))
549 , mxPageRangeEdit(m_xBuilder
->weld_entry("pagerange"))
550 , mxPageRangesRadioButton(m_xBuilder
->weld_radio_button("rbRangePages"))
551 , mxPaperSidesBox(m_xBuilder
->weld_combo_box("sidesbox"))
552 , mxSingleJobsBox(m_xBuilder
->weld_check_button("singlejobs"))
553 , mxReverseOrderBox(m_xBuilder
->weld_check_button("reverseorder"))
554 , mxOKButton(m_xBuilder
->weld_button("ok"))
555 , mxCancelButton(m_xBuilder
->weld_button("cancel"))
556 , mxHelpButton(m_xBuilder
->weld_button("help"))
557 , mxMoreOptionsBtn(m_xBuilder
->weld_button("moreoptionsbtn"))
558 , mxBackwardBtn(m_xBuilder
->weld_button("backward"))
559 , mxForwardBtn(m_xBuilder
->weld_button("forward"))
560 , mxFirstBtn(m_xBuilder
->weld_button("btnFirst"))
561 , mxLastBtn(m_xBuilder
->weld_button("btnLast"))
562 , mxPreviewBox(m_xBuilder
->weld_check_button("previewbox"))
563 , mxNumPagesText(m_xBuilder
->weld_label("totalnumpages"))
564 , mxPreview(new PrintPreviewWindow(this))
565 , mxPreviewWindow(new weld::CustomWeld(*m_xBuilder
, "preview", *mxPreview
))
566 , mxPageEdit(m_xBuilder
->weld_entry("pageedit"))
567 , mxPagesBtn(m_xBuilder
->weld_radio_button("pagespersheetbtn"))
568 , mxBrochureBtn(m_xBuilder
->weld_radio_button("brochure"))
569 , mxPagesBoxTitleTxt(m_xBuilder
->weld_label("pagespersheettxt"))
570 , mxNupPagesBox(m_xBuilder
->weld_combo_box("pagespersheetbox"))
571 , mxNupNumPagesTxt(m_xBuilder
->weld_label("pagestxt"))
572 , mxNupColEdt(m_xBuilder
->weld_spin_button("pagecols"))
573 , mxNupTimesTxt(m_xBuilder
->weld_label("by"))
574 , mxNupRowsEdt(m_xBuilder
->weld_spin_button("pagerows"))
575 , mxPageMarginTxt1(m_xBuilder
->weld_label("pagemargintxt1"))
576 , mxPageMarginEdt(m_xBuilder
->weld_metric_spin_button("pagemarginsb", FieldUnit::MM
))
577 , mxPageMarginTxt2(m_xBuilder
->weld_label("pagemargintxt2"))
578 , mxSheetMarginTxt1(m_xBuilder
->weld_label("sheetmargintxt1"))
579 , mxSheetMarginEdt(m_xBuilder
->weld_metric_spin_button("sheetmarginsb", FieldUnit::MM
))
580 , mxSheetMarginTxt2(m_xBuilder
->weld_label("sheetmargintxt2"))
581 , mxPaperSizeBox(m_xBuilder
->weld_combo_box("papersizebox"))
582 , mxOrientationBox(m_xBuilder
->weld_combo_box("pageorientationbox"))
583 , mxNupOrderTxt(m_xBuilder
->weld_label("labelorder"))
584 , mxNupOrderBox(m_xBuilder
->weld_combo_box("orderbox"))
585 , mxNupOrder(new ShowNupOrderWindow
)
586 , mxNupOrderWin(new weld::CustomWeld(*m_xBuilder
, "orderpreview", *mxNupOrder
))
587 , mxBorderCB(m_xBuilder
->weld_check_button("bordercb"))
588 , mxRangeExpander(m_xBuilder
->weld_expander("exRangeExpander"))
589 , mxLayoutExpander(m_xBuilder
->weld_expander("exLayoutExpander"))
590 , mxCustom(m_xBuilder
->weld_widget("customcontents"))
591 , maPrintToFileText( VclResId( SV_PRINT_TOFILE_TXT
) )
592 , maDefPrtText( VclResId( SV_PRINT_DEFPRT_TXT
) )
593 , maNoPageStr( VclResId( SV_PRINT_NOPAGES
) )
594 , maNoPreviewStr( VclResId( SV_PRINT_NOPREVIEW
) )
597 , mbCollateAlwaysOff(false)
598 , mbShowLayoutFrame( true )
599 , maUpdatePreviewIdle("Print Dialog Update Preview Idle")
600 , maUpdatePreviewNoCacheIdle("Print Dialog Update Preview (no cache) Idle")
602 // save printbutton text, gets exchanged occasionally with print to file
603 maPrintText
= mxOKButton
->get_label();
605 maPageStr
= mxNumPagesText
->get_label();
607 Printer::updatePrinters();
609 mxPrinters
->append_text(maPrintToFileText
);
610 // fill printer listbox
611 std::vector
< OUString
> rQueues( Printer::GetPrinterQueues() );
612 std::sort( rQueues
.begin(), rQueues
.end(), lcl_ListBoxCompare
);
613 for( const auto& rQueue
: rQueues
)
615 mxPrinters
->append_text(rQueue
);
617 // select current printer
618 if (mxPrinters
->find_text(maPController
->getPrinter()->GetName()) != -1)
619 mxPrinters
->set_active_text(maPController
->getPrinter()->GetName());
622 // fall back to last printer
623 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
624 OUString
aValue( pItem
->getValue( "PrintDialog",
626 if (mxPrinters
->find_text(aValue
) != -1)
628 mxPrinters
->set_active_text(aValue
);
629 maPController
->setPrinter( VclPtrInstance
<Printer
>( aValue
) );
633 // fall back to default printer
634 mxPrinters
->set_active_text(Printer::GetDefaultPrinterName());
635 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
639 // not printing to file
640 maPController
->resetPrinterOptions( false );
642 // update the text fields for the printer
645 // setup dependencies
646 checkControlDependencies();
648 // setup paper sides box
649 setupPaperSidesBox();
651 // set initial focus to "Number of copies"
652 mxCopyCountField
->grab_focus();
653 mxCopyCountField
->select_region(0, -1);
655 // setup sizes for N-Up
656 Size
aNupSize( maPController
->getPrinter()->PixelToLogic(
657 maPController
->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
658 if( maPController
->getPrinter()->GetOrientation() == Orientation::Landscape
)
660 maNupLandscapeSize
= aNupSize
;
661 // coverity[swapped_arguments : FALSE] - this is in the correct order
662 maNupPortraitSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
666 maNupPortraitSize
= aNupSize
;
667 // coverity[swapped_arguments : FALSE] - this is in the correct order
668 maNupLandscapeSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
671 maUpdatePreviewIdle
.SetPriority(TaskPriority::POST_PAINT
);
672 maUpdatePreviewIdle
.SetInvokeHandler(LINK( this, PrintDialog
, updatePreviewIdle
));
673 maUpdatePreviewNoCacheIdle
.SetPriority(TaskPriority::POST_PAINT
);
674 maUpdatePreviewNoCacheIdle
.SetInvokeHandler(LINK(this, PrintDialog
, updatePreviewNoCacheIdle
));
676 initFromMultiPageSetup( maPController
->getMultipage() );
678 // setup optional UI options set by application
681 // hide layout frame if unwanted
682 mxPageLayoutFrame
->set_visible(mbShowLayoutFrame
);
684 // restore settings from last run
688 mxOKButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
689 mxCancelButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
690 mxHelpButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
691 mxSetupButton
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
692 mxBackwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
693 mxForwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
694 mxFirstBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
695 mxLastBtn
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
696 mxPreviewBox
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
697 mxBorderCB
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
700 mxReverseOrderBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
701 mxCollateBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
702 mxSingleJobsBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
703 mxPagesBtn
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
706 mxPrinters
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
707 mxPaperSidesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
708 mxNupPagesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
709 mxOrientationBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
710 mxNupOrderBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
711 mxPaperSizeBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
714 mxPageEdit
->connect_activate( LINK( this, PrintDialog
, ActivateHdl
) );
715 mxPageEdit
->connect_focus_out( LINK( this, PrintDialog
, FocusOutHdl
) );
716 mxCopyCountField
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
717 mxNupColEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
718 mxNupRowsEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
719 mxPageMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
720 mxSheetMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
722 updateNupFromPages();
724 // tdf#129180 Delay setting the default value in the Paper Size list
725 // set paper sizes listbox
728 mxRangeExpander
->set_expanded(
729 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::get());
730 mxLayoutExpander
->set_expanded(
731 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::get());
733 // lock the dialog height, regardless of later expander state
734 mxScrolledWindow
->set_size_request(
735 mxScrolledWindow
->get_preferred_size().Width() + mxScrolledWindow
->get_vscroll_width(),
738 m_xDialog
->set_centered_on_parent(true);
741 PrintDialog::~PrintDialog()
743 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
744 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::set(mxRangeExpander
->get_expanded(), batch
);
745 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::set(mxLayoutExpander
->get_expanded(), batch
);
749 void PrintDialog::setupPaperSidesBox()
751 DuplexMode eDuplex
= maPController
->getPrinter()->GetDuplexMode();
753 if ( eDuplex
== DuplexMode::Unknown
|| isPrintToFile() )
755 mxPaperSidesBox
->set_active( 0 );
756 mxPaperSidesBox
->set_sensitive( false );
760 mxPaperSidesBox
->set_active( static_cast<sal_Int32
>(eDuplex
) - 1 );
761 mxPaperSidesBox
->set_sensitive( true );
765 void PrintDialog::storeToSettings()
767 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
769 pItem
->setValue( "PrintDialog",
771 isPrintToFile() ? Printer::GetDefaultPrinterName()
772 : mxPrinters
->get_active_text() );
774 pItem
->setValue( "PrintDialog",
776 mxTabCtrl
->get_tab_label_text(mxTabCtrl
->get_current_page_ident()));
778 pItem
->setValue( "PrintDialog",
780 OStringToOUString(m_xDialog
->get_window_state(WindowStateMask::All
), RTL_TEXTENCODING_UTF8
) );
782 pItem
->setValue( "PrintDialog",
784 mxCopyCountField
->get_text() );
786 pItem
->setValue( "PrintDialog",
788 mxCollateBox
->get_active() ? OUString("true") :
791 pItem
->setValue( "PrintDialog",
793 mxSingleJobsBox
->get_active() ? OUString("true") :
796 pItem
->setValue( "PrintDialog",
798 hasPreview() ? OUString("true") :
804 void PrintDialog::readFromSettings()
806 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
808 // read last selected tab page; if it exists, activate it
809 OUString aValue
= pItem
->getValue( "PrintDialog",
811 sal_uInt16 nCount
= mxTabCtrl
->get_n_pages();
812 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
814 OString sPageId
= mxTabCtrl
->get_page_ident(i
);
815 if (aValue
== mxTabCtrl
->get_tab_label_text(sPageId
))
817 mxTabCtrl
->set_current_page(sPageId
);
822 // persistent window state
823 aValue
= pItem
->getValue( "PrintDialog",
825 if (!aValue
.isEmpty())
826 m_xDialog
->set_window_state(OUStringToOString(aValue
, RTL_TEXTENCODING_UTF8
));
829 aValue
= pItem
->getValue( "PrintDialog",
831 if( aValue
.equalsIgnoreAsciiCase("alwaysoff") )
833 mbCollateAlwaysOff
= true;
834 mxCollateBox
->set_active( false );
835 mxCollateBox
->set_sensitive( false );
839 mbCollateAlwaysOff
= false;
840 aValue
= pItem
->getValue( "PrintDialog",
842 mxCollateBox
->set_active( aValue
.equalsIgnoreAsciiCase("true") );
845 // collate single jobs
846 aValue
= pItem
->getValue( "PrintDialog",
847 "CollateSingleJobs" );
848 mxSingleJobsBox
->set_active(aValue
.equalsIgnoreAsciiCase("true"));
851 aValue
= pItem
->getValue( "PrintDialog",
853 if ( aValue
.equalsIgnoreAsciiCase("false") )
854 mxPreviewBox
->set_active( false );
856 mxPreviewBox
->set_active( true );
860 void PrintDialog::setPaperSizes()
862 mxPaperSizeBox
->clear();
864 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
865 mePaper
= aPrt
->GetPaper();
867 if ( isPrintToFile() )
869 mxPaperSizeBox
->set_sensitive( false );
873 for (int nPaper
= 0; nPaper
< aPrt
->GetPaperInfoCount(); nPaper
++)
875 PaperInfo aInfo
= aPrt
->GetPaperInfo( nPaper
);
876 aInfo
.doSloppyFit(true);
877 Paper ePaper
= aInfo
.getPaper();
879 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
880 MapUnit eUnit
= MapUnit::MapMM
;
882 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
884 eUnit
= MapUnit::Map100thInch
;
887 Size aSize
= aPrt
->GetPaperSize( nPaper
);
888 Size
aLogicPaperSize( OutputDevice::LogicToLogic( aSize
, MapMode( MapUnit::Map100thMM
), MapMode( eUnit
) ) );
890 OUString
aWidth( rLocWrap
.getNum( aLogicPaperSize
.Width(), nDigits
) );
891 OUString
aHeight( rLocWrap
.getNum( aLogicPaperSize
.Height(), nDigits
) );
892 OUString aUnit
= eUnit
== MapUnit::MapMM
? OUString("mm") : OUString("in");
893 OUString aPaperName
= Printer::GetPaperName( ePaper
) + " " + aWidth
+ aUnit
+ " x " + aHeight
+ aUnit
;
895 mxPaperSizeBox
->append_text(aPaperName
);
897 if ( ePaper
== mePaper
)
898 mxPaperSizeBox
->set_active( nPaper
);
901 mxPaperSizeBox
->set_sensitive( true );
905 void PrintDialog::updatePrinterText()
907 const OUString
aDefPrt( Printer::GetDefaultPrinterName() );
908 const QueueInfo
* pInfo
= Printer::GetQueueInfo( mxPrinters
->get_active_text(), true );
911 // FIXME: status text
913 if( aDefPrt
== pInfo
->GetPrinterName() )
914 aStatus
= maDefPrtText
;
915 mxStatusTxt
->set_label( aStatus
);
919 mxStatusTxt
->set_label( OUString() );
923 void PrintDialog::setPreviewText()
925 OUString
aNewText( maPageStr
.replaceFirst( "%n", OUString::number( mnCachedPages
) ) );
926 mxNumPagesText
->set_label( aNewText
);
929 IMPL_LINK_NOARG(PrintDialog
, updatePreviewIdle
, Timer
*, void)
931 preparePreview(true);
934 IMPL_LINK_NOARG(PrintDialog
, updatePreviewNoCacheIdle
, Timer
*, void)
936 preparePreview(false);
939 void PrintDialog::preparePreview( bool i_bMayUseCache
)
941 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
942 Size aCurPageSize
= aPrt
->PixelToLogic( aPrt
->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) );
943 // tdf#123076 Get paper size for the preview top label
944 mePaper
= aPrt
->GetPaper();
947 // page range may have changed depending on options
948 sal_Int32 nPages
= maPController
->getFilteredPageCount();
949 mnCachedPages
= nPages
;
955 mxPreview
->setPreview( aMtf
, aCurPageSize
,
956 Printer::GetPaperName( mePaper
),
958 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
959 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
962 mxForwardBtn
->set_sensitive( false );
963 mxBackwardBtn
->set_sensitive( false );
964 mxFirstBtn
->set_sensitive( false );
965 mxLastBtn
->set_sensitive( false );
967 mxPageEdit
->set_sensitive( false );
972 if( mnCurPage
>= nPages
)
973 mnCurPage
= nPages
-1;
976 mxPageEdit
->set_text(OUString::number(mnCurPage
+ 1));
978 const MapMode
aMapMode( MapUnit::Map100thMM
);
981 PrinterController::PageSize aPageSize
=
982 maPController
->getFilteredPageFile( mnCurPage
, aMtf
, i_bMayUseCache
);
983 if( ! aPageSize
.bFullPaper
)
985 Point
aOff( aPrt
->PixelToLogic( aPrt
->GetPageOffsetPixel(), aMapMode
) );
986 aMtf
.Move( aOff
.X(), aOff
.Y() );
990 mxPreview
->setPreview( aMtf
, aCurPageSize
,
991 Printer::GetPaperName( mePaper
),
992 nPages
> 0 ? OUString() : maNoPageStr
,
993 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
994 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
997 mxForwardBtn
->set_sensitive( mnCurPage
< nPages
-1 );
998 mxBackwardBtn
->set_sensitive( mnCurPage
!= 0 );
999 mxFirstBtn
->set_sensitive( mnCurPage
!= 0 );
1000 mxLastBtn
->set_sensitive( mnCurPage
< nPages
-1 );
1001 mxPageEdit
->set_sensitive( nPages
> 1 );
1004 void PrintDialog::updateOrientationBox( const bool bAutomatic
)
1008 Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1009 mxOrientationBox
->set_active( static_cast<sal_Int32
>(eOrientation
) + 1 );
1011 else if ( hasOrientationChanged() )
1013 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1017 bool PrintDialog::hasOrientationChanged() const
1019 const int nOrientation
= mxOrientationBox
->get_active();
1020 const Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1022 return (nOrientation
== ORIENTATION_LANDSCAPE
&& eOrientation
== Orientation::Portrait
)
1023 || (nOrientation
== ORIENTATION_PORTRAIT
&& eOrientation
== Orientation::Landscape
);
1026 // make sure paper size matches paper orientation
1027 void PrintDialog::checkPaperSize( Size
& rPaperSize
)
1029 Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1030 if ( (eOrientation
== Orientation::Portrait
&& rPaperSize
.Width() > rPaperSize
.Height()) ||
1031 (eOrientation
== Orientation::Landscape
&& rPaperSize
.Width() < rPaperSize
.Height()) )
1033 // coverity[swapped-arguments : FALSE] - this is in the correct order
1034 rPaperSize
= Size( rPaperSize
.Height(), rPaperSize
.Width() );
1038 // Always use this function to set paper orientation to make sure everything behaves well
1039 void PrintDialog::setPaperOrientation( Orientation eOrientation
)
1041 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1042 aPrt
->SetOrientation( eOrientation
);
1044 // check if it's necessary to swap width and height of paper
1045 if ( maPController
->isPaperSizeFromUser() )
1047 Size
& aPaperSize
= maPController
->getPaperSizeFromUser();
1048 checkPaperSize( aPaperSize
);
1050 else if ( maPController
->getPapersizeFromSetup() )
1052 Size
& aPaperSize
= maPController
->getPaperSizeSetup();
1053 checkPaperSize( aPaperSize
);
1057 void PrintDialog::checkControlDependencies()
1059 if (mxCopyCountField
->get_value() > 1)
1061 mxCollateBox
->set_sensitive( !mbCollateAlwaysOff
);
1062 mxSingleJobsBox
->set_sensitive( mxCollateBox
->get_active() );
1066 mxCollateBox
->set_sensitive( false );
1067 mxSingleJobsBox
->set_sensitive( false );
1070 OUString
aImg(mxCollateBox
->get_active() ? OUString(SV_PRINT_COLLATE_BMP
) : OUString(SV_PRINT_NOCOLLATE_BMP
));
1072 mxCollateImage
->set_from_icon_name(aImg
);
1074 // enable setup button only for printers that can be setup
1075 bool bHaveSetup
= maPController
->getPrinter()->HasSupport( PrinterSupport::SetupDialog
);
1076 mxSetupButton
->set_sensitive(bHaveSetup
);
1079 void PrintDialog::checkOptionalControlDependencies()
1081 for( const auto& rEntry
: maControlToPropertyMap
)
1083 bool bShouldbeEnabled
= maPController
->isUIOptionEnabled( rEntry
.second
);
1085 if (bShouldbeEnabled
&& dynamic_cast<weld::RadioButton
*>(rEntry
.first
))
1087 auto r_it
= maControlToNumValMap
.find( rEntry
.first
);
1088 if( r_it
!= maControlToNumValMap
.end() )
1090 bShouldbeEnabled
= maPController
->isUIChoiceEnabled( rEntry
.second
, r_it
->second
);
1094 bool bIsEnabled
= rEntry
.first
->get_sensitive();
1095 // Enable does not do a change check first, so can be less cheap than expected
1096 if (bShouldbeEnabled
!= bIsEnabled
)
1097 rEntry
.first
->set_sensitive( bShouldbeEnabled
);
1101 void PrintDialog::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup
& i_rMPS
)
1103 mxNupOrderWin
->show();
1104 mxPagesBtn
->set_active(true);
1105 mxBrochureBtn
->hide();
1107 // setup field units for metric fields
1108 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
1109 FieldUnit eUnit
= FieldUnit::MM
;
1110 sal_uInt16 nDigits
= 0;
1111 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
1113 eUnit
= FieldUnit::INCH
;
1117 mxPageMarginEdt
->set_unit( eUnit
);
1118 mxSheetMarginEdt
->set_unit( eUnit
);
1121 mxPageMarginEdt
->set_digits( nDigits
);
1122 mxSheetMarginEdt
->set_digits( nDigits
);
1124 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( i_rMPS
.nLeftMargin
), FieldUnit::MM_100TH
);
1125 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( i_rMPS
.nHorizontalSpacing
), FieldUnit::MM_100TH
);
1126 mxBorderCB
->set_active( i_rMPS
.bDrawBorder
);
1127 mxNupRowsEdt
->set_value( i_rMPS
.nRows
);
1128 mxNupColEdt
->set_value( i_rMPS
.nColumns
);
1129 mxNupOrderBox
->set_active( static_cast<sal_Int32
>(i_rMPS
.nOrder
) );
1130 if( i_rMPS
.nRows
!= 1 || i_rMPS
.nColumns
!= 1 )
1132 mxNupPagesBox
->set_active( mxNupPagesBox
->get_count()-1 );
1133 showAdvancedControls( true );
1134 mxNupOrder
->setValues( i_rMPS
.nOrder
, i_rMPS
.nColumns
, i_rMPS
.nRows
);
1138 void PrintDialog::updateNup( bool i_bMayUseCache
)
1140 int nRows
= mxNupRowsEdt
->get_value();
1141 int nCols
= mxNupColEdt
->get_value();
1142 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1143 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1145 PrinterController::MultiPageSetup aMPS
;
1147 aMPS
.nColumns
= nCols
;
1151 aMPS
.nBottomMargin
= nSheetMargin
;
1153 aMPS
.nHorizontalSpacing
=
1154 aMPS
.nVerticalSpacing
= nPageMargin
;
1156 aMPS
.bDrawBorder
= mxBorderCB
->get_active();
1158 aMPS
.nOrder
= static_cast<NupOrderType
>(mxNupOrderBox
->get_active());
1160 int nOrientationMode
= mxOrientationBox
->get_active();
1161 if( nOrientationMode
== ORIENTATION_LANDSCAPE
)
1162 aMPS
.aPaperSize
= maNupLandscapeSize
;
1163 else if( nOrientationMode
== ORIENTATION_PORTRAIT
)
1164 aMPS
.aPaperSize
= maNupPortraitSize
;
1165 else // automatic mode
1167 // get size of first real page to see if it is portrait or landscape
1168 // we assume same page sizes for all the pages for this
1169 Size aPageSize
= getJobPageSize();
1171 Size
aMultiSize( aPageSize
.Width() * nCols
, aPageSize
.Height() * nRows
);
1172 if( aMultiSize
.Width() > aMultiSize
.Height() ) // fits better on landscape
1174 aMPS
.aPaperSize
= maNupLandscapeSize
;
1175 setPaperOrientation( Orientation::Landscape
);
1179 aMPS
.aPaperSize
= maNupPortraitSize
;
1180 setPaperOrientation( Orientation::Portrait
);
1184 maPController
->setMultipage( aMPS
);
1186 mxNupOrder
->setValues( aMPS
.nOrder
, nCols
, nRows
);
1189 maUpdatePreviewIdle
.Start();
1191 maUpdatePreviewNoCacheIdle
.Start();
1194 void PrintDialog::updateNupFromPages( bool i_bMayUseCache
)
1196 int nPages
= mxNupPagesBox
->get_active_id().toInt32();
1197 int nRows
= mxNupRowsEdt
->get_value();
1198 int nCols
= mxNupColEdt
->get_value();
1199 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1200 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1201 bool bCustom
= false;
1209 else if( nPages
== 2 || nPages
== 4 || nPages
== 6 || nPages
== 9 || nPages
== 16 )
1211 Size
aJobPageSize( getJobPageSize() );
1212 bool bPortrait
= aJobPageSize
.Width() < aJobPageSize
.Height();
1226 else if( nPages
== 4 )
1228 else if( nPages
== 6 )
1241 else if( nPages
== 9 )
1243 else if( nPages
== 16 )
1253 // set upper limits for margins based on job page size and rows/columns
1254 Size
aSize( getJobPageSize() );
1256 // maximum sheet distance: 1/2 sheet
1257 tools::Long nHorzMax
= aSize
.Width()/2;
1258 tools::Long nVertMax
= aSize
.Height()/2;
1259 if( nSheetMargin
> nHorzMax
)
1260 nSheetMargin
= nHorzMax
;
1261 if( nSheetMargin
> nVertMax
)
1262 nSheetMargin
= nVertMax
;
1264 mxSheetMarginEdt
->set_max(
1265 mxSheetMarginEdt
->normalize(
1266 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1268 // maximum page distance
1269 nHorzMax
= (aSize
.Width() - 2*nSheetMargin
);
1271 nHorzMax
/= (nCols
-1);
1272 nVertMax
= (aSize
.Height() - 2*nSheetMargin
);
1274 nHorzMax
/= (nRows
-1);
1276 if( nPageMargin
> nHorzMax
)
1277 nPageMargin
= nHorzMax
;
1278 if( nPageMargin
> nVertMax
)
1279 nPageMargin
= nVertMax
;
1281 mxPageMarginEdt
->set_max(
1282 mxSheetMarginEdt
->normalize(
1283 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1286 mxNupRowsEdt
->set_value( nRows
);
1287 mxNupColEdt
->set_value( nCols
);
1288 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( nPageMargin
), FieldUnit::MM_100TH
);
1289 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( nSheetMargin
), FieldUnit::MM_100TH
);
1291 showAdvancedControls( bCustom
);
1292 updateNup( i_bMayUseCache
);
1295 void PrintDialog::enableNupControls( bool bEnable
)
1297 mxNupPagesBox
->set_sensitive( bEnable
);
1298 mxNupNumPagesTxt
->set_sensitive( bEnable
);
1299 mxNupColEdt
->set_sensitive( bEnable
);
1300 mxNupTimesTxt
->set_sensitive( bEnable
);
1301 mxNupRowsEdt
->set_sensitive( bEnable
);
1302 mxPageMarginTxt1
->set_sensitive( bEnable
);
1303 mxPageMarginEdt
->set_sensitive( bEnable
);
1304 mxPageMarginTxt2
->set_sensitive( bEnable
);
1305 mxSheetMarginTxt1
->set_sensitive( bEnable
);
1306 mxSheetMarginEdt
->set_sensitive( bEnable
);
1307 mxSheetMarginTxt2
->set_sensitive( bEnable
);
1308 mxNupOrderTxt
->set_sensitive( bEnable
);
1309 mxNupOrderBox
->set_sensitive( bEnable
);
1310 mxNupOrderWin
->set_sensitive( bEnable
);
1311 mxBorderCB
->set_sensitive( bEnable
);
1314 void PrintDialog::showAdvancedControls( bool i_bShow
)
1316 mxNupNumPagesTxt
->set_visible( i_bShow
);
1317 mxNupColEdt
->set_visible( i_bShow
);
1318 mxNupTimesTxt
->set_visible( i_bShow
);
1319 mxNupRowsEdt
->set_visible( i_bShow
);
1320 mxPageMarginTxt1
->set_visible( i_bShow
);
1321 mxPageMarginEdt
->set_visible( i_bShow
);
1322 mxPageMarginTxt2
->set_visible( i_bShow
);
1323 mxSheetMarginTxt1
->set_visible( i_bShow
);
1324 mxSheetMarginEdt
->set_visible( i_bShow
);
1325 mxSheetMarginTxt2
->set_visible( i_bShow
);
1330 void setHelpId( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpIds
, sal_Int32 i_nIndex
)
1332 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpIds
.getLength() )
1333 i_pWindow
->set_help_id( OUStringToOString( i_rHelpIds
.getConstArray()[i_nIndex
], RTL_TEXTENCODING_UTF8
) );
1336 void setHelpText( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpTexts
, sal_Int32 i_nIndex
)
1338 // without a help text set and the correct smartID,
1339 // help texts will be retrieved from the online help system
1340 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpTexts
.getLength() )
1341 i_pWindow
->set_tooltip_text(i_rHelpTexts
.getConstArray()[i_nIndex
]);
1345 void PrintDialog::setupOptionalUI()
1347 const Sequence
< PropertyValue
>& rOptions( maPController
->getUIOptions() );
1348 for( const auto& rOption
: rOptions
)
1350 if (rOption
.Name
== "OptionsUIFile")
1352 OUString sOptionsUIFile
;
1353 rOption
.Value
>>= sOptionsUIFile
;
1354 mxCustomOptionsUIBuilder
.reset(Application::CreateBuilder(mxCustom
.get(), sOptionsUIFile
));
1355 std::unique_ptr
<weld::Container
> xWindow
= mxCustomOptionsUIBuilder
->weld_container("box");
1360 Sequence
< beans::PropertyValue
> aOptProp
;
1361 rOption
.Value
>>= aOptProp
;
1363 // extract ui element
1367 OUString aPropertyName
;
1368 Sequence
< OUString
> aChoices
;
1369 Sequence
< sal_Bool
> aChoicesDisabled
;
1370 Sequence
< OUString
> aHelpTexts
;
1371 Sequence
< OUString
> aIDs
;
1372 Sequence
< OUString
> aHelpIds
;
1373 sal_Int64 nMinValue
= 0, nMaxValue
= 0;
1374 OUString aGroupingHint
;
1376 for( const beans::PropertyValue
& rEntry
: std::as_const(aOptProp
) )
1378 if ( rEntry
.Name
== "ID" )
1380 rEntry
.Value
>>= aIDs
;
1381 aID
= OUStringToOString(aIDs
[0], RTL_TEXTENCODING_UTF8
);
1383 if ( rEntry
.Name
== "Text" )
1385 rEntry
.Value
>>= aText
;
1387 else if ( rEntry
.Name
== "ControlType" )
1389 rEntry
.Value
>>= aCtrlType
;
1391 else if ( rEntry
.Name
== "Choices" )
1393 rEntry
.Value
>>= aChoices
;
1395 else if ( rEntry
.Name
== "ChoicesDisabled" )
1397 rEntry
.Value
>>= aChoicesDisabled
;
1399 else if ( rEntry
.Name
== "Property" )
1402 rEntry
.Value
>>= aVal
;
1403 aPropertyName
= aVal
.Name
;
1405 else if ( rEntry
.Name
== "Enabled" )
1408 else if ( rEntry
.Name
== "GroupingHint" )
1410 rEntry
.Value
>>= aGroupingHint
;
1412 else if ( rEntry
.Name
== "DependsOnName" )
1415 else if ( rEntry
.Name
== "DependsOnEntry" )
1418 else if ( rEntry
.Name
== "AttachToDependency" )
1421 else if ( rEntry
.Name
== "MinValue" )
1423 rEntry
.Value
>>= nMinValue
;
1425 else if ( rEntry
.Name
== "MaxValue" )
1427 rEntry
.Value
>>= nMaxValue
;
1429 else if ( rEntry
.Name
== "HelpText" )
1431 if( ! (rEntry
.Value
>>= aHelpTexts
) )
1434 if( rEntry
.Value
>>= aHelpText
)
1436 aHelpTexts
.realloc( 1 );
1437 *aHelpTexts
.getArray() = aHelpText
;
1441 else if ( rEntry
.Name
== "HelpId" )
1443 if( ! (rEntry
.Value
>>= aHelpIds
) )
1446 if( rEntry
.Value
>>= aHelpId
)
1448 aHelpIds
.realloc( 1 );
1449 *aHelpIds
.getArray() = aHelpId
;
1453 else if ( rEntry
.Name
== "HintNoLayoutPage" )
1455 bool bHasLayoutFrame
= false;
1456 rEntry
.Value
>>= bHasLayoutFrame
;
1457 mbShowLayoutFrame
= !bHasLayoutFrame
;
1461 if (aCtrlType
== "Group")
1465 weld::Container
* pPage
= mxTabCtrl
->get_page(aID
);
1469 mxTabCtrl
->set_tab_label_text(aID
, aText
);
1472 if (aHelpIds
.hasElements())
1473 pPage
->set_help_id(OUStringToOString(aHelpIds
.getConstArray()[0], RTL_TEXTENCODING_UTF8
));
1476 if (aHelpTexts
.hasElements())
1477 pPage
->set_tooltip_text(aHelpTexts
.getConstArray()[0]);
1481 else if (aCtrlType
== "Subgroup" && !aID
.isEmpty())
1483 std::unique_ptr
<weld::Widget
> xWidget
;
1484 // since 'New Print Dialog Design' fromwhich in calc is not a frame anymore
1485 if (aID
== "fromwhich")
1487 std::unique_ptr
<weld::Label
> xLabel
= m_xBuilder
->weld_label(aID
);
1488 xLabel
->set_label(aText
);
1489 xWidget
= std::move(xLabel
);
1493 std::unique_ptr
<weld::Frame
> xFrame
= m_xBuilder
->weld_frame(aID
);
1494 if (!xFrame
&& mxCustomOptionsUIBuilder
)
1495 xFrame
= mxCustomOptionsUIBuilder
->weld_frame(aID
);
1498 xFrame
->set_label(aText
);
1499 xWidget
= std::move(xFrame
);
1507 setHelpId(xWidget
.get(), aHelpIds
, 0);
1509 setHelpText(xWidget
.get(), aHelpTexts
, 0);
1514 else if( aCtrlType
== "Bool" && aGroupingHint
== "LayoutPage" && aPropertyName
== "PrintProspect" )
1516 mxBrochureBtn
->set_label(aText
);
1517 mxBrochureBtn
->show();
1520 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1522 pVal
->Value
>>= bVal
;
1523 mxBrochureBtn
->set_active( bVal
);
1524 mxBrochureBtn
->set_sensitive( maPController
->isUIOptionEnabled( aPropertyName
) && pVal
!= nullptr );
1525 mxBrochureBtn
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
1527 maPropertyToWindowMap
[aPropertyName
].emplace_back(mxBrochureBtn
.get());
1528 maControlToPropertyMap
[mxBrochureBtn
.get()] = aPropertyName
;
1531 setHelpId( mxBrochureBtn
.get(), aHelpIds
, 0 );
1533 setHelpText( mxBrochureBtn
.get(), aHelpTexts
, 0 );
1535 else if (aCtrlType
== "Bool")
1538 std::unique_ptr
<weld::CheckButton
> xNewBox
= m_xBuilder
->weld_check_button(aID
);
1539 if (!xNewBox
&& mxCustomOptionsUIBuilder
)
1540 xNewBox
= mxCustomOptionsUIBuilder
->weld_check_button(aID
);
1544 xNewBox
->set_label( aText
);
1548 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1550 pVal
->Value
>>= bVal
;
1551 xNewBox
->set_active( bVal
);
1552 xNewBox
->connect_toggled( LINK( this, PrintDialog
, UIOption_CheckHdl
) );
1554 maExtraControls
.emplace_back(std::move(xNewBox
));
1556 weld::Widget
* pWidget
= maExtraControls
.back().get();
1558 maPropertyToWindowMap
[aPropertyName
].emplace_back(pWidget
);
1559 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1562 setHelpId(pWidget
, aHelpIds
, 0);
1564 setHelpText(pWidget
, aHelpTexts
, 0);
1566 else if (aCtrlType
== "Radio")
1568 sal_Int32 nCurHelpText
= 0;
1571 sal_Int32 nSelectVal
= 0;
1572 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1573 if( pVal
&& pVal
->Value
.hasValue() )
1574 pVal
->Value
>>= nSelectVal
;
1575 for( sal_Int32 m
= 0; m
< aChoices
.getLength(); m
++ )
1577 aID
= OUStringToOString(aIDs
[m
], RTL_TEXTENCODING_UTF8
);
1578 std::unique_ptr
<weld::RadioButton
> xBtn
= m_xBuilder
->weld_radio_button(aID
);
1579 if (!xBtn
&& mxCustomOptionsUIBuilder
)
1580 xBtn
= mxCustomOptionsUIBuilder
->weld_radio_button(aID
);
1584 xBtn
->set_label( aChoices
[m
] );
1585 xBtn
->set_active( m
== nSelectVal
);
1586 xBtn
->connect_toggled( LINK( this, PrintDialog
, UIOption_RadioHdl
) );
1587 if( aChoicesDisabled
.getLength() > m
&& aChoicesDisabled
[m
] )
1588 xBtn
->set_sensitive( false );
1591 maExtraControls
.emplace_back(std::move(xBtn
));
1593 weld::Widget
* pWidget
= maExtraControls
.back().get();
1595 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1596 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1597 maControlToNumValMap
[pWidget
] = m
;
1600 setHelpId( pWidget
, aHelpIds
, nCurHelpText
);
1602 setHelpText( pWidget
, aHelpTexts
, nCurHelpText
);
1606 else if ( aCtrlType
== "List" )
1608 std::unique_ptr
<weld::ComboBox
> xList
= m_xBuilder
->weld_combo_box(aID
);
1609 if (!xList
&& mxCustomOptionsUIBuilder
)
1610 xList
= mxCustomOptionsUIBuilder
->weld_combo_box(aID
);
1615 for( const auto& rChoice
: std::as_const(aChoices
) )
1616 xList
->append_text(rChoice
);
1618 sal_Int32 nSelectVal
= 0;
1619 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1620 if( pVal
&& pVal
->Value
.hasValue() )
1621 pVal
->Value
>>= nSelectVal
;
1622 xList
->set_active(nSelectVal
);
1623 xList
->connect_changed( LINK( this, PrintDialog
, UIOption_SelectHdl
) );
1626 maExtraControls
.emplace_back(std::move(xList
));
1628 weld::Widget
* pWidget
= maExtraControls
.back().get();
1630 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1631 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1634 setHelpId( pWidget
, aHelpIds
, 0 );
1636 setHelpText( pWidget
, aHelpTexts
, 0 );
1638 else if ( aCtrlType
== "Range" )
1640 std::unique_ptr
<weld::SpinButton
> xField
= m_xBuilder
->weld_spin_button(aID
);
1641 if (!xField
&& mxCustomOptionsUIBuilder
)
1642 xField
= mxCustomOptionsUIBuilder
->weld_spin_button(aID
);
1646 // set min/max and current value
1647 if(nMinValue
!= nMaxValue
)
1648 xField
->set_range(nMinValue
, nMaxValue
);
1650 sal_Int64 nCurVal
= 0;
1651 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1652 if( pVal
&& pVal
->Value
.hasValue() )
1653 pVal
->Value
>>= nCurVal
;
1654 xField
->set_value( nCurVal
);
1655 xField
->connect_value_changed( LINK( this, PrintDialog
, UIOption_SpinModifyHdl
) );
1658 maExtraControls
.emplace_back(std::move(xField
));
1660 weld::Widget
* pWidget
= maExtraControls
.back().get();
1662 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1663 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1666 setHelpId( pWidget
, aHelpIds
, 0 );
1668 setHelpText( pWidget
, aHelpTexts
, 0 );
1670 else if (aCtrlType
== "Edit")
1672 std::unique_ptr
<weld::Entry
> xField
= m_xBuilder
->weld_entry(aID
);
1673 if (!xField
&& mxCustomOptionsUIBuilder
)
1674 xField
= mxCustomOptionsUIBuilder
->weld_entry(aID
);
1679 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1680 if( pVal
&& pVal
->Value
.hasValue() )
1681 pVal
->Value
>>= aCurVal
;
1682 xField
->set_text( aCurVal
);
1683 xField
->connect_changed( LINK( this, PrintDialog
, UIOption_EntryModifyHdl
) );
1686 maExtraControls
.emplace_back(std::move(xField
));
1688 weld::Widget
* pWidget
= maExtraControls
.back().get();
1690 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1691 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1694 setHelpId( pWidget
, aHelpIds
, 0 );
1696 setHelpText( pWidget
, aHelpTexts
, 0 );
1700 SAL_WARN( "vcl", "Unsupported UI option: \"" << aCtrlType
<< '"');
1704 // #i106506# if no brochure button, then the singular Pages radio button
1705 // makes no sense, so replace it by a FixedText label
1706 if (!mxBrochureBtn
->get_visible() && mxPagesBtn
->get_visible())
1708 mxPagesBoxTitleTxt
->set_label(mxPagesBtn
->get_label());
1709 mxPagesBoxTitleTxt
->show();
1712 mxPagesBoxTitleTxt
->set_accessible_relation_label_for(mxNupPagesBox
.get());
1713 mxNupPagesBox
->set_accessible_relation_labeled_by(mxPagesBoxTitleTxt
.get());
1714 mxPagesBtn
->set_accessible_relation_label_for(nullptr);
1717 // update enable states
1718 checkOptionalControlDependencies();
1720 // print range not shown (currently math only) -> hide spacer line and reverse order
1721 if (!mxPageRangeEdit
->get_visible())
1723 mxReverseOrderBox
->hide();
1726 if (!mxCustomOptionsUIBuilder
)
1727 mxTabCtrl
->remove_page(mxTabCtrl
->get_page_ident(1));
1730 void PrintDialog::makeEnabled( weld::Widget
* i_pWindow
)
1732 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1733 if( it
!= maControlToPropertyMap
.end() )
1735 OUString
aDependency( maPController
->makeEnabled( it
->second
) );
1736 if( !aDependency
.isEmpty() )
1737 updateWindowFromProperty( aDependency
);
1741 void PrintDialog::updateWindowFromProperty( const OUString
& i_rProperty
)
1743 beans::PropertyValue
* pValue
= maPController
->getValue( i_rProperty
);
1744 auto it
= maPropertyToWindowMap
.find( i_rProperty
);
1745 if( !(pValue
&& it
!= maPropertyToWindowMap
.end()) )
1748 const auto& rWindows( it
->second
);
1749 if( rWindows
.empty() )
1753 sal_Int32 nVal
= -1;
1754 if( pValue
->Value
>>= bVal
)
1756 // we should have a CheckBox for this one
1757 weld::CheckButton
* pBox
= dynamic_cast<weld::CheckButton
*>(rWindows
.front());
1760 pBox
->set_active( bVal
);
1762 else if ( i_rProperty
== "PrintProspect" )
1764 // EVIL special case
1766 mxBrochureBtn
->set_active(true);
1768 mxPagesBtn
->set_active(true);
1772 SAL_WARN( "vcl", "missing a checkbox" );
1775 else if( pValue
->Value
>>= nVal
)
1777 // this could be a ListBox or a RadioButtonGroup
1778 weld::ComboBox
* pList
= dynamic_cast<weld::ComboBox
*>(rWindows
.front());
1781 pList
->set_active( static_cast< sal_uInt16
>(nVal
) );
1783 else if( nVal
>= 0 && nVal
< sal_Int32(rWindows
.size() ) )
1785 weld::RadioButton
* pBtn
= dynamic_cast<weld::RadioButton
*>(rWindows
[nVal
]);
1786 SAL_WARN_IF( !pBtn
, "vcl", "unexpected control for property" );
1788 pBtn
->set_active(true);
1793 bool PrintDialog::isPrintToFile() const
1795 return ( mxPrinters
->get_active() == 0 );
1798 bool PrintDialog::isCollate() const
1800 return mxCopyCountField
->get_value() > 1 && mxCollateBox
->get_active();
1803 bool PrintDialog::isSingleJobs() const
1805 return mxSingleJobsBox
->get_active();
1808 bool PrintDialog::hasPreview() const
1810 return mxPreviewBox
->get_active();
1813 PropertyValue
* PrintDialog::getValueForWindow( weld::Widget
* i_pWindow
) const
1815 PropertyValue
* pVal
= nullptr;
1816 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1817 if( it
!= maControlToPropertyMap
.end() )
1819 pVal
= maPController
->getValue( it
->second
);
1820 SAL_WARN_IF( !pVal
, "vcl", "property value not found" );
1824 OSL_FAIL( "changed control not in property map" );
1829 IMPL_LINK(PrintDialog
, ToggleHdl
, weld::ToggleButton
&, rButton
, void)
1834 IMPL_LINK(PrintDialog
, ClickHdl
, weld::Button
&, rButton
, void)
1836 if (&rButton
== mxOKButton
.get() || &rButton
== mxCancelButton
.get())
1839 m_xDialog
->response(&rButton
== mxOKButton
.get() ? RET_OK
: RET_CANCEL
);
1841 else if( &rButton
== mxHelpButton
.get() )
1843 // start help system
1844 Help
* pHelp
= Application::GetHelp();
1847 pHelp
->Start("vcl/ui/printdialog/PrintDialog", mxOKButton
.get());
1850 else if ( &rButton
== mxPreviewBox
.get() )
1852 maUpdatePreviewIdle
.Start();
1854 else if( &rButton
== mxForwardBtn
.get() )
1858 else if( &rButton
== mxBackwardBtn
.get() )
1862 else if( &rButton
== mxFirstBtn
.get() )
1866 else if( &rButton
== mxLastBtn
.get() )
1870 else if( &rButton
== mxBrochureBtn
.get() )
1872 PropertyValue
* pVal
= getValueForWindow( &rButton
);
1875 bool bVal
= mxBrochureBtn
->get_active();
1876 pVal
->Value
<<= bVal
;
1878 checkOptionalControlDependencies();
1880 // update preview and page settings
1881 maUpdatePreviewNoCacheIdle
.Start();
1883 if( mxBrochureBtn
->get_active() )
1885 mxOrientationBox
->set_sensitive( false );
1886 mxOrientationBox
->set_active( ORIENTATION_LANDSCAPE
);
1887 mxNupPagesBox
->set_active( 0 );
1888 updateNupFromPages();
1889 showAdvancedControls( false );
1890 enableNupControls( false );
1893 else if( &rButton
== mxPagesBtn
.get() )
1895 mxOrientationBox
->set_sensitive( true );
1896 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1897 enableNupControls( true );
1898 updateNupFromPages();
1900 else if( &rButton
== mxCollateBox
.get() )
1902 maPController
->setValue( "Collate",
1903 makeAny( isCollate() ) );
1904 checkControlDependencies();
1906 else if( &rButton
== mxSingleJobsBox
.get() )
1908 maPController
->setValue( "SinglePrintJobs",
1909 makeAny( isSingleJobs() ) );
1910 checkControlDependencies();
1912 else if( &rButton
== mxReverseOrderBox
.get() )
1914 bool bChecked
= mxReverseOrderBox
->get_active();
1915 maPController
->setReversePrint( bChecked
);
1916 maPController
->setValue( "PrintReverse",
1917 makeAny( bChecked
) );
1918 maUpdatePreviewIdle
.Start();
1920 else if( &rButton
== mxBorderCB
.get() )
1926 if( &rButton
== mxSetupButton
.get() )
1928 maPController
->setupPrinter(m_xDialog
.get());
1930 if ( !isPrintToFile() )
1932 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1933 mePaper
= aPrt
->GetPaper();
1935 for (int nPaper
= 0; nPaper
< aPrt
->GetPaperInfoCount(); nPaper
++ )
1937 PaperInfo aInfo
= aPrt
->GetPaperInfo( nPaper
);
1938 aInfo
.doSloppyFit(true);
1939 Paper ePaper
= aInfo
.getPaper();
1941 if ( mePaper
== ePaper
)
1943 mxPaperSizeBox
->set_active( nPaper
);
1949 updateOrientationBox( false );
1950 setupPaperSidesBox();
1952 // tdf#63905 don't use cache: page size may change
1953 maUpdatePreviewNoCacheIdle
.Start();
1955 checkControlDependencies();
1960 IMPL_LINK( PrintDialog
, SelectHdl
, weld::ComboBox
&, rBox
, void )
1962 if (&rBox
== mxPrinters
.get())
1964 if ( !isPrintToFile() )
1966 OUString
aNewPrinter(rBox
.get_active_text());
1968 maPController
->setPrinter( VclPtrInstance
<Printer
>( aNewPrinter
) );
1969 maPController
->resetPrinterOptions( false );
1971 updateOrientationBox();
1973 // update text fields
1974 mxOKButton
->set_label(maPrintText
);
1975 updatePrinterText();
1977 maUpdatePreviewIdle
.Start();
1979 else // print to file
1981 // use the default printer or FIXME: the last used one?
1982 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
1983 mxOKButton
->set_label(maPrintToFileText
);
1984 maPController
->resetPrinterOptions( true );
1987 updateOrientationBox();
1988 maUpdatePreviewIdle
.Start();
1991 setupPaperSidesBox();
1993 else if ( &rBox
== mxPaperSidesBox
.get() )
1995 DuplexMode eDuplex
= static_cast<DuplexMode
>(mxPaperSidesBox
->get_active() + 1);
1996 maPController
->getPrinter()->SetDuplexMode( eDuplex
);
1998 else if( &rBox
== mxOrientationBox
.get() )
2000 int nOrientation
= mxOrientationBox
->get_active();
2001 if ( nOrientation
!= ORIENTATION_AUTOMATIC
)
2002 setPaperOrientation( static_cast<Orientation
>( nOrientation
- 1 ) );
2006 else if ( &rBox
== mxNupOrderBox
.get() )
2010 else if( &rBox
== mxNupPagesBox
.get() )
2012 if( !mxPagesBtn
->get_active() )
2013 mxPagesBtn
->set_active(true);
2014 updateNupFromPages( false );
2016 else if ( &rBox
== mxPaperSizeBox
.get() )
2018 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
2019 PaperInfo aInfo
= aPrt
->GetPaperInfo( rBox
.get_active() );
2020 aInfo
.doSloppyFit(true);
2021 mePaper
= aInfo
.getPaper();
2023 if ( mePaper
== PAPER_USER
)
2024 aPrt
->SetPaperSizeUser( Size( aInfo
.getWidth(), aInfo
.getHeight() ) );
2026 aPrt
->SetPaper( mePaper
);
2028 Size
aPaperSize( aInfo
.getWidth(), aInfo
.getHeight() );
2029 checkPaperSize( aPaperSize
);
2030 maPController
->setPaperSizeFromUser( aPaperSize
);
2032 maUpdatePreviewIdle
.Start();
2036 IMPL_LINK_NOARG(PrintDialog
, MetricSpinModifyHdl
, weld::MetricSpinButton
&, void)
2038 checkControlDependencies();
2039 updateNupFromPages();
2042 IMPL_LINK_NOARG(PrintDialog
, FocusOutHdl
, weld::Widget
&, void)
2044 ActivateHdl(*mxPageEdit
);
2047 IMPL_LINK_NOARG(PrintDialog
, ActivateHdl
, weld::Entry
&, bool)
2049 sal_Int32 nPage
= mxPageEdit
->get_text().toInt32();
2053 mxPageEdit
->set_text("1");
2055 else if (nPage
> mnCachedPages
)
2057 nPage
= mnCachedPages
;
2058 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2060 int nNewCurPage
= nPage
- 1;
2061 if (nNewCurPage
!= mnCurPage
)
2063 mnCurPage
= nNewCurPage
;
2064 maUpdatePreviewIdle
.Start();
2069 IMPL_LINK( PrintDialog
, SpinModifyHdl
, weld::SpinButton
&, rEdit
, void )
2071 checkControlDependencies();
2072 if (&rEdit
== mxNupRowsEdt
.get() || &rEdit
== mxNupColEdt
.get())
2074 updateNupFromPages();
2076 else if( &rEdit
== mxCopyCountField
.get() )
2078 maPController
->setValue( "CopyCount",
2079 makeAny( sal_Int32(mxCopyCountField
->get_value()) ) );
2080 maPController
->setValue( "Collate",
2081 makeAny( isCollate() ) );
2085 IMPL_LINK( PrintDialog
, UIOption_CheckHdl
, weld::ToggleButton
&, i_rBox
, void )
2087 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2090 makeEnabled( &i_rBox
);
2092 bool bVal
= i_rBox
.get_active();
2093 pVal
->Value
<<= bVal
;
2095 checkOptionalControlDependencies();
2097 // update preview and page settings
2098 maUpdatePreviewNoCacheIdle
.Start();
2102 IMPL_LINK( PrintDialog
, UIOption_RadioHdl
, weld::ToggleButton
&, i_rBtn
, void )
2104 // this handler gets called for all radiobuttons that get unchecked, too
2105 // however we only want one notification for the new value (that is for
2106 // the button that gets checked)
2107 if( !i_rBtn
.get_active() )
2110 PropertyValue
* pVal
= getValueForWindow( &i_rBtn
);
2111 auto it
= maControlToNumValMap
.find( &i_rBtn
);
2112 if( !(pVal
&& it
!= maControlToNumValMap
.end()) )
2115 makeEnabled( &i_rBtn
);
2117 sal_Int32 nVal
= it
->second
;
2118 pVal
->Value
<<= nVal
;
2120 updateOrientationBox();
2122 checkOptionalControlDependencies();
2124 // tdf#41205 give focus to the page range edit if the corresponding radio button was selected
2125 if (pVal
->Name
== "PrintContent" && mxPageRangesRadioButton
->get_active())
2126 mxPageRangeEdit
->grab_focus();
2128 // update preview and page settings
2129 maUpdatePreviewNoCacheIdle
.Start();
2132 IMPL_LINK( PrintDialog
, UIOption_SelectHdl
, weld::ComboBox
&, i_rBox
, void )
2134 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2138 makeEnabled( &i_rBox
);
2140 sal_Int32
nVal( i_rBox
.get_active() );
2141 pVal
->Value
<<= nVal
;
2143 //If we are in impress we start in print slides mode and get a
2144 //maFirstPageSize for slides which are usually landscape mode, if we
2145 //change to notes which are usually in portrait mode, and then visit
2146 //n-up print, we will assume notes are in landscape unless we throw
2147 //away maFirstPageSize when we change page content type
2148 if (pVal
->Name
== "PageContentType")
2149 maFirstPageSize
= Size();
2151 checkOptionalControlDependencies();
2153 // update preview and page settings
2154 maUpdatePreviewNoCacheIdle
.Start();
2157 IMPL_LINK( PrintDialog
, UIOption_SpinModifyHdl
, weld::SpinButton
&, i_rBox
, void )
2159 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2162 makeEnabled( &i_rBox
);
2164 sal_Int64 nVal
= i_rBox
.get_value();
2165 pVal
->Value
<<= nVal
;
2167 checkOptionalControlDependencies();
2169 // update preview and page settings
2170 maUpdatePreviewNoCacheIdle
.Start();
2174 IMPL_LINK( PrintDialog
, UIOption_EntryModifyHdl
, weld::Entry
&, i_rBox
, void )
2176 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2179 makeEnabled( &i_rBox
);
2181 OUString
aVal( i_rBox
.get_text() );
2182 pVal
->Value
<<= aVal
;
2184 checkOptionalControlDependencies();
2186 // update preview and page settings
2187 maUpdatePreviewNoCacheIdle
.Start();
2191 void PrintDialog::previewForward()
2193 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() + 1;
2194 if (nValue
<= mnCachedPages
)
2196 mxPageEdit
->set_text(OUString::number(nValue
));
2197 ActivateHdl(*mxPageEdit
);
2201 void PrintDialog::previewBackward()
2203 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() - 1;
2206 mxPageEdit
->set_text(OUString::number(nValue
));
2207 ActivateHdl(*mxPageEdit
);
2211 void PrintDialog::previewFirst()
2213 mxPageEdit
->set_text("1");
2214 ActivateHdl(*mxPageEdit
);
2217 void PrintDialog::previewLast()
2219 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2220 ActivateHdl(*mxPageEdit
);
2224 static OUString
getNewLabel(const OUString
& aLabel
, int i_nCurr
, int i_nMax
)
2226 OUString
aNewText( aLabel
.replaceFirst( "%p", OUString::number( i_nCurr
) ) );
2227 aNewText
= aNewText
.replaceFirst( "%n", OUString::number( i_nMax
) );
2232 // PrintProgressDialog
2233 PrintProgressDialog::PrintProgressDialog(weld::Window
* i_pParent
, int i_nMax
)
2234 : GenericDialogController(i_pParent
, "vcl/ui/printprogressdialog.ui", "PrintProgressDialog")
2238 , mxText(m_xBuilder
->weld_label("label"))
2239 , mxProgress(m_xBuilder
->weld_progress_bar("progressbar"))
2240 , mxButton(m_xBuilder
->weld_button("cancel"))
2245 maStr
= mxText
->get_label();
2247 //just multiply largest value by 10 and take the width of that string as
2248 //the max size we will want
2249 mxText
->set_label(getNewLabel(maStr
, mnMax
* 10, mnMax
* 10));
2250 mxText
->set_size_request(mxText
->get_preferred_size().Width(), -1);
2252 //Pick a useful max width
2253 mxProgress
->set_size_request(mxProgress
->get_approximate_digit_width() * 25, -1);
2255 mxButton
->connect_clicked( LINK( this, PrintProgressDialog
, ClickHdl
) );
2257 // after this patch f7157f04fab298423e2c4f6a7e5f8e361164b15f, we have seen the calc Max string (sometimes) look above
2258 // now init to the right start values
2259 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2262 PrintProgressDialog::~PrintProgressDialog()
2266 IMPL_LINK_NOARG(PrintProgressDialog
, ClickHdl
, weld::Button
&, void)
2271 void PrintProgressDialog::setProgress( int i_nCurrent
)
2278 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2280 // here view the dialog, with the right label
2281 mxProgress
->set_percentage(mnCur
*100/mnMax
);
2284 void PrintProgressDialog::tick()
2287 setProgress( ++mnCur
);
2290 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */