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::container
;
54 using namespace com::sun::star::beans
;
58 ORIENTATION_AUTOMATIC
,
64 bool lcl_ListBoxCompare( const OUString
& rStr1
, const OUString
& rStr2
)
66 return vcl::NaturalSortCompare( rStr1
, rStr2
) < 0;
70 PrintDialog::PrintPreviewWindow::PrintPreviewWindow(PrintDialog
* pDialog
)
72 , maOrigSize( 10, 10 )
73 , mnDPIX(Application::GetDefaultDevice()->GetDPIX())
74 , mnDPIY(Application::GetDefaultDevice()->GetDPIY())
75 , mbGreyscale( false )
79 PrintDialog::PrintPreviewWindow::~PrintPreviewWindow()
83 void PrintDialog::PrintPreviewWindow::Resize()
85 Size
aNewSize(GetOutputSizePixel());
86 tools::Long nTextHeight
= GetDrawingArea()->get_text_height();
87 // leave small space for decoration
88 aNewSize
.AdjustWidth( -(nTextHeight
+ 2) );
89 aNewSize
.AdjustHeight( -(nTextHeight
+ 2) );
93 // #i106435# catch corner case of Size(0,0)
94 Size
aOrigSize( maOrigSize
);
95 if( aOrigSize
.Width() < 1 )
96 aOrigSize
.setWidth( aNewSize
.Width() );
97 if( aOrigSize
.Height() < 1 )
98 aOrigSize
.setHeight( aNewSize
.Height() );
99 if( aOrigSize
.Width() > aOrigSize
.Height() )
101 aScaledSize
= Size( aNewSize
.Width(), aNewSize
.Width() * aOrigSize
.Height() / aOrigSize
.Width() );
102 if( aScaledSize
.Height() > aNewSize
.Height() )
103 fScale
= double(aNewSize
.Height())/double(aScaledSize
.Height());
107 aScaledSize
= Size( aNewSize
.Height() * aOrigSize
.Width() / aOrigSize
.Height(), aNewSize
.Height() );
108 if( aScaledSize
.Width() > aNewSize
.Width() )
109 fScale
= double(aNewSize
.Width())/double(aScaledSize
.Width());
111 aScaledSize
.setWidth( tools::Long(aScaledSize
.Width()*fScale
) );
112 aScaledSize
.setHeight( tools::Long(aScaledSize
.Height()*fScale
) );
114 maPreviewSize
= aScaledSize
;
116 // check and evtl. recreate preview bitmap
117 preparePreviewBitmap();
120 void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
122 rRenderContext
.Push();
123 weld::SetPointFont(rRenderContext
, rRenderContext
.GetSettings().GetStyleSettings().GetLabelFont());
124 rRenderContext
.SetTextColor(rRenderContext
.GetSettings().GetStyleSettings().GetLabelTextColor());
125 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
126 rRenderContext
.Erase();
128 auto nTextHeight
= rRenderContext
.GetTextHeight();
129 Size
aSize(GetOutputSizePixel());
130 Point
aOffset((aSize
.Width() - maPreviewSize
.Width() + nTextHeight
) / 2,
131 (aSize
.Height() - maPreviewSize
.Height() + nTextHeight
) / 2);
135 auto nWidth
= rRenderContext
.GetTextWidth(maHorzText
);
137 auto nStart
= aOffset
.X() + (maPreviewSize
.Width() - nWidth
) / 2;
138 rRenderContext
.DrawText(Point(nStart
, aOffset
.Y() - nTextHeight
), maHorzText
, 0, maHorzText
.getLength());
140 DecorationView
aDecoView(&rRenderContext
);
141 auto nTop
= aOffset
.Y() - (nTextHeight
/ 2);
142 aDecoView
.DrawSeparator(Point(aOffset
.X(), nTop
), Point(nStart
- 2, nTop
), false);
143 aDecoView
.DrawSeparator(Point(nStart
+ nWidth
+ 2, nTop
), Point(aOffset
.X() + maPreviewSize
.Width(), nTop
), false);
148 rRenderContext
.Push(PushFlags::FONT
);
149 vcl::Font
aFont(rRenderContext
.GetFont());
150 aFont
.SetOrientation(900_deg10
);
151 rRenderContext
.SetFont(aFont
);
153 auto nLeft
= aOffset
.X() - nTextHeight
;
155 auto nWidth
= rRenderContext
.GetTextWidth(maVertText
);
156 auto nStart
= aOffset
.Y() + (maPreviewSize
.Height() + nWidth
) / 2;
158 rRenderContext
.DrawText(Point(nLeft
, nStart
), maVertText
, 0, maVertText
.getLength());
160 DecorationView
aDecoView(&rRenderContext
);
161 nLeft
= aOffset
.X() - (nTextHeight
/ 2);
162 aDecoView
.DrawSeparator(Point(nLeft
, aOffset
.Y()), Point(nLeft
, nStart
- nWidth
- 2), true);
163 aDecoView
.DrawSeparator(Point(nLeft
, nStart
+ 2), Point(nLeft
, aOffset
.Y() + maPreviewSize
.Height()), true);
165 rRenderContext
.Pop();
168 if (!maReplacementString
.isEmpty())
170 // replacement is active
171 tools::Rectangle
aTextRect(aOffset
+ Point(2, 2), Size(maPreviewSize
.Width() - 4, maPreviewSize
.Height() - 4));
172 rRenderContext
.DrawText(aTextRect
, maReplacementString
,
173 DrawTextFlags::Center
| DrawTextFlags::VCenter
|
174 DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
);
178 BitmapEx
aPreviewBitmap(maPreviewBitmap
);
180 // This explicit force-to-scale allows us to get the
181 // mentioned best quality here. Unfortunately this is
182 // currently not sure when using just ::DrawBitmap with
183 // a defined size or ::DrawOutDev
184 aPreviewBitmap
.Scale(maPreviewSize
, BmpScaleFlag::BestQuality
);
185 rRenderContext
.DrawBitmapEx(aOffset
, aPreviewBitmap
);
188 tools::Rectangle
aFrameRect(aOffset
+ Point(-1, -1), Size(maPreviewSize
.Width() + 2, maPreviewSize
.Height() + 2));
189 DecorationView
aDecorationView(&rRenderContext
);
190 aDecorationView
.DrawFrame(aFrameRect
, DrawFrameStyle::Group
);
192 rRenderContext
.Pop();
195 bool PrintDialog::PrintPreviewWindow::Command( const CommandEvent
& rEvt
)
197 if( rEvt
.GetCommand() == CommandEventId::Wheel
)
199 const CommandWheelData
* pWheelData
= rEvt
.GetWheelData();
200 if(pWheelData
->GetDelta() > 0)
201 mpDialog
->previewForward();
202 else if (pWheelData
->GetDelta() < 0)
203 mpDialog
->previewBackward();
206 return CustomWidgetController::Command(rEvt
);
209 void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile
& i_rNewPreview
,
210 const Size
& i_rOrigSize
,
211 std::u16string_view i_rPaperName
,
212 const OUString
& i_rReplacement
,
218 maMtf
= i_rNewPreview
;
221 maOrigSize
= i_rOrigSize
;
222 maReplacementString
= i_rReplacement
;
223 mbGreyscale
= i_bGreyscale
;
225 // use correct measurements
226 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
227 o3tl::Length eUnit
= o3tl::Length::mm
;
229 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
231 eUnit
= o3tl::Length::in100
;
234 Size
aLogicPaperSize(o3tl::convert(i_rOrigSize
, o3tl::Length::mm100
, eUnit
));
235 OUString
aNumText( rLocWrap
.getNum( aLogicPaperSize
.Width(), nDigits
) );
236 OUStringBuffer
aBuf( aNumText
+ " " );
237 aBuf
.appendAscii( eUnit
== o3tl::Length::mm
? "mm" : "in" );
238 if( !i_rPaperName
.empty() )
240 aBuf
.append( OUString::Concat(" (") + i_rPaperName
+ ")" );
242 maHorzText
= aBuf
.makeStringAndClear();
244 aNumText
= rLocWrap
.getNum( aLogicPaperSize
.Height(), nDigits
);
245 aBuf
.append( aNumText
+ " " );
246 aBuf
.appendAscii( eUnit
== o3tl::Length::mm
? "mm" : "in" );
247 maVertText
= aBuf
.makeStringAndClear();
249 // We have a new Metafile and evtl. a new page, so we need to reset
250 // the PreviewBitmap to force new creation
251 maPreviewBitmap
= Bitmap();
253 // sets/calculates e.g. maPreviewSize
254 // also triggers preparePreviewBitmap()
260 void PrintDialog::PrintPreviewWindow::preparePreviewBitmap()
262 if(maPreviewSize
.IsEmpty())
264 // not yet fully initialized, no need to prepare anything
268 // define an allowed number of pixels, also see
269 // defaults for primitive renderers and similar. This
270 // might be centralized and made dependent of 32/64bit
271 const sal_uInt32
nMaxSquarePixels(500000);
273 // check how big (squarePixels) the preview is currently (with
274 // max value of MaxSquarePixels)
275 const sal_uInt32
nCurrentSquarePixels(
278 static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getWidth())
279 * static_cast<sal_uInt32
>(maPreviewBitmap
.GetSizePixel().getHeight())));
281 // check how big (squarePixels) the preview needs to be (with
282 // max value of MaxSquarePixels)
283 const sal_uInt32
nRequiredSquarePixels(
286 static_cast<sal_uInt32
>(maPreviewSize
.getWidth())
287 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight())));
289 // check if preview is big enough. Use a scaling value in
290 // the comparison to not get bigger at the last possible moment
291 // what may look awkward and pixelated (again). This means
292 // to use a percentage value - if we have at least
293 // that value of required pixels, we are good.
294 static const double fPreventAwkwardFactor(1.35); // 35%
295 if(nCurrentSquarePixels
>= static_cast<sal_uInt32
>(nRequiredSquarePixels
* fPreventAwkwardFactor
))
297 // at this place we also could add a mechanism to let the preview
298 // bitmap 'shrink' again if it is currently 'too big' -> bigger
299 // than required. I think this is not necessary for now.
301 // already sufficient, done.
305 // check if we have enough square pixels e.g for 8x8 pixels
306 if(nRequiredSquarePixels
< 64)
308 // too small preview - let it empty
312 // Calculate nPlannedSquarePixels which is the required size
313 // expanded by a percentage (with max value of MaxSquarePixels)
314 static const double fExtraSpaceFactor(1.65); // 65%
315 const sal_uInt32
nPlannedSquarePixels(
318 static_cast<sal_uInt32
>(maPreviewSize
.getWidth() * fExtraSpaceFactor
)
319 * static_cast<sal_uInt32
>(maPreviewSize
.getHeight() * fExtraSpaceFactor
)));
321 // calculate back new width and height - it might have been
322 // truncated by MaxSquarePixels.
323 // We know that w*h == nPlannedSquarePixels and w/h == ratio
324 const double fRatio(static_cast<double>(maPreviewSize
.getWidth()) / static_cast<double>(maPreviewSize
.getHeight()));
325 const double fNewWidth(sqrt(static_cast<double>(nPlannedSquarePixels
) * fRatio
));
326 const double fNewHeight(sqrt(static_cast<double>(nPlannedSquarePixels
) / fRatio
));
327 const Size
aScaledSize(basegfx::fround
<tools::Long
>(fNewWidth
), basegfx::fround
<tools::Long
>(fNewHeight
));
329 // check if this eventual maximum is already reached
330 // due to having hit the MaxSquarePixels. Due to using
331 // an integer AspectRatio, we cannot make a numeric exact
332 // comparison - we need to compare if we are close
333 const double fScaledSizeSquare(static_cast<double>(aScaledSize
.getWidth() * aScaledSize
.getHeight()));
334 const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap
.GetSizePixel().getWidth() * maPreviewBitmap
.GetSizePixel().getHeight()));
336 // test as equal up to 0.1% (0.001)
337 if(fPreviewSizeSquare
!= 0.0 && fabs((fScaledSizeSquare
/ fPreviewSizeSquare
) - 1.0) < 0.001)
339 // maximum is reached, avoid bigger scaling
343 // create temporary VDev with requested Size and DPI.
344 // CAUTION: DPI *is* important here - it DIFFERS from 75x75, usually 600x600 is used
345 ScopedVclPtrInstance
<VirtualDevice
> pPrerenderVDev(*Application::GetDefaultDevice());
346 pPrerenderVDev
->SetOutputSizePixel(aScaledSize
, false);
347 pPrerenderVDev
->SetReferenceDevice( mnDPIX
, mnDPIY
);
349 // calculate needed Scale for Metafile (using Size and DPI from VDev)
350 Size
aLogicSize( pPrerenderVDev
->PixelToLogic( pPrerenderVDev
->GetOutputSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
351 Size
aOrigSize( maOrigSize
);
352 if( aOrigSize
.Width() < 1 )
353 aOrigSize
.setWidth( aLogicSize
.Width() );
354 if( aOrigSize
.Height() < 1 )
355 aOrigSize
.setHeight( aLogicSize
.Height() );
356 double fScale
= double(aLogicSize
.Width())/double(aOrigSize
.Width());
359 // The display quality of the Preview is pretty ugly when
360 // FormControls are used. I made a deep-dive why this happens,
361 // and in principle the reason is the Mteafile::Scale used
362 // below. Since Metafile actions are integer, that floating point
363 // scale leads to rounding errors that make the lines painting
364 // the FormControls disappear in the surrounding ClipRegions.
365 // That Scale cannot be avoided since the Metafile contains it's
366 // own SetMapMode commands which *will* be executed on ::Play,
367 // so the ::Scale is the only possibility fr Metafile currently:
368 // Giving a Size as parameter in ::Play will *not* work due to
369 // the relativeMapMode that gets created will fail on
370 // ::SetMapMode actions in the Metafile - and FormControls DO
371 // use ::SetMapMode(MapPixel).
372 // This can only be solved better in the future using Primitives
373 // which would allow any scale by embedding to a Transformation,
374 // but that would be a bigger rework.
375 // Until then, use this little 'trick' to improve quality.
376 // It uses the fact to empirically having tested that the quality
377 // gets really bad for FormControls starting by a scale factor
378 // smaller than 0.2 - that makes the ClipRegion overlap start.
379 // So - for now - try not to go below that.
380 static const double fMinimumScale(0.2);
382 if(fScale
< fMinimumScale
)
384 fFactor
= fMinimumScale
/ fScale
;
385 fScale
= fMinimumScale
;
387 double fWidth(aScaledSize
.getWidth() * fFactor
);
388 double fHeight(aScaledSize
.getHeight() * fFactor
);
389 const double fNewNeededPixels(fWidth
* fHeight
);
391 // to not risk using too big bitmaps and running into
392 // memory problems, still limit to a useful factor is
393 // necessary, also empirically estimated to
394 // avoid the quality from collapsing (using a direct
395 // in-between , ceil'd result)
396 static const double fMaximumQualitySquare(1396221.0);
398 if(fNewNeededPixels
> fMaximumQualitySquare
)
400 const double fCorrection(fMaximumQualitySquare
/fNewNeededPixels
);
401 fWidth
*= fCorrection
;
402 fHeight
*= fCorrection
;
403 fScale
*= fCorrection
;
406 const Size
aScaledSize2(basegfx::fround
<tools::Long
>(fWidth
), basegfx::fround
<tools::Long
>(fHeight
));
407 pPrerenderVDev
->SetOutputSizePixel(aScaledSize2
, false);
408 aLogicSize
= pPrerenderVDev
->PixelToLogic( aScaledSize2
, MapMode( MapUnit::Map100thMM
) );
411 pPrerenderVDev
->EnableOutput();
412 pPrerenderVDev
->SetBackground( Wallpaper(COL_WHITE
) );
413 pPrerenderVDev
->Erase();
414 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
416 pPrerenderVDev
->SetDrawMode( pPrerenderVDev
->GetDrawMode() |
417 ( DrawModeFlags::GrayLine
| DrawModeFlags::GrayFill
| DrawModeFlags::GrayText
|
418 DrawModeFlags::GrayBitmap
| DrawModeFlags::GrayGradient
) );
420 // Copy, Scale and Paint Metafile
421 GDIMetaFile
aMtf( maMtf
);
423 aMtf
.Scale( fScale
, fScale
);
425 aMtf
.Play(*pPrerenderVDev
, Point(0, 0), aLogicSize
);
427 pPrerenderVDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
428 maPreviewBitmap
= pPrerenderVDev
->GetBitmapEx(Point(0, 0), pPrerenderVDev
->GetOutputSizePixel());
432 // Correct to needed size, BmpScaleFlag::Interpolate is acceptable,
433 // but BmpScaleFlag::BestQuality is just better. In case of time
434 // constraints, change to Interpolate would be possible
435 maPreviewBitmap
.Scale(aScaledSize
, BmpScaleFlag::BestQuality
);
439 PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow()
440 : mnOrderMode( NupOrderType::LRTB
)
446 void PrintDialog::ShowNupOrderWindow::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
449 pDrawingArea
->set_size_request(aSize
.Width(), aSize
.Height());
450 CustomWidgetController::SetDrawingArea(pDrawingArea
);
451 SetOutputSizePixel(aSize
);
454 void PrintDialog::ShowNupOrderWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& /*i_rRect*/)
456 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
457 rRenderContext
.SetTextColor(rRenderContext
.GetSettings().GetStyleSettings().GetFieldTextColor());
458 rRenderContext
.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFieldColor()));
459 rRenderContext
.Erase();
461 int nPages
= mnRows
* mnColumns
;
462 Font
aFont(rRenderContext
.GetSettings().GetStyleSettings().GetFieldFont());
463 aFont
.SetFontSize(Size(0, 24));
464 rRenderContext
.SetFont(aFont
);
465 Size
aSampleTextSize(rRenderContext
.GetTextWidth(OUString::number(nPages
+ 1)), rRenderContext
.GetTextHeight());
466 Size
aOutSize(GetOutputSizePixel());
467 Size
aSubSize(aOutSize
.Width() / mnColumns
, aOutSize
.Height() / mnRows
);
468 // calculate font size: shrink the sample text so it fits
469 double fX
= double(aSubSize
.Width()) / double(aSampleTextSize
.Width());
470 double fY
= double(aSubSize
.Height()) / double(aSampleTextSize
.Height());
471 double fScale
= (fX
< fY
) ? fX
: fY
;
472 tools::Long nFontHeight
= tools::Long(24.0 * fScale
) - 3;
475 aFont
.SetFontSize(Size( 0, nFontHeight
));
476 rRenderContext
.SetFont(aFont
);
477 tools::Long nTextHeight
= rRenderContext
.GetTextHeight();
478 for (int i
= 0; i
< nPages
; i
++)
480 OUString
aPageText(OUString::number(i
+ 1));
484 case NupOrderType::LRTB
:
485 nX
= (i
% mnColumns
);
486 nY
= (i
/ mnColumns
);
488 case NupOrderType::TBLR
:
492 case NupOrderType::RLTB
:
493 nX
= mnColumns
- 1 - (i
% mnColumns
);
494 nY
= (i
/ mnColumns
);
496 case NupOrderType::TBRL
:
497 nX
= mnColumns
- 1 - (i
/ mnRows
);
501 Size
aTextSize(rRenderContext
.GetTextWidth(aPageText
), nTextHeight
);
502 int nDeltaX
= (aSubSize
.Width() - aTextSize
.Width()) / 2;
503 int nDeltaY
= (aSubSize
.Height() - aTextSize
.Height()) / 2;
504 rRenderContext
.DrawText(Point(nX
* aSubSize
.Width() + nDeltaX
,
505 nY
* aSubSize
.Height() + nDeltaY
), aPageText
);
507 DecorationView
aDecorationView(&rRenderContext
);
508 aDecorationView
.DrawFrame(tools::Rectangle(Point(0, 0), aOutSize
), DrawFrameStyle::Group
);
511 Size
const & PrintDialog::getJobPageSize()
513 if( maFirstPageSize
.IsEmpty() )
515 maFirstPageSize
= maNupPortraitSize
;
517 if( maPController
->getPageCountProtected() > 0 )
519 PrinterController::PageSize aPageSize
= maPController
->getPageFile( 0, aMtf
, true );
520 maFirstPageSize
= aPageSize
.aSize
;
523 return maFirstPageSize
;
526 PrintDialog::PrintDialog(weld::Window
* i_pWindow
, std::shared_ptr
<PrinterController
> i_xController
)
527 : GenericDialogController(i_pWindow
, u
"vcl/ui/printdialog.ui"_ustr
, u
"PrintDialog"_ustr
)
528 , maPController(std::move( i_xController
))
529 , mxTabCtrl(m_xBuilder
->weld_notebook(u
"tabcontrol"_ustr
))
530 , mxScrolledWindow(m_xBuilder
->weld_scrolled_window(u
"scrolledwindow"_ustr
))
531 , mxPageLayoutFrame(m_xBuilder
->weld_frame(u
"layoutframe"_ustr
))
532 , mxPrinters(m_xBuilder
->weld_combo_box(u
"printersbox"_ustr
))
533 , mxStatusTxt(m_xBuilder
->weld_label(u
"status"_ustr
))
534 , mxSetupButton(m_xBuilder
->weld_button(u
"setup"_ustr
))
535 , mxCopyCountField(m_xBuilder
->weld_spin_button(u
"copycount"_ustr
))
536 , mxCollateBox(m_xBuilder
->weld_check_button(u
"collate"_ustr
))
537 , mxCollateImage(m_xBuilder
->weld_image(u
"collateimage"_ustr
))
538 , mxPageRangeEdit(m_xBuilder
->weld_entry(u
"pagerange"_ustr
))
539 , mxPageRangesRadioButton(m_xBuilder
->weld_radio_button(u
"rbRangePages"_ustr
))
540 , mxPaperSidesBox(m_xBuilder
->weld_combo_box(u
"sidesbox"_ustr
))
541 , mxSingleJobsBox(m_xBuilder
->weld_check_button(u
"singlejobs"_ustr
))
542 , mxReverseOrderBox(m_xBuilder
->weld_check_button(u
"reverseorder"_ustr
))
543 , mxOKButton(m_xBuilder
->weld_button(u
"ok"_ustr
))
544 , mxCancelButton(m_xBuilder
->weld_button(u
"cancel"_ustr
))
545 , mxBackwardBtn(m_xBuilder
->weld_button(u
"backward"_ustr
))
546 , mxForwardBtn(m_xBuilder
->weld_button(u
"forward"_ustr
))
547 , mxFirstBtn(m_xBuilder
->weld_button(u
"btnFirst"_ustr
))
548 , mxLastBtn(m_xBuilder
->weld_button(u
"btnLast"_ustr
))
549 , mxPreviewBox(m_xBuilder
->weld_check_button(u
"previewbox"_ustr
))
550 , mxNumPagesText(m_xBuilder
->weld_label(u
"totalnumpages"_ustr
))
551 , mxPreview(new PrintPreviewWindow(this))
552 , mxPreviewWindow(new weld::CustomWeld(*m_xBuilder
, u
"preview"_ustr
, *mxPreview
))
553 , mxPageEdit(m_xBuilder
->weld_entry(u
"pageedit"_ustr
))
554 , mxPagesBtn(m_xBuilder
->weld_radio_button(u
"pagespersheetbtn"_ustr
))
555 , mxBrochureBtn(m_xBuilder
->weld_radio_button(u
"brochure"_ustr
))
556 , mxPagesBoxTitleTxt(m_xBuilder
->weld_label(u
"pagespersheettxt"_ustr
))
557 , mxNupPagesBox(m_xBuilder
->weld_combo_box(u
"pagespersheetbox"_ustr
))
558 , mxNupNumPagesTxt(m_xBuilder
->weld_label(u
"pagestxt"_ustr
))
559 , mxNupColEdt(m_xBuilder
->weld_spin_button(u
"pagecols"_ustr
))
560 , mxNupTimesTxt(m_xBuilder
->weld_label(u
"by"_ustr
))
561 , mxNupRowsEdt(m_xBuilder
->weld_spin_button(u
"pagerows"_ustr
))
562 , mxPageMarginTxt1(m_xBuilder
->weld_label(u
"pagemargintxt1"_ustr
))
563 , mxPageMarginEdt(m_xBuilder
->weld_metric_spin_button(u
"pagemarginsb"_ustr
, FieldUnit::MM
))
564 , mxPageMarginTxt2(m_xBuilder
->weld_label(u
"pagemargintxt2"_ustr
))
565 , mxSheetMarginTxt1(m_xBuilder
->weld_label(u
"sheetmargintxt1"_ustr
))
566 , mxSheetMarginEdt(m_xBuilder
->weld_metric_spin_button(u
"sheetmarginsb"_ustr
, FieldUnit::MM
))
567 , mxSheetMarginTxt2(m_xBuilder
->weld_label(u
"sheetmargintxt2"_ustr
))
568 , mxPaperSizeBox(m_xBuilder
->weld_combo_box(u
"papersizebox"_ustr
))
569 , mxOrientationBox(m_xBuilder
->weld_combo_box(u
"pageorientationbox"_ustr
))
570 , mxNupOrderTxt(m_xBuilder
->weld_label(u
"labelorder"_ustr
))
571 , mxNupOrderBox(m_xBuilder
->weld_combo_box(u
"orderbox"_ustr
))
572 , mxNupOrder(new ShowNupOrderWindow
)
573 , mxNupOrderWin(new weld::CustomWeld(*m_xBuilder
, u
"orderpreview"_ustr
, *mxNupOrder
))
574 , mxBorderCB(m_xBuilder
->weld_check_button(u
"bordercb"_ustr
))
575 , mxRangeExpander(m_xBuilder
->weld_expander(u
"exRangeExpander"_ustr
))
576 , mxLayoutExpander(m_xBuilder
->weld_expander(u
"exLayoutExpander"_ustr
))
577 , mxCustom(m_xBuilder
->weld_widget(u
"customcontents"_ustr
))
578 , maPrintToFileText( VclResId( SV_PRINT_TOFILE_TXT
) )
579 , maDefPrtText( VclResId( SV_PRINT_DEFPRT_TXT
) )
580 , maNoPageStr( VclResId( SV_PRINT_NOPAGES
) )
581 , maNoPreviewStr( VclResId( SV_PRINT_NOPREVIEW
) )
584 , mbCollateAlwaysOff(false)
585 , mbShowLayoutFrame( true )
586 , maUpdatePreviewIdle("Print Dialog Update Preview Idle")
587 , maUpdatePreviewNoCacheIdle("Print Dialog Update Preview (no cache) Idle")
589 // save printbutton text, gets exchanged occasionally with print to file
590 maPrintText
= mxOKButton
->get_label();
592 maPageStr
= mxNumPagesText
->get_label();
594 mxPrinters
->append_text(maPrintToFileText
);
595 // fill printer listbox
596 std::vector
< OUString
> rQueues( Printer::GetPrinterQueues() );
597 std::sort( rQueues
.begin(), rQueues
.end(), lcl_ListBoxCompare
);
598 for( const auto& rQueue
: rQueues
)
600 mxPrinters
->append_text(rQueue
);
602 // select current printer
603 if (mxPrinters
->find_text(maPController
->getPrinter()->GetName()) != -1)
604 mxPrinters
->set_active_text(maPController
->getPrinter()->GetName());
607 // fall back to last printer
608 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
609 OUString
aValue( pItem
->getValue( u
"PrintDialog"_ustr
,
610 u
"LastPrinter"_ustr
) );
611 if (mxPrinters
->find_text(aValue
) != -1)
613 mxPrinters
->set_active_text(aValue
);
614 maPController
->setPrinter( VclPtrInstance
<Printer
>( aValue
) );
618 // fall back to default printer
619 mxPrinters
->set_active_text(Printer::GetDefaultPrinterName());
620 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
624 // not printing to file
625 maPController
->resetPrinterOptions( false );
627 // update the text fields for the printer
630 // setup dependencies
631 checkControlDependencies();
633 // setup paper sides box
634 setupPaperSidesBox();
636 // set initial focus to "Printer"
637 mxPrinters
->grab_focus();
639 // setup sizes for N-Up
640 Size
aNupSize( maPController
->getPrinter()->PixelToLogic(
641 maPController
->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) ) );
642 if( maPController
->getPrinter()->GetOrientation() == Orientation::Landscape
)
644 maNupLandscapeSize
= aNupSize
;
645 // coverity[swapped_arguments : FALSE] - this is in the correct order
646 maNupPortraitSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
650 maNupPortraitSize
= aNupSize
;
651 // coverity[swapped_arguments : FALSE] - this is in the correct order
652 maNupLandscapeSize
= Size( aNupSize
.Height(), aNupSize
.Width() );
655 maUpdatePreviewIdle
.SetPriority(TaskPriority::POST_PAINT
);
656 maUpdatePreviewIdle
.SetInvokeHandler(LINK( this, PrintDialog
, updatePreviewIdle
));
657 maUpdatePreviewNoCacheIdle
.SetPriority(TaskPriority::POST_PAINT
);
658 maUpdatePreviewNoCacheIdle
.SetInvokeHandler(LINK(this, PrintDialog
, updatePreviewNoCacheIdle
));
660 initFromMultiPageSetup( maPController
->getMultipage() );
662 // setup optional UI options set by application
665 // hide layout frame if unwanted
666 mxPageLayoutFrame
->set_visible(mbShowLayoutFrame
);
668 // restore settings from last run
672 mxOKButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
673 mxCancelButton
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
674 mxSetupButton
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
675 mxBackwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
676 mxForwardBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
677 mxFirstBtn
->connect_clicked(LINK(this, PrintDialog
, ClickHdl
));
678 mxLastBtn
->connect_clicked( LINK( this, PrintDialog
, ClickHdl
) );
681 mxReverseOrderBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
682 mxCollateBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
683 mxSingleJobsBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
684 mxBrochureBtn
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
685 mxPreviewBox
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
686 mxBorderCB
->connect_toggled( LINK( this, PrintDialog
, ToggleHdl
) );
689 mxPrinters
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
690 mxPaperSidesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
691 mxNupPagesBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
692 mxOrientationBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
693 mxNupOrderBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
694 mxPaperSizeBox
->connect_changed( LINK( this, PrintDialog
, SelectHdl
) );
697 mxPageEdit
->connect_activate( LINK( this, PrintDialog
, ActivateHdl
) );
698 mxPageEdit
->connect_focus_out( LINK( this, PrintDialog
, FocusOutHdl
) );
699 mxCopyCountField
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
700 mxNupColEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
701 mxNupRowsEdt
->connect_value_changed( LINK( this, PrintDialog
, SpinModifyHdl
) );
702 mxPageMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
703 mxSheetMarginEdt
->connect_value_changed( LINK( this, PrintDialog
, MetricSpinModifyHdl
) );
705 updateNupFromPages();
707 // tdf#129180 Delay setting the default value in the Paper Size list
708 // set paper sizes listbox
711 mxRangeExpander
->set_expanded(
712 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::get());
713 mxLayoutExpander
->set_expanded(
714 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::get());
716 // lock the dialog height, regardless of later expander state
717 mxScrolledWindow
->set_size_request(
718 mxScrolledWindow
->get_preferred_size().Width() + mxScrolledWindow
->get_scroll_thickness(),
721 m_xDialog
->set_centered_on_parent(true);
724 PrintDialog::~PrintDialog()
726 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
727 officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::set(mxRangeExpander
->get_expanded(), batch
);
728 officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::set(mxLayoutExpander
->get_expanded(), batch
);
732 void PrintDialog::setupPaperSidesBox()
734 DuplexMode eDuplex
= maPController
->getPrinter()->GetDuplexMode();
736 if ( eDuplex
== DuplexMode::Unknown
|| isPrintToFile() )
738 mxPaperSidesBox
->set_active( 0 );
739 mxPaperSidesBox
->set_sensitive( false );
743 mxPaperSidesBox
->set_active( static_cast<sal_Int32
>(eDuplex
) - 1 );
744 mxPaperSidesBox
->set_sensitive( true );
748 void PrintDialog::storeToSettings()
750 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
752 pItem
->setValue( u
"PrintDialog"_ustr
,
754 isPrintToFile() ? Printer::GetDefaultPrinterName()
755 : mxPrinters
->get_active_text() );
757 pItem
->setValue( u
"PrintDialog"_ustr
,
759 mxTabCtrl
->get_tab_label_text(mxTabCtrl
->get_current_page_ident()));
761 pItem
->setValue( u
"PrintDialog"_ustr
,
763 m_xDialog
->get_window_state(vcl::WindowDataMask::All
) );
765 pItem
->setValue( u
"PrintDialog"_ustr
,
767 mxCopyCountField
->get_text() );
769 pItem
->setValue( u
"PrintDialog"_ustr
,
771 mxCollateBox
->get_active() ? u
"true"_ustr
:
774 pItem
->setValue( u
"PrintDialog"_ustr
,
775 u
"CollateSingleJobs"_ustr
,
776 mxSingleJobsBox
->get_active() ? u
"true"_ustr
:
779 pItem
->setValue( u
"PrintDialog"_ustr
,
781 hasPreview() ? u
"true"_ustr
:
787 void PrintDialog::readFromSettings()
789 SettingsConfigItem
* pItem
= SettingsConfigItem::get();
791 // read last selected tab page; if it exists, activate it
792 OUString aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
794 sal_uInt16 nCount
= mxTabCtrl
->get_n_pages();
795 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
797 OUString sPageId
= mxTabCtrl
->get_page_ident(i
);
798 if (aValue
== mxTabCtrl
->get_tab_label_text(sPageId
))
800 mxTabCtrl
->set_current_page(sPageId
);
805 // persistent window state
806 aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
807 u
"WindowState"_ustr
);
808 if (!aValue
.isEmpty())
809 m_xDialog
->set_window_state(aValue
);
812 aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
813 u
"CollateBox"_ustr
);
814 if( aValue
.equalsIgnoreAsciiCase("alwaysoff") )
816 mbCollateAlwaysOff
= true;
817 mxCollateBox
->set_active( false );
818 mxCollateBox
->set_sensitive( false );
822 mbCollateAlwaysOff
= false;
823 aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
825 mxCollateBox
->set_active( aValue
.equalsIgnoreAsciiCase("true") );
828 // collate single jobs
829 aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
830 u
"CollateSingleJobs"_ustr
);
831 mxSingleJobsBox
->set_active(aValue
.equalsIgnoreAsciiCase("true"));
834 aValue
= pItem
->getValue( u
"PrintDialog"_ustr
,
835 u
"HasPreview"_ustr
);
836 if ( aValue
.equalsIgnoreAsciiCase("false") )
837 mxPreviewBox
->set_active( false );
839 mxPreviewBox
->set_active( true );
843 void PrintDialog::setPaperSizes()
845 mxPaperSizeBox
->clear();
846 mxPaperSizeBox
->set_active(-1);
848 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
849 mePaper
= aPrt
->GetPaper();
851 if ( isPrintToFile() )
853 mxPaperSizeBox
->set_sensitive( false );
857 int nExactMatch
= -1;
859 int nRotatedSizeMatch
= -1;
860 Size aSizeOfPaper
= aPrt
->GetSizeOfPaper();
861 PaperInfo
aPaperInfo(aSizeOfPaper
.getWidth(), aSizeOfPaper
.getHeight());
862 // coverity[swapped_arguments : FALSE] - this is in the correct order
863 PaperInfo
aRotatedPaperInfo(aSizeOfPaper
.getHeight(), aSizeOfPaper
.getWidth());
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
? u
"mm"_ustr
: u
"in"_ustr
;
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 nExactMatch
= nPaper
;
898 if (ePaper
== PAPER_USER
&& aInfo
.sloppyEqual(aPaperInfo
))
901 if (ePaper
== PAPER_USER
&& aInfo
.sloppyEqual(aRotatedPaperInfo
))
902 nRotatedSizeMatch
= nPaper
;
905 if (nExactMatch
!= -1)
906 mxPaperSizeBox
->set_active(nExactMatch
);
907 else if (nSizeMatch
!= -1)
908 mxPaperSizeBox
->set_active(nSizeMatch
);
909 else if (nRotatedSizeMatch
!= -1)
910 mxPaperSizeBox
->set_active(nRotatedSizeMatch
);
912 mxPaperSizeBox
->set_sensitive( true );
916 void PrintDialog::updatePrinterText()
918 const OUString
aDefPrt( Printer::GetDefaultPrinterName() );
919 const QueueInfo
* pInfo
= Printer::GetQueueInfo( mxPrinters
->get_active_text(), true );
922 // FIXME: status text
924 if( aDefPrt
== pInfo
->GetPrinterName() )
925 aStatus
= maDefPrtText
;
926 mxStatusTxt
->set_label( aStatus
);
930 mxStatusTxt
->set_label( OUString() );
934 void PrintDialog::setPreviewText()
936 OUString
aNewText( maPageStr
.replaceFirst( "%n", OUString::number( mnCachedPages
) ) );
937 mxNumPagesText
->set_label( aNewText
);
940 IMPL_LINK_NOARG(PrintDialog
, updatePreviewIdle
, Timer
*, void)
942 preparePreview(true);
945 IMPL_LINK_NOARG(PrintDialog
, updatePreviewNoCacheIdle
, Timer
*, void)
947 preparePreview(false);
950 void PrintDialog::preparePreview( bool i_bMayUseCache
)
952 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
953 Size aCurPageSize
= aPrt
->PixelToLogic( aPrt
->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM
) );
954 // tdf#123076 Get paper size for the preview top label
955 mePaper
= aPrt
->GetPaper();
958 // page range may have changed depending on options
959 sal_Int32 nPages
= maPController
->getFilteredPageCount();
960 mnCachedPages
= nPages
;
963 updatePageRange(nPages
);
969 mxPreview
->setPreview( aMtf
, aCurPageSize
,
970 Printer::GetPaperName( mePaper
),
972 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
973 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
976 mxForwardBtn
->set_sensitive( false );
977 mxBackwardBtn
->set_sensitive( false );
978 mxFirstBtn
->set_sensitive( false );
979 mxLastBtn
->set_sensitive( false );
981 mxPageEdit
->set_sensitive( false );
986 if( mnCurPage
>= nPages
)
987 mnCurPage
= nPages
-1;
990 mxPageEdit
->set_text(OUString::number(mnCurPage
+ 1));
994 PrinterController::PageSize aPageSize
=
995 maPController
->getFilteredPageFile( mnCurPage
, aMtf
, i_bMayUseCache
);
996 aCurPageSize
= aPrt
->PixelToLogic(aPrt
->GetPaperSizePixel(), MapMode(MapUnit::Map100thMM
));
997 if( ! aPageSize
.bFullPaper
)
999 const MapMode
aMapMode( MapUnit::Map100thMM
);
1000 Point
aOff( aPrt
->PixelToLogic( aPrt
->GetPageOffsetPixel(), aMapMode
) );
1001 aMtf
.Move( aOff
.X(), aOff
.Y() );
1003 // tdf#150561: page size may have changed so sync mePaper with it
1004 mePaper
= aPrt
->GetPaper();
1007 mxPreview
->setPreview( aMtf
, aCurPageSize
,
1008 Printer::GetPaperName( mePaper
),
1009 nPages
> 0 ? OUString() : maNoPageStr
,
1010 aPrt
->GetDPIX(), aPrt
->GetDPIY(),
1011 aPrt
->GetPrinterOptions().IsConvertToGreyscales()
1014 mxForwardBtn
->set_sensitive( mnCurPage
< nPages
-1 );
1015 mxBackwardBtn
->set_sensitive( mnCurPage
!= 0 );
1016 mxFirstBtn
->set_sensitive( mnCurPage
!= 0 );
1017 mxLastBtn
->set_sensitive( mnCurPage
< nPages
-1 );
1018 mxPageEdit
->set_sensitive( nPages
> 1 );
1021 void PrintDialog::updatePageRange(sal_Int32 nPages
)
1023 if (nPages
> 0 && !mxPageRangesRadioButton
->get_active())
1025 OUStringBuffer
aBuf(32);
1029 aBuf
.append("-" + OUString::number(nPages
));
1031 OUString sRange
= aBuf
.makeStringAndClear();
1032 mxPageRangeEdit
->set_text(sRange
);
1033 maPController
->setValue(u
"PageRange"_ustr
, Any(sRange
));
1037 void PrintDialog::updatePageSize(int nOrientation
)
1039 VclPtr
<Printer
> aPrt(maPController
->getPrinter());
1042 if (mxNupPagesBox
->get_active_id() == "1")
1044 PaperInfo aInfo
= aPrt
->GetPaperInfo(mxPaperSizeBox
->get_active());
1045 aSize
= Size(aInfo
.getWidth(), aInfo
.getHeight());
1046 if (aSize
.IsEmpty())
1047 aSize
= aPrt
->GetSizeOfPaper();
1049 if (nOrientation
!= ORIENTATION_AUTOMATIC
)
1051 if ((nOrientation
== ORIENTATION_PORTRAIT
&& aSize
.Width() > aSize
.Height())
1052 || (nOrientation
== ORIENTATION_LANDSCAPE
&& aSize
.Width() < aSize
.Height()))
1054 // coverity[swapped_arguments : FALSE] - this is in the intended order
1055 aSize
= Size(aSize
.Height(), aSize
.Width());
1060 aSize
= getJobPageSize();
1062 aPrt
->SetPrintPageSize(aSize
);
1063 aPrt
->SetUsePrintDialogSetting(true);
1066 void PrintDialog::updateOrientationBox( const bool bAutomatic
)
1070 Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1071 mxOrientationBox
->set_active( static_cast<sal_Int32
>(eOrientation
) + 1 );
1073 else if ( hasOrientationChanged() )
1075 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1079 bool PrintDialog::hasOrientationChanged() const
1081 const int nOrientation
= mxOrientationBox
->get_active();
1082 const Orientation eOrientation
= maPController
->getPrinter()->GetOrientation();
1084 return (nOrientation
== ORIENTATION_LANDSCAPE
&& eOrientation
== Orientation::Portrait
)
1085 || (nOrientation
== ORIENTATION_PORTRAIT
&& eOrientation
== Orientation::Landscape
);
1088 // Always use this function to set paper orientation to make sure everything behaves well
1089 void PrintDialog::setPaperOrientation( Orientation eOrientation
, bool fromUser
)
1091 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1092 aPrt
->SetOrientation( eOrientation
);
1093 maPController
->setOrientationFromUser( eOrientation
, fromUser
);
1096 void PrintDialog::checkControlDependencies()
1098 if (mxCopyCountField
->get_value() > 1)
1100 mxCollateBox
->set_sensitive( !mbCollateAlwaysOff
);
1101 mxSingleJobsBox
->set_sensitive( mxCollateBox
->get_active() );
1105 mxCollateBox
->set_sensitive( false );
1106 mxSingleJobsBox
->set_sensitive( false );
1109 OUString
aImg(mxCollateBox
->get_active() ? SV_PRINT_COLLATE_BMP
: SV_PRINT_NOCOLLATE_BMP
);
1111 mxCollateImage
->set_from_icon_name(aImg
);
1113 // enable setup button only for printers that can be setup
1114 bool bHaveSetup
= maPController
->getPrinter()->HasSupport( PrinterSupport::SetupDialog
);
1115 mxSetupButton
->set_sensitive(bHaveSetup
);
1118 void PrintDialog::checkOptionalControlDependencies()
1120 for( const auto& rEntry
: maControlToPropertyMap
)
1122 assert(rEntry
.first
);
1124 bool bShouldbeEnabled
= maPController
->isUIOptionEnabled( rEntry
.second
);
1126 if (bShouldbeEnabled
&& dynamic_cast<weld::RadioButton
*>(rEntry
.first
))
1128 auto r_it
= maControlToNumValMap
.find( rEntry
.first
);
1129 if( r_it
!= maControlToNumValMap
.end() )
1131 bShouldbeEnabled
= maPController
->isUIChoiceEnabled( rEntry
.second
, r_it
->second
);
1135 bool bIsEnabled
= rEntry
.first
->get_sensitive();
1136 // Enable does not do a change check first, so can be less cheap than expected
1137 if (bShouldbeEnabled
!= bIsEnabled
)
1138 rEntry
.first
->set_sensitive( bShouldbeEnabled
);
1142 void PrintDialog::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup
& i_rMPS
)
1144 mxNupOrderWin
->show();
1145 mxPagesBtn
->set_active(true);
1146 mxBrochureBtn
->hide();
1148 // setup field units for metric fields
1149 const LocaleDataWrapper
& rLocWrap(Application::GetSettings().GetLocaleDataWrapper());
1150 FieldUnit eUnit
= FieldUnit::MM
;
1151 sal_uInt16 nDigits
= 0;
1152 if( rLocWrap
.getMeasurementSystemEnum() == MeasurementSystem::US
)
1154 eUnit
= FieldUnit::INCH
;
1158 mxPageMarginEdt
->set_unit( eUnit
);
1159 mxSheetMarginEdt
->set_unit( eUnit
);
1162 mxPageMarginEdt
->set_digits( nDigits
);
1163 mxSheetMarginEdt
->set_digits( nDigits
);
1165 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( i_rMPS
.nLeftMargin
), FieldUnit::MM_100TH
);
1166 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( i_rMPS
.nHorizontalSpacing
), FieldUnit::MM_100TH
);
1167 mxBorderCB
->set_active( i_rMPS
.bDrawBorder
);
1168 mxNupRowsEdt
->set_value( i_rMPS
.nRows
);
1169 mxNupColEdt
->set_value( i_rMPS
.nColumns
);
1170 mxNupOrderBox
->set_active( static_cast<sal_Int32
>(i_rMPS
.nOrder
) );
1171 if( i_rMPS
.nRows
!= 1 || i_rMPS
.nColumns
!= 1 )
1173 mxNupPagesBox
->set_active( mxNupPagesBox
->get_count()-1 );
1174 showAdvancedControls( true );
1175 mxNupOrder
->setValues( i_rMPS
.nOrder
, i_rMPS
.nColumns
, i_rMPS
.nRows
);
1179 void PrintDialog::updateNup( bool i_bMayUseCache
)
1181 int nRows
= mxNupRowsEdt
->get_value();
1182 int nCols
= mxNupColEdt
->get_value();
1183 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1184 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1186 PrinterController::MultiPageSetup aMPS
;
1188 aMPS
.nColumns
= nCols
;
1192 aMPS
.nBottomMargin
= nSheetMargin
;
1194 aMPS
.nHorizontalSpacing
=
1195 aMPS
.nVerticalSpacing
= nPageMargin
;
1197 aMPS
.bDrawBorder
= mxBorderCB
->get_active();
1199 aMPS
.nOrder
= static_cast<NupOrderType
>(mxNupOrderBox
->get_active());
1201 int nOrientationMode
= mxOrientationBox
->get_active();
1202 if( nOrientationMode
== ORIENTATION_LANDSCAPE
)
1203 aMPS
.aPaperSize
= maNupLandscapeSize
;
1204 else if( nOrientationMode
== ORIENTATION_PORTRAIT
)
1205 aMPS
.aPaperSize
= maNupPortraitSize
;
1206 else // automatic mode
1208 // get size of first real page to see if it is portrait or landscape
1209 // we assume same page sizes for all the pages for this
1210 Size aPageSize
= getJobPageSize();
1212 Size
aMultiSize( aPageSize
.Width() * nCols
, aPageSize
.Height() * nRows
);
1213 if( aMultiSize
.Width() > aMultiSize
.Height() ) // fits better on landscape
1215 aMPS
.aPaperSize
= maNupLandscapeSize
;
1216 setPaperOrientation( Orientation::Landscape
, false );
1220 aMPS
.aPaperSize
= maNupPortraitSize
;
1221 setPaperOrientation( Orientation::Portrait
, false );
1225 maPController
->setMultipage( aMPS
);
1227 mxNupOrder
->setValues( aMPS
.nOrder
, nCols
, nRows
);
1230 maUpdatePreviewIdle
.Start();
1232 maUpdatePreviewNoCacheIdle
.Start();
1235 void PrintDialog::updateNupFromPages( bool i_bMayUseCache
)
1237 int nPages
= mxNupPagesBox
->get_active_id().toInt32();
1238 int nRows
= mxNupRowsEdt
->get_value();
1239 int nCols
= mxNupColEdt
->get_value();
1240 tools::Long nPageMargin
= mxPageMarginEdt
->denormalize(mxPageMarginEdt
->get_value( FieldUnit::MM_100TH
));
1241 tools::Long nSheetMargin
= mxSheetMarginEdt
->denormalize(mxSheetMarginEdt
->get_value( FieldUnit::MM_100TH
));
1242 bool bCustom
= false;
1250 else if( nPages
== 2 || nPages
== 4 || nPages
== 6 || nPages
== 9 || nPages
== 16 )
1252 Size
aJobPageSize( getJobPageSize() );
1253 bool bPortrait
= aJobPageSize
.Width() < aJobPageSize
.Height();
1267 else if( nPages
== 4 )
1269 else if( nPages
== 6 )
1282 else if( nPages
== 9 )
1284 else if( nPages
== 16 )
1294 // set upper limits for margins based on job page size and rows/columns
1295 Size
aSize( getJobPageSize() );
1297 // maximum sheet distance: 1/2 sheet
1298 tools::Long nHorzMax
= aSize
.Width()/2;
1299 tools::Long nVertMax
= aSize
.Height()/2;
1300 if( nSheetMargin
> nHorzMax
)
1301 nSheetMargin
= nHorzMax
;
1302 if( nSheetMargin
> nVertMax
)
1303 nSheetMargin
= nVertMax
;
1305 mxSheetMarginEdt
->set_max(
1306 mxSheetMarginEdt
->normalize(
1307 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1309 // maximum page distance
1310 nHorzMax
= (aSize
.Width() - 2*nSheetMargin
);
1312 nHorzMax
/= (nCols
-1);
1313 nVertMax
= (aSize
.Height() - 2*nSheetMargin
);
1315 nHorzMax
/= (nRows
-1);
1317 if( nPageMargin
> nHorzMax
)
1318 nPageMargin
= nHorzMax
;
1319 if( nPageMargin
> nVertMax
)
1320 nPageMargin
= nVertMax
;
1322 mxPageMarginEdt
->set_max(
1323 mxSheetMarginEdt
->normalize(
1324 std::min(nHorzMax
, nVertMax
) ), FieldUnit::MM_100TH
);
1327 mxNupRowsEdt
->set_value( nRows
);
1328 mxNupColEdt
->set_value( nCols
);
1329 mxPageMarginEdt
->set_value( mxPageMarginEdt
->normalize( nPageMargin
), FieldUnit::MM_100TH
);
1330 mxSheetMarginEdt
->set_value( mxSheetMarginEdt
->normalize( nSheetMargin
), FieldUnit::MM_100TH
);
1332 showAdvancedControls( bCustom
);
1333 updateNup( i_bMayUseCache
);
1336 void PrintDialog::enableNupControls( bool bEnable
)
1338 mxNupPagesBox
->set_sensitive( bEnable
);
1339 mxNupNumPagesTxt
->set_sensitive( bEnable
);
1340 mxNupColEdt
->set_sensitive( bEnable
);
1341 mxNupTimesTxt
->set_sensitive( bEnable
);
1342 mxNupRowsEdt
->set_sensitive( bEnable
);
1343 mxPageMarginTxt1
->set_sensitive( bEnable
);
1344 mxPageMarginEdt
->set_sensitive( bEnable
);
1345 mxPageMarginTxt2
->set_sensitive( bEnable
);
1346 mxSheetMarginTxt1
->set_sensitive( bEnable
);
1347 mxSheetMarginEdt
->set_sensitive( bEnable
);
1348 mxSheetMarginTxt2
->set_sensitive( bEnable
);
1349 mxNupOrderTxt
->set_sensitive( bEnable
);
1350 mxNupOrderBox
->set_sensitive( bEnable
);
1351 mxNupOrderWin
->set_sensitive( bEnable
);
1352 mxBorderCB
->set_sensitive( bEnable
);
1355 void PrintDialog::showAdvancedControls( bool i_bShow
)
1357 mxNupNumPagesTxt
->set_visible( i_bShow
);
1358 mxNupColEdt
->set_visible( i_bShow
);
1359 mxNupTimesTxt
->set_visible( i_bShow
);
1360 mxNupRowsEdt
->set_visible( i_bShow
);
1361 mxPageMarginTxt1
->set_visible( i_bShow
);
1362 mxPageMarginEdt
->set_visible( i_bShow
);
1363 mxPageMarginTxt2
->set_visible( i_bShow
);
1364 mxSheetMarginTxt1
->set_visible( i_bShow
);
1365 mxSheetMarginEdt
->set_visible( i_bShow
);
1366 mxSheetMarginTxt2
->set_visible( i_bShow
);
1371 void setHelpId( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpIds
, sal_Int32 i_nIndex
)
1373 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpIds
.getLength() )
1374 i_pWindow
->set_help_id( i_rHelpIds
.getConstArray()[i_nIndex
] );
1377 void setHelpText( weld::Widget
* i_pWindow
, const Sequence
< OUString
>& i_rHelpTexts
, sal_Int32 i_nIndex
)
1379 // without a help text set and the correct smartID,
1380 // help texts will be retrieved from the online help system
1381 if( i_nIndex
>= 0 && i_nIndex
< i_rHelpTexts
.getLength() )
1382 i_pWindow
->set_tooltip_text(i_rHelpTexts
.getConstArray()[i_nIndex
]);
1386 void PrintDialog::setupOptionalUI()
1388 const Sequence
< PropertyValue
>& rOptions( maPController
->getUIOptions() );
1389 for( const auto& rOption
: rOptions
)
1391 if (rOption
.Name
== "OptionsUIFile")
1393 OUString sOptionsUIFile
;
1394 rOption
.Value
>>= sOptionsUIFile
;
1395 mxCustomOptionsUIBuilder
= Application::CreateBuilder(mxCustom
.get(), sOptionsUIFile
);
1396 std::unique_ptr
<weld::Container
> xWindow
= mxCustomOptionsUIBuilder
->weld_container(u
"box"_ustr
);
1397 xWindow
->set_help_id(u
"vcl/ui/printdialog/PrintDialog"_ustr
);
1402 Sequence
< beans::PropertyValue
> aOptProp
;
1403 rOption
.Value
>>= aOptProp
;
1405 // extract ui element
1409 OUString aPropertyName
;
1410 Sequence
< OUString
> aChoices
;
1411 Sequence
< sal_Bool
> aChoicesDisabled
;
1412 Sequence
< OUString
> aHelpTexts
;
1413 Sequence
< OUString
> aIDs
;
1414 Sequence
< OUString
> aHelpIds
;
1415 sal_Int64 nMinValue
= 0, nMaxValue
= 0;
1416 OUString aGroupingHint
;
1418 for (const beans::PropertyValue
& rEntry
: aOptProp
)
1420 if ( rEntry
.Name
== "ID" )
1422 rEntry
.Value
>>= aIDs
;
1425 if ( rEntry
.Name
== "Text" )
1427 rEntry
.Value
>>= aText
;
1429 else if ( rEntry
.Name
== "ControlType" )
1431 rEntry
.Value
>>= aCtrlType
;
1433 else if ( rEntry
.Name
== "Choices" )
1435 rEntry
.Value
>>= aChoices
;
1437 else if ( rEntry
.Name
== "ChoicesDisabled" )
1439 rEntry
.Value
>>= aChoicesDisabled
;
1441 else if ( rEntry
.Name
== "Property" )
1444 rEntry
.Value
>>= aVal
;
1445 aPropertyName
= aVal
.Name
;
1447 else if ( rEntry
.Name
== "Enabled" )
1450 else if ( rEntry
.Name
== "GroupingHint" )
1452 rEntry
.Value
>>= aGroupingHint
;
1454 else if ( rEntry
.Name
== "DependsOnName" )
1457 else if ( rEntry
.Name
== "DependsOnEntry" )
1460 else if ( rEntry
.Name
== "AttachToDependency" )
1463 else if ( rEntry
.Name
== "MinValue" )
1465 rEntry
.Value
>>= nMinValue
;
1467 else if ( rEntry
.Name
== "MaxValue" )
1469 rEntry
.Value
>>= nMaxValue
;
1471 else if ( rEntry
.Name
== "HelpText" )
1473 if( ! (rEntry
.Value
>>= aHelpTexts
) )
1476 if( rEntry
.Value
>>= aHelpText
)
1478 aHelpTexts
.realloc( 1 );
1479 *aHelpTexts
.getArray() = aHelpText
;
1483 else if ( rEntry
.Name
== "HelpId" )
1485 if( ! (rEntry
.Value
>>= aHelpIds
) )
1488 if( rEntry
.Value
>>= aHelpId
)
1490 aHelpIds
.realloc( 1 );
1491 *aHelpIds
.getArray() = aHelpId
;
1495 else if ( rEntry
.Name
== "HintNoLayoutPage" )
1497 bool bHasLayoutFrame
= false;
1498 rEntry
.Value
>>= bHasLayoutFrame
;
1499 mbShowLayoutFrame
= !bHasLayoutFrame
;
1503 if (aCtrlType
== "Group")
1507 weld::Container
* pPage
= mxTabCtrl
->get_page(aID
);
1511 mxTabCtrl
->set_tab_label_text(aID
, aText
);
1514 if (aHelpIds
.hasElements())
1515 pPage
->set_help_id(aHelpIds
[0]);
1518 if (aHelpTexts
.hasElements())
1519 pPage
->set_tooltip_text(aHelpTexts
[0]);
1523 else if (aCtrlType
== "Subgroup" && !aID
.isEmpty())
1525 std::unique_ptr
<weld::Widget
> xWidget
;
1526 // since 'New Print Dialog Design' fromwhich in calc is not a frame anymore
1527 if (aID
== "fromwhich")
1529 std::unique_ptr
<weld::Label
> xLabel
= m_xBuilder
->weld_label(aID
);
1530 xLabel
->set_label(aText
);
1531 xWidget
= std::move(xLabel
);
1535 std::unique_ptr
<weld::Frame
> xFrame
= m_xBuilder
->weld_frame(aID
);
1536 if (!xFrame
&& mxCustomOptionsUIBuilder
)
1537 xFrame
= mxCustomOptionsUIBuilder
->weld_frame(aID
);
1540 xFrame
->set_label(aText
);
1541 xWidget
= std::move(xFrame
);
1549 setHelpId(xWidget
.get(), aHelpIds
, 0);
1551 setHelpText(xWidget
.get(), aHelpTexts
, 0);
1556 else if( aCtrlType
== "Bool" && aGroupingHint
== "LayoutPage" && aPropertyName
== "PrintProspect" )
1558 mxBrochureBtn
->set_label(aText
);
1559 mxBrochureBtn
->show();
1562 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1564 pVal
->Value
>>= bVal
;
1565 mxBrochureBtn
->set_active( bVal
);
1566 mxBrochureBtn
->set_sensitive( maPController
->isUIOptionEnabled( aPropertyName
) && pVal
!= nullptr );
1568 maPropertyToWindowMap
[aPropertyName
].emplace_back(mxBrochureBtn
.get());
1569 maControlToPropertyMap
[mxBrochureBtn
.get()] = aPropertyName
;
1572 setHelpId( mxBrochureBtn
.get(), aHelpIds
, 0 );
1574 setHelpText( mxBrochureBtn
.get(), aHelpTexts
, 0 );
1576 else if (aCtrlType
== "Bool")
1579 std::unique_ptr
<weld::CheckButton
> xNewBox
= m_xBuilder
->weld_check_button(aID
);
1580 if (!xNewBox
&& mxCustomOptionsUIBuilder
)
1581 xNewBox
= mxCustomOptionsUIBuilder
->weld_check_button(aID
);
1585 xNewBox
->set_label( aText
);
1589 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1591 pVal
->Value
>>= bVal
;
1592 xNewBox
->set_active( bVal
);
1593 xNewBox
->connect_toggled( LINK( this, PrintDialog
, UIOption_CheckHdl
) );
1595 maExtraControls
.emplace_back(std::move(xNewBox
));
1597 weld::Widget
* pWidget
= maExtraControls
.back().get();
1599 maPropertyToWindowMap
[aPropertyName
].emplace_back(pWidget
);
1600 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1603 setHelpId(pWidget
, aHelpIds
, 0);
1605 setHelpText(pWidget
, aHelpTexts
, 0);
1607 else if (aCtrlType
== "Radio")
1609 sal_Int32 nCurHelpText
= 0;
1612 sal_Int32 nSelectVal
= 0;
1613 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1614 if( pVal
&& pVal
->Value
.hasValue() )
1615 pVal
->Value
>>= nSelectVal
;
1616 for( sal_Int32 m
= 0; m
< aChoices
.getLength(); m
++ )
1619 std::unique_ptr
<weld::RadioButton
> xBtn
= m_xBuilder
->weld_radio_button(aID
);
1620 if (!xBtn
&& mxCustomOptionsUIBuilder
)
1621 xBtn
= mxCustomOptionsUIBuilder
->weld_radio_button(aID
);
1625 xBtn
->set_label( aChoices
[m
] );
1626 xBtn
->set_active( m
== nSelectVal
);
1627 xBtn
->connect_toggled( LINK( this, PrintDialog
, UIOption_RadioHdl
) );
1628 if( aChoicesDisabled
.getLength() > m
&& aChoicesDisabled
[m
] )
1629 xBtn
->set_sensitive( false );
1632 maExtraControls
.emplace_back(std::move(xBtn
));
1634 weld::Widget
* pWidget
= maExtraControls
.back().get();
1636 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1637 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1638 maControlToNumValMap
[pWidget
] = m
;
1641 setHelpId( pWidget
, aHelpIds
, nCurHelpText
);
1643 setHelpText( pWidget
, aHelpTexts
, nCurHelpText
);
1647 else if ( aCtrlType
== "List" )
1649 std::unique_ptr
<weld::ComboBox
> xList
= m_xBuilder
->weld_combo_box(aID
);
1650 if (!xList
&& mxCustomOptionsUIBuilder
)
1651 xList
= mxCustomOptionsUIBuilder
->weld_combo_box(aID
);
1656 for (const auto& rChoice
: aChoices
)
1657 xList
->append_text(rChoice
);
1659 sal_Int32 nSelectVal
= 0;
1660 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1661 if( pVal
&& pVal
->Value
.hasValue() )
1662 pVal
->Value
>>= nSelectVal
;
1663 xList
->set_active(nSelectVal
);
1664 xList
->connect_changed( LINK( this, PrintDialog
, UIOption_SelectHdl
) );
1667 maExtraControls
.emplace_back(std::move(xList
));
1669 weld::Widget
* pWidget
= maExtraControls
.back().get();
1671 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1672 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1675 setHelpId( pWidget
, aHelpIds
, 0 );
1677 setHelpText( pWidget
, aHelpTexts
, 0 );
1679 else if ( aCtrlType
== "Range" )
1681 std::unique_ptr
<weld::SpinButton
> xField
= m_xBuilder
->weld_spin_button(aID
);
1682 if (!xField
&& mxCustomOptionsUIBuilder
)
1683 xField
= mxCustomOptionsUIBuilder
->weld_spin_button(aID
);
1687 // set min/max and current value
1688 if(nMinValue
!= nMaxValue
)
1689 xField
->set_range(nMinValue
, nMaxValue
);
1691 sal_Int64 nCurVal
= 0;
1692 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1693 if( pVal
&& pVal
->Value
.hasValue() )
1694 pVal
->Value
>>= nCurVal
;
1695 xField
->set_value( nCurVal
);
1696 xField
->connect_value_changed( LINK( this, PrintDialog
, UIOption_SpinModifyHdl
) );
1699 maExtraControls
.emplace_back(std::move(xField
));
1701 weld::Widget
* pWidget
= maExtraControls
.back().get();
1703 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1704 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1707 setHelpId( pWidget
, aHelpIds
, 0 );
1709 setHelpText( pWidget
, aHelpTexts
, 0 );
1711 else if (aCtrlType
== "Edit")
1713 std::unique_ptr
<weld::Entry
> xField
= m_xBuilder
->weld_entry(aID
);
1714 if (!xField
&& mxCustomOptionsUIBuilder
)
1715 xField
= mxCustomOptionsUIBuilder
->weld_entry(aID
);
1720 PropertyValue
* pVal
= maPController
->getValue( aPropertyName
);
1721 if( pVal
&& pVal
->Value
.hasValue() )
1722 pVal
->Value
>>= aCurVal
;
1723 xField
->set_text( aCurVal
);
1724 xField
->connect_changed( LINK( this, PrintDialog
, UIOption_EntryModifyHdl
) );
1727 maExtraControls
.emplace_back(std::move(xField
));
1729 weld::Widget
* pWidget
= maExtraControls
.back().get();
1731 maPropertyToWindowMap
[ aPropertyName
].emplace_back(pWidget
);
1732 maControlToPropertyMap
[pWidget
] = aPropertyName
;
1735 setHelpId( pWidget
, aHelpIds
, 0 );
1737 setHelpText( pWidget
, aHelpTexts
, 0 );
1741 SAL_WARN( "vcl", "Unsupported UI option: \"" << aCtrlType
<< '"');
1745 // #i106506# if no brochure button, then the singular Pages radio button
1746 // makes no sense, so replace it by a FixedText label
1747 if (!mxBrochureBtn
->get_visible() && mxPagesBtn
->get_visible())
1749 mxPagesBoxTitleTxt
->set_label(mxPagesBtn
->get_label());
1750 mxPagesBoxTitleTxt
->show();
1753 mxNupPagesBox
->set_accessible_relation_labeled_by(mxPagesBoxTitleTxt
.get());
1756 // update enable states
1757 checkOptionalControlDependencies();
1759 // print range not shown (currently math only) -> hide spacer line and reverse order
1760 if (!mxPageRangeEdit
->get_visible())
1762 mxReverseOrderBox
->hide();
1765 if (!mxCustomOptionsUIBuilder
)
1766 mxTabCtrl
->remove_page(mxTabCtrl
->get_page_ident(1));
1769 void PrintDialog::makeEnabled( weld::Widget
* i_pWindow
)
1771 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1772 if( it
!= maControlToPropertyMap
.end() )
1774 OUString
aDependency( maPController
->makeEnabled( it
->second
) );
1775 if( !aDependency
.isEmpty() )
1776 updateWindowFromProperty( aDependency
);
1780 void PrintDialog::updateWindowFromProperty( const OUString
& i_rProperty
)
1782 beans::PropertyValue
* pValue
= maPController
->getValue( i_rProperty
);
1783 auto it
= maPropertyToWindowMap
.find( i_rProperty
);
1784 if( !(pValue
&& it
!= maPropertyToWindowMap
.end()) )
1787 const auto& rWindows( it
->second
);
1788 if( rWindows
.empty() )
1792 sal_Int32 nVal
= -1;
1793 if( pValue
->Value
>>= bVal
)
1795 // we should have a CheckBox for this one
1796 weld::CheckButton
* pBox
= dynamic_cast<weld::CheckButton
*>(rWindows
.front());
1799 pBox
->set_active( bVal
);
1801 else if ( i_rProperty
== "PrintProspect" )
1803 // EVIL special case
1805 mxBrochureBtn
->set_active(true);
1807 mxPagesBtn
->set_active(true);
1811 SAL_WARN( "vcl", "missing a checkbox" );
1814 else if( pValue
->Value
>>= nVal
)
1816 // this could be a ListBox or a RadioButtonGroup
1817 weld::ComboBox
* pList
= dynamic_cast<weld::ComboBox
*>(rWindows
.front());
1820 pList
->set_active( static_cast< sal_uInt16
>(nVal
) );
1822 else if( nVal
>= 0 && o3tl::make_unsigned(nVal
) < rWindows
.size() )
1824 weld::RadioButton
* pBtn
= dynamic_cast<weld::RadioButton
*>(rWindows
[nVal
]);
1825 SAL_WARN_IF( !pBtn
, "vcl", "unexpected control for property" );
1827 pBtn
->set_active(true);
1832 bool PrintDialog::isPrintToFile() const
1834 return ( mxPrinters
->get_active() == 0 );
1837 bool PrintDialog::isCollate() const
1839 return mxCopyCountField
->get_value() > 1 && mxCollateBox
->get_active();
1842 bool PrintDialog::isSingleJobs() const
1844 return mxSingleJobsBox
->get_active();
1847 bool PrintDialog::hasPreview() const
1849 return mxPreviewBox
->get_active();
1852 PropertyValue
* PrintDialog::getValueForWindow( weld::Widget
* i_pWindow
) const
1854 PropertyValue
* pVal
= nullptr;
1855 auto it
= maControlToPropertyMap
.find( i_pWindow
);
1856 if( it
!= maControlToPropertyMap
.end() )
1858 pVal
= maPController
->getValue( it
->second
);
1859 SAL_WARN_IF( !pVal
, "vcl", "property value not found" );
1863 OSL_FAIL( "changed control not in property map" );
1868 IMPL_LINK(PrintDialog
, ToggleHdl
, weld::Toggleable
&, rButton
, void)
1870 if (&rButton
== mxPreviewBox
.get())
1872 maUpdatePreviewIdle
.Start();
1874 else if( &rButton
== mxBorderCB
.get() )
1878 else if (&rButton
== mxSingleJobsBox
.get())
1880 maPController
->setValue( u
"SinglePrintJobs"_ustr
,
1881 Any( isSingleJobs() ) );
1882 checkControlDependencies();
1884 else if( &rButton
== mxCollateBox
.get() )
1886 maPController
->setValue( u
"Collate"_ustr
,
1887 Any( isCollate() ) );
1888 checkControlDependencies();
1890 else if( &rButton
== mxReverseOrderBox
.get() )
1892 bool bChecked
= mxReverseOrderBox
->get_active();
1893 maPController
->setReversePrint( bChecked
);
1894 maPController
->setValue( u
"PrintReverse"_ustr
,
1896 maUpdatePreviewIdle
.Start();
1898 else if (&rButton
== mxBrochureBtn
.get())
1900 PropertyValue
* pVal
= getValueForWindow(mxBrochureBtn
.get());
1903 bool bVal
= mxBrochureBtn
->get_active();
1904 pVal
->Value
<<= bVal
;
1906 checkOptionalControlDependencies();
1908 // update preview and page settings
1909 maUpdatePreviewNoCacheIdle
.Start();
1911 if (mxBrochureBtn
->get_active())
1913 mxOrientationBox
->set_sensitive( false );
1914 mxOrientationBox
->set_active( ORIENTATION_LANDSCAPE
);
1915 mxNupPagesBox
->set_active( 0 );
1916 updateNupFromPages();
1917 showAdvancedControls( false );
1918 enableNupControls( false );
1922 mxOrientationBox
->set_sensitive( true );
1923 mxOrientationBox
->set_active( ORIENTATION_AUTOMATIC
);
1924 enableNupControls( true );
1925 updateNupFromPages();
1931 IMPL_LINK(PrintDialog
, ClickHdl
, weld::Button
&, rButton
, void)
1933 if (&rButton
== mxOKButton
.get() || &rButton
== mxCancelButton
.get())
1936 m_xDialog
->response(&rButton
== mxOKButton
.get() ? RET_OK
: RET_CANCEL
);
1938 else if( &rButton
== mxForwardBtn
.get() )
1942 else if( &rButton
== mxBackwardBtn
.get() )
1946 else if( &rButton
== mxFirstBtn
.get() )
1950 else if( &rButton
== mxLastBtn
.get() )
1956 if( &rButton
== mxSetupButton
.get() )
1958 maPController
->setupPrinter(m_xDialog
.get());
1960 if ( !isPrintToFile() )
1962 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
1963 mePaper
= aPrt
->GetPaper();
1965 for (int nPaper
= 0; nPaper
< aPrt
->GetPaperInfoCount(); nPaper
++ )
1967 PaperInfo aInfo
= aPrt
->GetPaperInfo( nPaper
);
1968 aInfo
.doSloppyFit(true);
1969 Paper ePaper
= aInfo
.getPaper();
1971 if ( mePaper
== ePaper
)
1973 mxPaperSizeBox
->set_active( nPaper
);
1979 updateOrientationBox( false );
1981 updatePageSize(mxOrientationBox
->get_active());
1983 setupPaperSidesBox();
1985 // tdf#63905 don't use cache: page size may change
1986 maUpdatePreviewNoCacheIdle
.Start();
1988 checkControlDependencies();
1993 IMPL_LINK( PrintDialog
, SelectHdl
, weld::ComboBox
&, rBox
, void )
1995 if (&rBox
== mxPrinters
.get())
1997 if ( !isPrintToFile() )
1999 OUString
aNewPrinter(rBox
.get_active_text());
2001 maPController
->setPrinter( VclPtrInstance
<Printer
>( aNewPrinter
) );
2002 maPController
->resetPrinterOptions( false );
2003 // invalidate page cache and start fresh
2004 maPController
->invalidatePageCache();
2005 maFirstPageSize
= Size();
2007 updateOrientationBox();
2009 // update text fields
2010 mxOKButton
->set_label(maPrintText
);
2011 updatePrinterText();
2014 maUpdatePreviewIdle
.Start();
2016 else // print to file
2018 // use the default printer or FIXME: the last used one?
2019 maPController
->setPrinter( VclPtrInstance
<Printer
>( Printer::GetDefaultPrinterName() ) );
2020 mxOKButton
->set_label(maPrintToFileText
);
2021 maPController
->resetPrinterOptions( true );
2024 updateOrientationBox();
2025 maUpdatePreviewIdle
.Start();
2028 updatePageSize(mxOrientationBox
->get_active());
2029 setupPaperSidesBox();
2031 else if ( &rBox
== mxPaperSidesBox
.get() )
2033 DuplexMode eDuplex
= static_cast<DuplexMode
>(mxPaperSidesBox
->get_active() + 1);
2034 maPController
->getPrinter()->SetDuplexMode( eDuplex
);
2036 else if( &rBox
== mxOrientationBox
.get() )
2038 int nOrientation
= mxOrientationBox
->get_active();
2039 if ( nOrientation
!= ORIENTATION_AUTOMATIC
)
2040 setPaperOrientation( static_cast<Orientation
>( nOrientation
- 1 ), true );
2042 updatePageSize(nOrientation
);
2045 else if ( &rBox
== mxNupOrderBox
.get() )
2049 else if( &rBox
== mxNupPagesBox
.get() )
2051 if( !mxPagesBtn
->get_active() )
2052 mxPagesBtn
->set_active(true);
2053 updatePageSize(mxOrientationBox
->get_active());
2054 updateNupFromPages( false );
2056 else if ( &rBox
== mxPaperSizeBox
.get() )
2058 VclPtr
<Printer
> aPrt( maPController
->getPrinter() );
2059 PaperInfo aInfo
= aPrt
->GetPaperInfo( rBox
.get_active() );
2060 aInfo
.doSloppyFit(true);
2061 mePaper
= aInfo
.getPaper();
2063 if ( mePaper
== PAPER_USER
)
2064 aPrt
->SetPaperSizeUser( Size( aInfo
.getWidth(), aInfo
.getHeight() ) );
2066 aPrt
->SetPaper( mePaper
);
2068 maPController
->setPaperSizeFromUser( Size( aInfo
.getWidth(), aInfo
.getHeight() ) );
2070 updatePageSize(mxOrientationBox
->get_active());
2072 maUpdatePreviewNoCacheIdle
.Start();
2076 IMPL_LINK_NOARG(PrintDialog
, MetricSpinModifyHdl
, weld::MetricSpinButton
&, void)
2078 checkControlDependencies();
2079 updateNupFromPages();
2082 IMPL_LINK_NOARG(PrintDialog
, FocusOutHdl
, weld::Widget
&, void)
2084 ActivateHdl(*mxPageEdit
);
2087 IMPL_LINK_NOARG(PrintDialog
, ActivateHdl
, weld::Entry
&, bool)
2089 sal_Int32 nPage
= mxPageEdit
->get_text().toInt32();
2093 mxPageEdit
->set_text(u
"1"_ustr
);
2095 else if (nPage
> mnCachedPages
)
2097 nPage
= mnCachedPages
;
2098 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2100 int nNewCurPage
= nPage
- 1;
2101 if (nNewCurPage
!= mnCurPage
)
2103 mnCurPage
= nNewCurPage
;
2104 maUpdatePreviewIdle
.Start();
2109 IMPL_LINK( PrintDialog
, SpinModifyHdl
, weld::SpinButton
&, rEdit
, void )
2111 checkControlDependencies();
2112 if (&rEdit
== mxNupRowsEdt
.get() || &rEdit
== mxNupColEdt
.get())
2114 updateNupFromPages();
2116 else if( &rEdit
== mxCopyCountField
.get() )
2118 maPController
->setValue( u
"CopyCount"_ustr
,
2119 Any( sal_Int32(mxCopyCountField
->get_value()) ) );
2120 maPController
->setValue( u
"Collate"_ustr
,
2121 Any( isCollate() ) );
2125 IMPL_LINK( PrintDialog
, UIOption_CheckHdl
, weld::Toggleable
&, i_rBox
, void )
2127 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2130 makeEnabled( &i_rBox
);
2132 bool bVal
= i_rBox
.get_active();
2133 pVal
->Value
<<= bVal
;
2135 checkOptionalControlDependencies();
2137 // update preview and page settings
2138 maUpdatePreviewNoCacheIdle
.Start();
2142 IMPL_LINK( PrintDialog
, UIOption_RadioHdl
, weld::Toggleable
&, i_rBtn
, void )
2144 // this handler gets called for all radiobuttons that get unchecked, too
2145 // however we only want one notification for the new value (that is for
2146 // the button that gets checked)
2147 if( !i_rBtn
.get_active() )
2150 PropertyValue
* pVal
= getValueForWindow( &i_rBtn
);
2151 auto it
= maControlToNumValMap
.find( &i_rBtn
);
2152 if( !(pVal
&& it
!= maControlToNumValMap
.end()) )
2155 makeEnabled( &i_rBtn
);
2157 sal_Int32 nVal
= it
->second
;
2158 pVal
->Value
<<= nVal
;
2160 updateOrientationBox();
2162 checkOptionalControlDependencies();
2164 // tdf#41205 give focus to the page range edit if the corresponding radio button was selected
2165 if (pVal
->Name
== "PrintContent" && mxPageRangesRadioButton
->get_active())
2166 mxPageRangeEdit
->grab_focus();
2168 // update preview and page settings
2169 maUpdatePreviewNoCacheIdle
.Start();
2172 IMPL_LINK( PrintDialog
, UIOption_SelectHdl
, weld::ComboBox
&, i_rBox
, void )
2174 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2178 makeEnabled( &i_rBox
);
2180 sal_Int32
nVal( i_rBox
.get_active() );
2181 pVal
->Value
<<= nVal
;
2183 //If we are in impress we start in print slides mode and get a
2184 //maFirstPageSize for slides which are usually landscape mode, if we
2185 //change to notes which are usually in portrait mode, and then visit
2186 //n-up print, we will assume notes are in landscape unless we throw
2187 //away maFirstPageSize when we change page content type
2188 if (pVal
->Name
== "PageContentType")
2189 maFirstPageSize
= Size();
2191 checkOptionalControlDependencies();
2193 // update preview and page settings
2194 maUpdatePreviewNoCacheIdle
.Start();
2197 IMPL_LINK( PrintDialog
, UIOption_SpinModifyHdl
, weld::SpinButton
&, i_rBox
, void )
2199 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2202 makeEnabled( &i_rBox
);
2204 sal_Int64 nVal
= i_rBox
.get_value();
2205 pVal
->Value
<<= nVal
;
2207 checkOptionalControlDependencies();
2209 // update preview and page settings
2210 maUpdatePreviewNoCacheIdle
.Start();
2214 IMPL_LINK( PrintDialog
, UIOption_EntryModifyHdl
, weld::Entry
&, i_rBox
, void )
2216 PropertyValue
* pVal
= getValueForWindow( &i_rBox
);
2217 if( pVal
&& mxPageRangesRadioButton
->get_active() )
2219 makeEnabled( &i_rBox
);
2221 OUString
aVal( i_rBox
.get_text() );
2222 pVal
->Value
<<= aVal
;
2224 checkOptionalControlDependencies();
2226 // update preview and page settings
2227 maUpdatePreviewNoCacheIdle
.Start();
2231 void PrintDialog::previewForward()
2233 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() + 1;
2234 if (nValue
<= mnCachedPages
)
2236 mxPageEdit
->set_text(OUString::number(nValue
));
2237 ActivateHdl(*mxPageEdit
);
2241 void PrintDialog::previewBackward()
2243 sal_Int32 nValue
= mxPageEdit
->get_text().toInt32() - 1;
2246 mxPageEdit
->set_text(OUString::number(nValue
));
2247 ActivateHdl(*mxPageEdit
);
2251 void PrintDialog::previewFirst()
2253 mxPageEdit
->set_text(u
"1"_ustr
);
2254 ActivateHdl(*mxPageEdit
);
2257 void PrintDialog::previewLast()
2259 mxPageEdit
->set_text(OUString::number(mnCachedPages
));
2260 ActivateHdl(*mxPageEdit
);
2264 static OUString
getNewLabel(const OUString
& aLabel
, int i_nCurr
, int i_nMax
)
2266 OUString
aNewText( aLabel
.replaceFirst( "%p", OUString::number( i_nCurr
) ) );
2267 aNewText
= aNewText
.replaceFirst( "%n", OUString::number( i_nMax
) );
2272 // PrintProgressDialog
2273 PrintProgressDialog::PrintProgressDialog(weld::Window
* i_pParent
, int i_nMax
)
2274 : GenericDialogController(i_pParent
, u
"vcl/ui/printprogressdialog.ui"_ustr
, u
"PrintProgressDialog"_ustr
)
2278 , mxText(m_xBuilder
->weld_label(u
"label"_ustr
))
2279 , mxProgress(m_xBuilder
->weld_progress_bar(u
"progressbar"_ustr
))
2280 , mxButton(m_xBuilder
->weld_button(u
"cancel"_ustr
))
2285 maStr
= mxText
->get_label();
2287 //just multiply largest value by 10 and take the width of that string as
2288 //the max size we will want
2289 mxText
->set_label(getNewLabel(maStr
, mnMax
* 10, mnMax
* 10));
2290 mxText
->set_size_request(mxText
->get_preferred_size().Width(), -1);
2292 //Pick a useful max width
2293 mxProgress
->set_size_request(mxProgress
->get_approximate_digit_width() * 25, -1);
2295 mxButton
->connect_clicked( LINK( this, PrintProgressDialog
, ClickHdl
) );
2297 // after this patch f7157f04fab298423e2c4f6a7e5f8e361164b15f, we have seen the calc Max string (sometimes) look above
2298 // now init to the right start values
2299 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2302 PrintProgressDialog::~PrintProgressDialog()
2306 IMPL_LINK_NOARG(PrintProgressDialog
, ClickHdl
, weld::Button
&, void)
2311 void PrintProgressDialog::setProgress( int i_nCurrent
)
2318 mxText
->set_label(getNewLabel(maStr
, mnCur
, mnMax
));
2320 // here view the dialog, with the right label
2321 mxProgress
->set_percentage(mnCur
*100/mnMax
);
2324 void PrintProgressDialog::tick()
2327 setProgress( ++mnCur
);
2330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */