/src/libreoffice/vcl/source/window/printdlg.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <o3tl/safeint.hxx> |
21 | | #include <sal/log.hxx> |
22 | | #include <osl/diagnose.h> |
23 | | #include <rtl/ustrbuf.hxx> |
24 | | #include <tools/mapunit.hxx> |
25 | | #include <unotools/localedatawrapper.hxx> |
26 | | #include <officecfg/Office/Common.hxx> |
27 | | #include <officecfg/VCL.hxx> |
28 | | |
29 | | #include <utility> |
30 | | #include <vcl/QueueInfo.hxx> |
31 | | #include <vcl/commandevent.hxx> |
32 | | #include <vcl/decoview.hxx> |
33 | | #include <vcl/help.hxx> |
34 | | #include <vcl/naturalsort.hxx> |
35 | | #include <vcl/print.hxx> |
36 | | #include <vcl/printer/Options.hxx> |
37 | | #include <vcl/PrinterSupport.hxx> |
38 | | #include <vcl/rendercontext/DrawModeFlags.hxx> |
39 | | #include <vcl/settings.hxx> |
40 | | #include <vcl/svapp.hxx> |
41 | | #include <vcl/virdev.hxx> |
42 | | #include <vcl/wall.hxx> |
43 | | #include <vcl/weld/Builder.hxx> |
44 | | #include <vcl/weld/Dialog.hxx> |
45 | | #include <vcl/weld/weldutils.hxx> |
46 | | #include <vcl/windowstate.hxx> |
47 | | |
48 | | #include <bitmaps.hlst> |
49 | | #include <printdlg.hxx> |
50 | | #include <strings.hrc> |
51 | | #include <svdata.hxx> |
52 | | |
53 | | #include <com/sun/star/beans/PropertyValue.hpp> |
54 | | |
55 | | using namespace vcl; |
56 | | using namespace com::sun::star; |
57 | | using namespace com::sun::star::uno; |
58 | | using namespace com::sun::star::container; |
59 | | using namespace com::sun::star::beans; |
60 | | |
61 | | enum |
62 | | { |
63 | | ORIENTATION_AUTOMATIC, |
64 | | ORIENTATION_PORTRAIT, |
65 | | ORIENTATION_LANDSCAPE |
66 | | }; |
67 | | |
68 | | namespace { |
69 | | bool lcl_ListBoxCompare( const OUString& rStr1, const OUString& rStr2 ) |
70 | 0 | { |
71 | 0 | return vcl::NaturalSortCompare( rStr1, rStr2 ) < 0; |
72 | 0 | } |
73 | | } |
74 | | |
75 | | PrintDialog::PrintPreviewWindow::PrintPreviewWindow(PrintDialog* pDialog) |
76 | 0 | : mpDialog(pDialog) |
77 | 0 | , maOrigSize( 10, 10 ) |
78 | 0 | , mnDPIX(Application::GetDefaultDevice()->GetDPIX()) |
79 | 0 | , mnDPIY(Application::GetDefaultDevice()->GetDPIY()) |
80 | 0 | , mbGreyscale( false ) |
81 | 0 | { |
82 | 0 | } |
83 | | |
84 | | PrintDialog::PrintPreviewWindow::~PrintPreviewWindow() |
85 | 0 | { |
86 | 0 | } |
87 | | |
88 | | void PrintDialog::PrintPreviewWindow::Resize() |
89 | 0 | { |
90 | 0 | Size aNewSize(GetOutputSizePixel()); |
91 | 0 | tools::Long nTextHeight = GetDrawingArea()->get_text_height(); |
92 | | // leave small space for decoration |
93 | 0 | aNewSize.AdjustWidth( -(nTextHeight + 2) ); |
94 | 0 | aNewSize.AdjustHeight( -(nTextHeight + 2) ); |
95 | 0 | Size aScaledSize; |
96 | 0 | double fScale = 1.0; |
97 | | |
98 | | // #i106435# catch corner case of Size(0,0) |
99 | 0 | Size aOrigSize( maOrigSize ); |
100 | 0 | if( aOrigSize.Width() < 1 ) |
101 | 0 | aOrigSize.setWidth( aNewSize.Width() ); |
102 | 0 | if( aOrigSize.Height() < 1 ) |
103 | 0 | aOrigSize.setHeight( aNewSize.Height() ); |
104 | 0 | if( aOrigSize.Width() > aOrigSize.Height() ) |
105 | 0 | { |
106 | 0 | aScaledSize = Size( aNewSize.Width(), aNewSize.Width() * aOrigSize.Height() / aOrigSize.Width() ); |
107 | 0 | if( aScaledSize.Height() > aNewSize.Height() ) |
108 | 0 | fScale = double(aNewSize.Height())/double(aScaledSize.Height()); |
109 | 0 | } |
110 | 0 | else |
111 | 0 | { |
112 | 0 | aScaledSize = Size( aNewSize.Height() * aOrigSize.Width() / aOrigSize.Height(), aNewSize.Height() ); |
113 | 0 | if( aScaledSize.Width() > aNewSize.Width() ) |
114 | 0 | fScale = double(aNewSize.Width())/double(aScaledSize.Width()); |
115 | 0 | } |
116 | 0 | aScaledSize.setWidth( tools::Long(aScaledSize.Width()*fScale) ); |
117 | 0 | aScaledSize.setHeight( tools::Long(aScaledSize.Height()*fScale) ); |
118 | |
|
119 | 0 | maPreviewSize = aScaledSize; |
120 | | |
121 | | // check and evtl. recreate preview bitmap |
122 | 0 | preparePreviewBitmap(); |
123 | 0 | } |
124 | | |
125 | | void PrintDialog::PrintPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) |
126 | 0 | { |
127 | 0 | auto popIt = rRenderContext.ScopedPush(); |
128 | 0 | weld::SetPointFont(rRenderContext, rRenderContext.GetSettings().GetStyleSettings().GetLabelFont()); |
129 | 0 | rRenderContext.SetTextColor(rRenderContext.GetSettings().GetStyleSettings().GetLabelTextColor()); |
130 | 0 | rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor())); |
131 | 0 | rRenderContext.Erase(); |
132 | |
|
133 | 0 | auto nTextHeight = rRenderContext.GetTextHeight(); |
134 | 0 | Size aSize(GetOutputSizePixel()); |
135 | 0 | Point aOffset((aSize.Width() - maPreviewSize.Width() + nTextHeight) / 2, |
136 | 0 | (aSize.Height() - maPreviewSize.Height() + nTextHeight) / 2); |
137 | | |
138 | | // horizontal line |
139 | 0 | { |
140 | 0 | auto nWidth = rRenderContext.GetTextWidth(maHorzText); |
141 | |
|
142 | 0 | auto nStart = aOffset.X() + (maPreviewSize.Width() - nWidth) / 2; |
143 | 0 | rRenderContext.DrawText(Point(nStart, aOffset.Y() - nTextHeight), maHorzText, 0, maHorzText.getLength()); |
144 | |
|
145 | 0 | DecorationView aDecoView(&rRenderContext); |
146 | 0 | auto nTop = aOffset.Y() - (nTextHeight / 2); |
147 | 0 | aDecoView.DrawSeparator(Point(aOffset.X(), nTop), Point(nStart - 2, nTop), false); |
148 | 0 | aDecoView.DrawSeparator(Point(nStart + nWidth + 2, nTop), Point(aOffset.X() + maPreviewSize.Width(), nTop), false); |
149 | 0 | } |
150 | | |
151 | | // vertical line |
152 | 0 | { |
153 | 0 | auto popIt2 = rRenderContext.ScopedPush(PushFlags::FONT); |
154 | 0 | vcl::Font aFont(rRenderContext.GetFont()); |
155 | 0 | aFont.SetOrientation(900_deg10); |
156 | 0 | rRenderContext.SetFont(aFont); |
157 | |
|
158 | 0 | auto nLeft = aOffset.X() - nTextHeight; |
159 | |
|
160 | 0 | auto nWidth = rRenderContext.GetTextWidth(maVertText); |
161 | 0 | auto nStart = aOffset.Y() + (maPreviewSize.Height() + nWidth) / 2; |
162 | |
|
163 | 0 | rRenderContext.DrawText(Point(nLeft, nStart), maVertText, 0, maVertText.getLength()); |
164 | |
|
165 | 0 | DecorationView aDecoView(&rRenderContext); |
166 | 0 | nLeft = aOffset.X() - (nTextHeight / 2); |
167 | 0 | aDecoView.DrawSeparator(Point(nLeft, aOffset.Y()), Point(nLeft, nStart - nWidth - 2), true); |
168 | 0 | aDecoView.DrawSeparator(Point(nLeft, nStart + 2), Point(nLeft, aOffset.Y() + maPreviewSize.Height()), true); |
169 | 0 | } |
170 | |
|
171 | 0 | if (!maReplacementString.isEmpty()) |
172 | 0 | { |
173 | | // replacement is active |
174 | 0 | tools::Rectangle aTextRect(aOffset + Point(2, 2), Size(maPreviewSize.Width() - 4, maPreviewSize.Height() - 4)); |
175 | 0 | rRenderContext.DrawText(aTextRect, maReplacementString, |
176 | 0 | DrawTextFlags::Center | DrawTextFlags::VCenter | |
177 | 0 | DrawTextFlags::WordBreak | DrawTextFlags::MultiLine); |
178 | 0 | } |
179 | 0 | else |
180 | 0 | { |
181 | 0 | Bitmap aPreviewBitmap(maPreviewBitmap); |
182 | | |
183 | | // This explicit force-to-scale allows us to get the |
184 | | // mentioned best quality here. Unfortunately this is |
185 | | // currently not sure when using just ::DrawBitmap with |
186 | | // a defined size or ::DrawOutDev |
187 | 0 | aPreviewBitmap.Scale(maPreviewSize, BmpScaleFlag::BestQuality); |
188 | 0 | rRenderContext.DrawBitmap(aOffset, aPreviewBitmap); |
189 | 0 | } |
190 | |
|
191 | 0 | tools::Rectangle aFrameRect(aOffset + Point(-1, -1), Size(maPreviewSize.Width() + 2, maPreviewSize.Height() + 2)); |
192 | 0 | DecorationView aDecorationView(&rRenderContext); |
193 | 0 | aDecorationView.DrawFrame(aFrameRect, DrawFrameStyle::Group); |
194 | 0 | } |
195 | | |
196 | | bool PrintDialog::PrintPreviewWindow::Command( const CommandEvent& rEvt ) |
197 | 0 | { |
198 | 0 | if( rEvt.GetCommand() == CommandEventId::Wheel ) |
199 | 0 | { |
200 | 0 | const CommandWheelData* pWheelData = rEvt.GetWheelData(); |
201 | 0 | if(pWheelData->GetDelta() > 0) |
202 | 0 | mpDialog->previewBackward(); |
203 | 0 | else if (pWheelData->GetDelta() < 0) |
204 | 0 | mpDialog->previewForward(); |
205 | 0 | return true; |
206 | 0 | } |
207 | 0 | return CustomWidgetController::Command(rEvt); |
208 | 0 | } |
209 | | |
210 | | void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPreview, |
211 | | const Size& i_rOrigSize, |
212 | | std::u16string_view i_rPaperName, |
213 | | const OUString& i_rReplacement, |
214 | | sal_Int32 i_nDPIX, |
215 | | sal_Int32 i_nDPIY, |
216 | | bool i_bGreyscale |
217 | | ) |
218 | 0 | { |
219 | 0 | maMtf = i_rNewPreview; |
220 | 0 | mnDPIX = i_nDPIX; |
221 | 0 | mnDPIY = i_nDPIY; |
222 | 0 | maOrigSize = i_rOrigSize; |
223 | 0 | maReplacementString = i_rReplacement; |
224 | 0 | mbGreyscale = i_bGreyscale; |
225 | | |
226 | | // use correct measurements |
227 | 0 | const LocaleDataWrapper& rLocWrap(Application::GetSettings().GetLocaleDataWrapper()); |
228 | 0 | o3tl::Length eUnit = o3tl::Length::mm; |
229 | 0 | int nDigits = 0; |
230 | 0 | if( rLocWrap.getMeasurementSystemEnum() == MeasurementSystem::US ) |
231 | 0 | { |
232 | 0 | eUnit = o3tl::Length::in100; |
233 | 0 | nDigits = 2; |
234 | 0 | } |
235 | 0 | Size aLogicPaperSize(o3tl::convert(i_rOrigSize, o3tl::Length::mm100, eUnit)); |
236 | 0 | OUString aNumText( rLocWrap.getNum( aLogicPaperSize.Width(), nDigits ) ); |
237 | 0 | OUStringBuffer aBuf( aNumText + " " ); |
238 | 0 | aBuf.appendAscii( eUnit == o3tl::Length::mm ? "mm" : "in" ); |
239 | 0 | if( !i_rPaperName.empty() ) |
240 | 0 | { |
241 | 0 | aBuf.append( OUString::Concat(" (") + i_rPaperName + ")" ); |
242 | 0 | } |
243 | 0 | maHorzText = aBuf.makeStringAndClear(); |
244 | |
|
245 | 0 | aNumText = rLocWrap.getNum( aLogicPaperSize.Height(), nDigits ); |
246 | 0 | aBuf.append( aNumText + " " ); |
247 | 0 | aBuf.appendAscii( eUnit == o3tl::Length::mm ? "mm" : "in" ); |
248 | 0 | maVertText = aBuf.makeStringAndClear(); |
249 | | |
250 | | // We have a new Metafile and evtl. a new page, so we need to reset |
251 | | // the PreviewBitmap to force new creation |
252 | 0 | maPreviewBitmap = Bitmap(); |
253 | | |
254 | | // sets/calculates e.g. maPreviewSize |
255 | | // also triggers preparePreviewBitmap() |
256 | 0 | Resize(); |
257 | |
|
258 | 0 | Invalidate(); |
259 | 0 | } |
260 | | |
261 | | void PrintDialog::PrintPreviewWindow::preparePreviewBitmap() |
262 | 0 | { |
263 | 0 | if(maPreviewSize.IsEmpty()) |
264 | 0 | { |
265 | | // not yet fully initialized, no need to prepare anything |
266 | 0 | return; |
267 | 0 | } |
268 | | |
269 | | // define an allowed number of pixels, also see |
270 | | // defaults for primitive renderers and similar. This |
271 | | // might be centralized and made dependent of 32/64bit |
272 | 0 | const sal_uInt32 nMaxSquarePixels(500000); |
273 | | |
274 | | // check how big (squarePixels) the preview is currently (with |
275 | | // max value of MaxSquarePixels) |
276 | 0 | const sal_uInt32 nCurrentSquarePixels( |
277 | 0 | std::min( |
278 | 0 | nMaxSquarePixels, |
279 | 0 | static_cast<sal_uInt32>(maPreviewBitmap.GetSizePixel().getWidth()) |
280 | 0 | * static_cast<sal_uInt32>(maPreviewBitmap.GetSizePixel().getHeight()))); |
281 | | |
282 | | // check how big (squarePixels) the preview needs to be (with |
283 | | // max value of MaxSquarePixels) |
284 | 0 | const sal_uInt32 nRequiredSquarePixels( |
285 | 0 | std::min( |
286 | 0 | nMaxSquarePixels, |
287 | 0 | static_cast<sal_uInt32>(maPreviewSize.getWidth()) |
288 | 0 | * static_cast<sal_uInt32>(maPreviewSize.getHeight()))); |
289 | | |
290 | | // check if preview is big enough. Use a scaling value in |
291 | | // the comparison to not get bigger at the last possible moment |
292 | | // what may look awkward and pixelated (again). This means |
293 | | // to use a percentage value - if we have at least |
294 | | // that value of required pixels, we are good. |
295 | 0 | static const double fPreventAwkwardFactor(1.35); // 35% |
296 | 0 | if(nCurrentSquarePixels >= static_cast<sal_uInt32>(nRequiredSquarePixels * fPreventAwkwardFactor)) |
297 | 0 | { |
298 | | // at this place we also could add a mechanism to let the preview |
299 | | // bitmap 'shrink' again if it is currently 'too big' -> bigger |
300 | | // than required. I think this is not necessary for now. |
301 | | |
302 | | // already sufficient, done. |
303 | 0 | return; |
304 | 0 | } |
305 | | |
306 | | // check if we have enough square pixels e.g for 8x8 pixels |
307 | 0 | if(nRequiredSquarePixels < 64) |
308 | 0 | { |
309 | | // too small preview - let it empty |
310 | 0 | return; |
311 | 0 | } |
312 | | |
313 | | // Calculate nPlannedSquarePixels which is the required size |
314 | | // expanded by a percentage (with max value of MaxSquarePixels) |
315 | 0 | static const double fExtraSpaceFactor(1.65); // 65% |
316 | 0 | const sal_uInt32 nPlannedSquarePixels( |
317 | 0 | std::min( |
318 | 0 | nMaxSquarePixels, |
319 | 0 | static_cast<sal_uInt32>(maPreviewSize.getWidth() * fExtraSpaceFactor) |
320 | 0 | * static_cast<sal_uInt32>(maPreviewSize.getHeight() * fExtraSpaceFactor))); |
321 | | |
322 | | // calculate back new width and height - it might have been |
323 | | // truncated by MaxSquarePixels. |
324 | | // We know that w*h == nPlannedSquarePixels and w/h == ratio |
325 | 0 | const double fRatio(static_cast<double>(maPreviewSize.getWidth()) / static_cast<double>(maPreviewSize.getHeight())); |
326 | 0 | const double fNewWidth(sqrt(static_cast<double>(nPlannedSquarePixels) * fRatio)); |
327 | 0 | const double fNewHeight(sqrt(static_cast<double>(nPlannedSquarePixels) / fRatio)); |
328 | 0 | const Size aScaledSize(basegfx::fround<tools::Long>(fNewWidth), basegfx::fround<tools::Long>(fNewHeight)); |
329 | | |
330 | | // check if this eventual maximum is already reached |
331 | | // due to having hit the MaxSquarePixels. Due to using |
332 | | // an integer AspectRatio, we cannot make a numeric exact |
333 | | // comparison - we need to compare if we are close |
334 | 0 | const double fScaledSizeSquare(static_cast<double>(aScaledSize.getWidth() * aScaledSize.getHeight())); |
335 | 0 | const double fPreviewSizeSquare(static_cast<double>(maPreviewBitmap.GetSizePixel().getWidth() * maPreviewBitmap.GetSizePixel().getHeight())); |
336 | | |
337 | | // test as equal up to 0.1% (0.001) |
338 | 0 | if(fPreviewSizeSquare != 0.0 && fabs((fScaledSizeSquare / fPreviewSizeSquare) - 1.0) < 0.001) |
339 | 0 | { |
340 | | // maximum is reached, avoid bigger scaling |
341 | 0 | return; |
342 | 0 | } |
343 | | |
344 | | // create temporary VDev with requested Size and DPI. |
345 | | // CAUTION: DPI *is* important here - it DIFFERS from 75x75, usually 600x600 is used |
346 | 0 | ScopedVclPtrInstance<VirtualDevice> pPrerenderVDev(*Application::GetDefaultDevice()); |
347 | 0 | pPrerenderVDev->SetOutputSizePixel(aScaledSize, false); |
348 | 0 | pPrerenderVDev->SetReferenceDevice( mnDPIX, mnDPIY ); |
349 | | |
350 | | // calculate needed Scale for Metafile (using Size and DPI from VDev) |
351 | 0 | Size aLogicSize( pPrerenderVDev->PixelToLogic( pPrerenderVDev->GetOutputSizePixel(), MapMode( MapUnit::Map100thMM ) ) ); |
352 | 0 | Size aOrigSize( maOrigSize ); |
353 | 0 | if( aOrigSize.Width() < 1 ) |
354 | 0 | aOrigSize.setWidth( aLogicSize.Width() ); |
355 | 0 | if( aOrigSize.Height() < 1 ) |
356 | 0 | aOrigSize.setHeight( aLogicSize.Height() ); |
357 | 0 | double fScale = double(aLogicSize.Width())/double(aOrigSize.Width()); |
358 | | |
359 | | // tdf#141761 |
360 | | // The display quality of the Preview is pretty ugly when |
361 | | // FormControls are used. I made a deep-dive why this happens, |
362 | | // and in principle the reason is the Metafile::Scale used |
363 | | // below. Since Metafile actions are integer, that floating point |
364 | | // scale leads to rounding errors that make the lines painting |
365 | | // the FormControls disappear in the surrounding ClipRegions. |
366 | | // That Scale cannot be avoided since the Metafile contains its |
367 | | // own SetMapMode commands which *will* be executed on ::Play, |
368 | | // so the ::Scale is the only possibility for Metafile currently: |
369 | | // Giving a Size as parameter in ::Play will *not* work due to |
370 | | // the relativeMapMode that gets created will fail on |
371 | | // ::SetMapMode actions in the Metafile - and FormControls DO |
372 | | // use ::SetMapMode(MapPixel). |
373 | | // This can only be solved better in the future using Primitives |
374 | | // which would allow any scale by embedding to a Transformation, |
375 | | // but that would be a bigger rework. |
376 | | // Until then, use this little 'trick' to improve quality. |
377 | | // It uses the fact to empirically having tested that the quality |
378 | | // gets really bad for FormControls starting by a scale factor |
379 | | // smaller than 0.2 - that makes the ClipRegion overlap start. |
380 | | // So - for now - try not to go below that. |
381 | 0 | static const double fMinimumScale(0.2); |
382 | 0 | double fFactor(0.0); |
383 | 0 | if(fScale < fMinimumScale) |
384 | 0 | { |
385 | 0 | fFactor = fMinimumScale / fScale; |
386 | 0 | fScale = fMinimumScale; |
387 | |
|
388 | 0 | double fWidth(aScaledSize.getWidth() * fFactor); |
389 | 0 | double fHeight(aScaledSize.getHeight() * fFactor); |
390 | 0 | const double fNewNeededPixels(fWidth * fHeight); |
391 | | |
392 | | // to not risk using too big bitmaps and running into |
393 | | // memory problems, still limit to a useful factor is |
394 | | // necessary, also empirically estimated to |
395 | | // avoid the quality from collapsing (using a direct |
396 | | // in-between, ceil'd result) |
397 | 0 | static const double fMaximumQualitySquare(1396221.0); |
398 | |
|
399 | 0 | if(fNewNeededPixels > fMaximumQualitySquare) |
400 | 0 | { |
401 | 0 | const double fCorrection(fMaximumQualitySquare/fNewNeededPixels); |
402 | 0 | fWidth *= fCorrection; |
403 | 0 | fHeight *= fCorrection; |
404 | 0 | fScale *= fCorrection; |
405 | 0 | } |
406 | |
|
407 | 0 | const Size aScaledSize2(basegfx::fround<tools::Long>(fWidth), basegfx::fround<tools::Long>(fHeight)); |
408 | 0 | pPrerenderVDev->SetOutputSizePixel(aScaledSize2, false); |
409 | 0 | aLogicSize = pPrerenderVDev->PixelToLogic( aScaledSize2, MapMode( MapUnit::Map100thMM ) ); |
410 | 0 | } |
411 | |
|
412 | 0 | pPrerenderVDev->EnableOutput(); |
413 | 0 | pPrerenderVDev->SetBackground( Wallpaper(COL_WHITE) ); |
414 | 0 | pPrerenderVDev->Erase(); |
415 | 0 | pPrerenderVDev->SetMapMode(MapMode(MapUnit::Map100thMM)); |
416 | 0 | if( mbGreyscale ) |
417 | 0 | pPrerenderVDev->SetDrawMode( pPrerenderVDev->GetDrawMode() | |
418 | 0 | ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText | |
419 | 0 | DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) ); |
420 | | |
421 | | // Copy, Scale and Paint Metafile |
422 | 0 | GDIMetaFile aMtf( maMtf ); |
423 | 0 | aMtf.WindStart(); |
424 | 0 | aMtf.Scale( fScale, fScale ); |
425 | 0 | aMtf.WindStart(); |
426 | 0 | aMtf.Play(*pPrerenderVDev, Point(0, 0), aLogicSize); |
427 | |
|
428 | 0 | pPrerenderVDev->SetMapMode(MapMode(MapUnit::MapPixel)); |
429 | 0 | maPreviewBitmap = pPrerenderVDev->GetBitmap(Point(0, 0), pPrerenderVDev->GetOutputSizePixel()); |
430 | |
|
431 | 0 | if(0.0 != fFactor) |
432 | 0 | { |
433 | | // Correct to needed size, BmpScaleFlag::Interpolate is acceptable, |
434 | | // but BmpScaleFlag::BestQuality is just better. In case of time |
435 | | // constraints, change to Interpolate would be possible |
436 | 0 | maPreviewBitmap.Scale(aScaledSize, BmpScaleFlag::BestQuality); |
437 | 0 | } |
438 | 0 | } |
439 | | |
440 | | PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow() |
441 | 0 | : mnOrderMode( NupOrderType::LRTB ) |
442 | 0 | , mnRows( 1 ) |
443 | 0 | , mnColumns( 1 ) |
444 | 0 | { |
445 | 0 | } |
446 | | |
447 | | void PrintDialog::ShowNupOrderWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea) |
448 | 0 | { |
449 | 0 | Size aSize(70, 70); |
450 | 0 | pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); |
451 | 0 | CustomWidgetController::SetDrawingArea(pDrawingArea); |
452 | 0 | SetOutputSizePixel(aSize); |
453 | 0 | } |
454 | | |
455 | | void PrintDialog::ShowNupOrderWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*i_rRect*/) |
456 | 0 | { |
457 | 0 | rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel)); |
458 | 0 | rRenderContext.SetTextColor(rRenderContext.GetSettings().GetStyleSettings().GetFieldTextColor()); |
459 | 0 | rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFieldColor())); |
460 | 0 | rRenderContext.Erase(); |
461 | |
|
462 | 0 | int nPages = mnRows * mnColumns; |
463 | 0 | Font aFont(rRenderContext.GetSettings().GetStyleSettings().GetFieldFont()); |
464 | 0 | aFont.SetFontSize(Size(0, 24)); |
465 | 0 | rRenderContext.SetFont(aFont); |
466 | 0 | Size aSampleTextSize(rRenderContext.GetTextWidth(OUString::number(nPages + 1)), rRenderContext.GetTextHeight()); |
467 | 0 | Size aOutSize(GetOutputSizePixel()); |
468 | 0 | Size aSubSize(aOutSize.Width() / mnColumns, aOutSize.Height() / mnRows); |
469 | | // calculate font size: shrink the sample text so it fits |
470 | 0 | double fX = double(aSubSize.Width()) / double(aSampleTextSize.Width()); |
471 | 0 | double fY = double(aSubSize.Height()) / double(aSampleTextSize.Height()); |
472 | 0 | double fScale = (fX < fY) ? fX : fY; |
473 | 0 | tools::Long nFontHeight = tools::Long(24.0 * fScale) - 3; |
474 | 0 | if (nFontHeight < 5) |
475 | 0 | nFontHeight = 5; |
476 | 0 | aFont.SetFontSize(Size( 0, nFontHeight)); |
477 | 0 | rRenderContext.SetFont(aFont); |
478 | 0 | tools::Long nTextHeight = rRenderContext.GetTextHeight(); |
479 | 0 | for (int i = 0; i < nPages; i++) |
480 | 0 | { |
481 | 0 | OUString aPageText(OUString::number(i + 1)); |
482 | 0 | int nX = 0, nY = 0; |
483 | 0 | switch (mnOrderMode) |
484 | 0 | { |
485 | 0 | case NupOrderType::LRTB: |
486 | 0 | nX = (i % mnColumns); |
487 | 0 | nY = (i / mnColumns); |
488 | 0 | break; |
489 | 0 | case NupOrderType::TBLR: |
490 | 0 | nX = (i / mnRows); |
491 | 0 | nY = (i % mnRows); |
492 | 0 | break; |
493 | 0 | case NupOrderType::RLTB: |
494 | 0 | nX = mnColumns - 1 - (i % mnColumns); |
495 | 0 | nY = (i / mnColumns); |
496 | 0 | break; |
497 | 0 | case NupOrderType::TBRL: |
498 | 0 | nX = mnColumns - 1 - (i / mnRows); |
499 | 0 | nY = (i % mnRows); |
500 | 0 | break; |
501 | 0 | } |
502 | 0 | Size aTextSize(rRenderContext.GetTextWidth(aPageText), nTextHeight); |
503 | 0 | int nDeltaX = (aSubSize.Width() - aTextSize.Width()) / 2; |
504 | 0 | int nDeltaY = (aSubSize.Height() - aTextSize.Height()) / 2; |
505 | 0 | rRenderContext.DrawText(Point(nX * aSubSize.Width() + nDeltaX, |
506 | 0 | nY * aSubSize.Height() + nDeltaY), aPageText); |
507 | 0 | } |
508 | 0 | DecorationView aDecorationView(&rRenderContext); |
509 | 0 | aDecorationView.DrawFrame(tools::Rectangle(Point(0, 0), aOutSize), DrawFrameStyle::Group); |
510 | 0 | } |
511 | | |
512 | | Size const & PrintDialog::getJobPageSize() |
513 | 0 | { |
514 | 0 | if( maFirstPageSize.IsEmpty() ) |
515 | 0 | { |
516 | 0 | maFirstPageSize = maNupPortraitSize; |
517 | 0 | GDIMetaFile aMtf; |
518 | 0 | if( maPController->getPageCountProtected() > 0 ) |
519 | 0 | { |
520 | 0 | PrinterController::PageSize aPageSize = maPController->getPageFile( 0, aMtf, true ); |
521 | 0 | maFirstPageSize = aPageSize.aSize; |
522 | 0 | } |
523 | 0 | } |
524 | 0 | return maFirstPageSize; |
525 | 0 | } |
526 | | |
527 | | PrintDialog::PrintDialog(weld::Window* i_pWindow, std::shared_ptr<PrinterController> i_xController) |
528 | 0 | : GenericDialogController(i_pWindow, u"vcl/ui/printdialog.ui"_ustr, u"PrintDialog"_ustr) |
529 | 0 | , maPController(std::move( i_xController )) |
530 | 0 | , mxTabCtrl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr)) |
531 | 0 | , mxScrolledWindow(m_xBuilder->weld_scrolled_window(u"scrolledwindow"_ustr)) |
532 | 0 | , mxPageLayoutFrame(m_xBuilder->weld_frame(u"layoutframe"_ustr)) |
533 | 0 | , mxPrinters(m_xBuilder->weld_combo_box(u"printersbox"_ustr)) |
534 | 0 | , mxStatusTxt(m_xBuilder->weld_label(u"status"_ustr)) |
535 | 0 | , mxSetupButton(m_xBuilder->weld_button(u"setup"_ustr)) |
536 | 0 | , mxCopyCountField(m_xBuilder->weld_spin_button(u"copycount"_ustr)) |
537 | 0 | , mxCollateBox(m_xBuilder->weld_check_button(u"collate"_ustr)) |
538 | 0 | , mxCollateImage(m_xBuilder->weld_image(u"collateimage"_ustr)) |
539 | 0 | , mxPageRangeEdit(m_xBuilder->weld_entry(u"pagerange"_ustr)) |
540 | 0 | , mxPageRangesRadioButton(m_xBuilder->weld_radio_button(u"rbRangePages"_ustr)) |
541 | 0 | , mxPaperSidesBox(m_xBuilder->weld_combo_box(u"sidesbox"_ustr)) |
542 | 0 | , mxSingleJobsBox(m_xBuilder->weld_check_button(u"singlejobs"_ustr)) |
543 | 0 | , mxReverseOrderBox(m_xBuilder->weld_check_button(u"reverseorder"_ustr)) |
544 | 0 | , mxOKButton(m_xBuilder->weld_button(u"ok"_ustr)) |
545 | 0 | , mxCancelButton(m_xBuilder->weld_button(u"cancel"_ustr)) |
546 | 0 | , mxBackwardBtn(m_xBuilder->weld_button(u"backward"_ustr)) |
547 | 0 | , mxForwardBtn(m_xBuilder->weld_button(u"forward"_ustr)) |
548 | 0 | , mxFirstBtn(m_xBuilder->weld_button(u"btnFirst"_ustr)) |
549 | 0 | , mxLastBtn(m_xBuilder->weld_button(u"btnLast"_ustr)) |
550 | 0 | , mxPreviewBox(m_xBuilder->weld_check_button(u"previewbox"_ustr)) |
551 | 0 | , mxNumPagesText(m_xBuilder->weld_label(u"totalnumpages"_ustr)) |
552 | 0 | , mxPreview(new PrintPreviewWindow(this)) |
553 | 0 | , mxPreviewWindow(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, *mxPreview)) |
554 | 0 | , mxPageEdit(m_xBuilder->weld_entry(u"pageedit"_ustr)) |
555 | 0 | , mxPagesBtn(m_xBuilder->weld_radio_button(u"pagespersheetbtn"_ustr)) |
556 | 0 | , mxBrochureBtn(m_xBuilder->weld_radio_button(u"brochure"_ustr)) |
557 | 0 | , mxPagesBoxTitleTxt(m_xBuilder->weld_label(u"pagespersheettxt"_ustr)) |
558 | 0 | , mxNupPagesBox(m_xBuilder->weld_combo_box(u"pagespersheetbox"_ustr)) |
559 | 0 | , mxNupNumPagesTxt(m_xBuilder->weld_label(u"pagestxt"_ustr)) |
560 | 0 | , mxNupColEdt(m_xBuilder->weld_spin_button(u"pagecols"_ustr)) |
561 | 0 | , mxNupTimesTxt(m_xBuilder->weld_label(u"by"_ustr)) |
562 | 0 | , mxNupRowsEdt(m_xBuilder->weld_spin_button(u"pagerows"_ustr)) |
563 | 0 | , mxPageMarginTxt1(m_xBuilder->weld_label(u"pagemargintxt1"_ustr)) |
564 | 0 | , mxPageMarginEdt(m_xBuilder->weld_metric_spin_button(u"pagemarginsb"_ustr, FieldUnit::MM)) |
565 | 0 | , mxPageMarginTxt2(m_xBuilder->weld_label(u"pagemargintxt2"_ustr)) |
566 | 0 | , mxSheetMarginTxt1(m_xBuilder->weld_label(u"sheetmargintxt1"_ustr)) |
567 | 0 | , mxSheetMarginEdt(m_xBuilder->weld_metric_spin_button(u"sheetmarginsb"_ustr, FieldUnit::MM)) |
568 | 0 | , mxSheetMarginTxt2(m_xBuilder->weld_label(u"sheetmargintxt2"_ustr)) |
569 | 0 | , mxPaperSizeBox(m_xBuilder->weld_combo_box(u"papersizebox"_ustr)) |
570 | 0 | , mxOrientationBox(m_xBuilder->weld_combo_box(u"pageorientationbox"_ustr)) |
571 | 0 | , mxNupOrderTxt(m_xBuilder->weld_label(u"labelorder"_ustr)) |
572 | 0 | , mxNupOrderBox(m_xBuilder->weld_combo_box(u"orderbox"_ustr)) |
573 | 0 | , mxNupOrder(new ShowNupOrderWindow) |
574 | 0 | , mxNupOrderWin(new weld::CustomWeld(*m_xBuilder, u"orderpreview"_ustr, *mxNupOrder)) |
575 | 0 | , mxBorderCB(m_xBuilder->weld_check_button(u"bordercb"_ustr)) |
576 | 0 | , mxRangeExpander(m_xBuilder->weld_expander(u"exRangeExpander"_ustr)) |
577 | 0 | , mxLayoutExpander(m_xBuilder->weld_expander(u"exLayoutExpander"_ustr)) |
578 | 0 | , mxCustom(m_xBuilder->weld_widget(u"customcontents"_ustr)) |
579 | 0 | , maPrintToFileText( VclResId( SV_PRINT_TOFILE_TXT ) ) |
580 | 0 | , maDefPrtText( VclResId( SV_PRINT_DEFPRT_TXT ) ) |
581 | 0 | , maNoPageStr( VclResId( SV_PRINT_NOPAGES ) ) |
582 | 0 | , maNoPreviewStr( VclResId( SV_PRINT_NOPREVIEW ) ) |
583 | 0 | , mnInitialPage( 0 ) |
584 | 0 | , mnCurPage( 0 ) |
585 | 0 | , mnCachedPages( 0 ) |
586 | 0 | , mbShowLayoutFrame( true ) |
587 | 0 | , mbHasCustomPaperEntry( false ) |
588 | 0 | , maUpdatePreviewIdle("Print Dialog Update Preview Idle") |
589 | 0 | , maPageRangeUpdateTimer("PageRangeUpdateTimer") |
590 | 0 | { |
591 | | // Retrieve current page, it'll be used later in updatePageRange method |
592 | 0 | PropertyValue* pPageRange = maPController->getValue(u"PageRange"_ustr); |
593 | 0 | if (pPageRange && pPageRange->Value.hasValue()) |
594 | 0 | { |
595 | 0 | OUString aPageRange; |
596 | 0 | pPageRange->Value >>= aPageRange; |
597 | 0 | mnInitialPage = aPageRange.toInt32(); |
598 | 0 | } |
599 | | |
600 | | // save printbutton text, gets exchanged occasionally with print to file |
601 | 0 | maPrintText = mxOKButton->get_label(); |
602 | |
|
603 | 0 | maPageStr = mxNumPagesText->get_label(); |
604 | |
|
605 | 0 | mxPrinters->append_text(maPrintToFileText); |
606 | | // fill printer listbox |
607 | 0 | std::vector< OUString > rQueues( Printer::GetPrinterQueues() ); |
608 | 0 | std::sort( rQueues.begin(), rQueues.end(), lcl_ListBoxCompare ); |
609 | 0 | for( const auto& rQueue : rQueues ) |
610 | 0 | { |
611 | 0 | mxPrinters->append_text(rQueue); |
612 | 0 | } |
613 | | // select current printer |
614 | 0 | if (mxPrinters->find_text(maPController->getPrinter()->GetName()) != -1) |
615 | 0 | mxPrinters->set_active_text(maPController->getPrinter()->GetName()); |
616 | 0 | else |
617 | 0 | { |
618 | | // fall back to last printer |
619 | 0 | OUString aValue( officecfg::VCL::VCLSettings::PrintDialog::LastPrinter::get() ); |
620 | 0 | if (mxPrinters->find_text(aValue) != -1) |
621 | 0 | { |
622 | 0 | mxPrinters->set_active_text(aValue); |
623 | 0 | maPController->setPrinter( VclPtrInstance<Printer>( aValue ) ); |
624 | 0 | } |
625 | 0 | else |
626 | 0 | { |
627 | | // fall back to default printer |
628 | 0 | mxPrinters->set_active_text(Printer::GetDefaultPrinterName()); |
629 | 0 | maPController->setPrinter( VclPtrInstance<Printer>( Printer::GetDefaultPrinterName() ) ); |
630 | 0 | } |
631 | 0 | } |
632 | | |
633 | | // not printing to file |
634 | 0 | maPController->resetPrinterOptions( false ); |
635 | | |
636 | | // update the text fields for the printer |
637 | 0 | updatePrinterText(); |
638 | | |
639 | | // setup dependencies |
640 | 0 | checkControlDependencies(); |
641 | | |
642 | | // setup paper sides box |
643 | 0 | setupPaperSidesBox(); |
644 | | |
645 | | // set initial focus to "Printer" |
646 | 0 | mxPrinters->grab_focus(); |
647 | | |
648 | | // setup sizes for N-Up |
649 | 0 | Size aNupSize( maPController->getPrinter()->PixelToLogic( |
650 | 0 | maPController->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) ); |
651 | 0 | if( maPController->getPrinter()->GetOrientation() == Orientation::Landscape ) |
652 | 0 | { |
653 | 0 | maNupLandscapeSize = aNupSize; |
654 | | // coverity[swapped_arguments : FALSE] - this is in the correct order |
655 | 0 | maNupPortraitSize = Size( aNupSize.Height(), aNupSize.Width() ); |
656 | 0 | } |
657 | 0 | else |
658 | 0 | { |
659 | 0 | maNupPortraitSize = aNupSize; |
660 | | // coverity[swapped_arguments : FALSE] - this is in the correct order |
661 | 0 | maNupLandscapeSize = Size( aNupSize.Height(), aNupSize.Width() ); |
662 | 0 | } |
663 | |
|
664 | 0 | maUpdatePreviewIdle.SetPriority(TaskPriority::POST_PAINT); |
665 | 0 | maUpdatePreviewIdle.SetInvokeHandler(LINK( this, PrintDialog, updatePreviewIdle)); |
666 | |
|
667 | 0 | maPageRangeUpdateTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT); |
668 | 0 | maPageRangeUpdateTimer.SetInvokeHandler(LINK(this, PrintDialog, PageRangeUpdateTimerHdl)); |
669 | | |
670 | |
|
671 | 0 | initFromMultiPageSetup( maPController->getMultipage() ); |
672 | | |
673 | | // setup optional UI options set by application |
674 | 0 | setupOptionalUI(); |
675 | | |
676 | | // hide layout frame if unwanted |
677 | 0 | mxPageLayoutFrame->set_visible(mbShowLayoutFrame); |
678 | | |
679 | | // restore settings from last run |
680 | 0 | readFromSettings(); |
681 | | |
682 | | // setup click hdl |
683 | 0 | mxOKButton->connect_clicked(LINK(this, PrintDialog, ClickOKCancelHdl)); |
684 | 0 | mxCancelButton->connect_clicked(LINK(this, PrintDialog, ClickOKCancelHdl)); |
685 | 0 | mxSetupButton->connect_clicked(LINK(this, PrintDialog, ClickSetupHdl)); |
686 | 0 | mxBackwardBtn->connect_clicked(LINK(this, PrintDialog, ClickBackwardHdl)); |
687 | 0 | mxForwardBtn->connect_clicked(LINK(this, PrintDialog, ClickForwardHdl)); |
688 | 0 | mxFirstBtn->connect_clicked(LINK(this, PrintDialog, ClickFirstHdl)); |
689 | 0 | mxLastBtn->connect_clicked(LINK(this, PrintDialog, ClickLastHdl)); |
690 | | |
691 | | // setup toggle hdl |
692 | 0 | mxReverseOrderBox->connect_toggled(LINK(this, PrintDialog, ToggleReverseOrderHdl)); |
693 | 0 | mxCollateBox->connect_toggled(LINK(this, PrintDialog, ToggleCollateHdl)); |
694 | 0 | mxSingleJobsBox->connect_toggled(LINK(this, PrintDialog, ToggleSingleJobsHdl)); |
695 | 0 | mxBrochureBtn->connect_toggled(LINK(this, PrintDialog, ToggleBrochureHdl)); |
696 | 0 | mxPreviewBox->connect_toggled(LINK(this, PrintDialog, TogglePreviewHdl)); |
697 | 0 | mxBorderCB->connect_toggled(LINK(this, PrintDialog, ToggleBorderHdl)); |
698 | | |
699 | | // setup select hdl |
700 | 0 | mxPrinters->connect_changed(LINK(this, PrintDialog, SelectPrinterHdl)); |
701 | 0 | mxPaperSidesBox->connect_changed(LINK(this, PrintDialog, SelectPaperSidesHdl)); |
702 | 0 | mxNupPagesBox->connect_changed(LINK(this, PrintDialog, SelectNupPagesHdl)); |
703 | 0 | mxOrientationBox->connect_changed(LINK(this, PrintDialog, SelectOrientationHdl)); |
704 | 0 | mxNupOrderBox->connect_changed(LINK(this, PrintDialog, SelectNupOrderHdl)); |
705 | 0 | mxPaperSizeBox->connect_changed(LINK(this, PrintDialog, SelectPaperSizeHdl)); |
706 | | |
707 | | // setup modify hdl |
708 | 0 | mxPageEdit->connect_activate( LINK( this, PrintDialog, ActivateHdl ) ); |
709 | 0 | mxPageEdit->connect_focus_out( LINK( this, PrintDialog, FocusOutHdl ) ); |
710 | 0 | mxCopyCountField->connect_value_changed( LINK( this, PrintDialog, SpinModifyHdl ) ); |
711 | 0 | mxNupColEdt->connect_value_changed( LINK( this, PrintDialog, SpinModifyHdl ) ); |
712 | 0 | mxNupRowsEdt->connect_value_changed( LINK( this, PrintDialog, SpinModifyHdl ) ); |
713 | 0 | mxPageMarginEdt->connect_value_changed( LINK( this, PrintDialog, MetricSpinModifyHdl ) ); |
714 | 0 | mxSheetMarginEdt->connect_value_changed( LINK( this, PrintDialog, MetricSpinModifyHdl ) ); |
715 | |
|
716 | 0 | updateNupFromPages(); |
717 | | |
718 | | // tdf#129180 Delay setting the default value in the Paper Size list |
719 | | // set paper sizes listbox |
720 | 0 | setPaperSizes(); |
721 | | // Sync selected paper size with the controller for preview. |
722 | 0 | if (mxPaperSizeBox->get_sensitive() && mxPaperSizeBox->get_active() != -1) |
723 | 0 | SelectPaperSizeHdl(*mxPaperSizeBox); |
724 | |
|
725 | 0 | mxRangeExpander->set_expanded( |
726 | 0 | officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::get()); |
727 | 0 | mxLayoutExpander->set_expanded( |
728 | 0 | officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::get()); |
729 | | |
730 | | // lock the dialog height, regardless of later expander state |
731 | 0 | mxScrolledWindow->set_size_request( |
732 | 0 | mxScrolledWindow->get_preferred_size().Width() + mxScrolledWindow->get_scroll_thickness(), |
733 | 0 | 450); |
734 | |
|
735 | 0 | m_xDialog->set_centered_on_parent(true); |
736 | 0 | } |
737 | | |
738 | | void PrintDialog::ImplDestroy() |
739 | 0 | { |
740 | 0 | std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); |
741 | 0 | officecfg::Office::Common::Print::Dialog::RangeSectionExpanded::set(mxRangeExpander->get_expanded(), batch); |
742 | 0 | officecfg::Office::Common::Print::Dialog::LayoutSectionExpanded::set(mxLayoutExpander->get_expanded(), batch); |
743 | 0 | batch->commit(); |
744 | 0 | } |
745 | | |
746 | | PrintDialog::~PrintDialog() |
747 | 0 | { |
748 | 0 | suppress_fun_call_w_exception(ImplDestroy()); |
749 | 0 | } |
750 | | |
751 | | void PrintDialog::setupPaperSidesBox() |
752 | 0 | { |
753 | 0 | DuplexMode eDuplex = maPController->getPrinter()->GetDuplexMode(); |
754 | |
|
755 | 0 | if ( eDuplex == DuplexMode::Unknown || isPrintToFile() ) |
756 | 0 | { |
757 | 0 | mxPaperSidesBox->set_active( 0 ); |
758 | 0 | mxPaperSidesBox->set_sensitive( false ); |
759 | 0 | } |
760 | 0 | else |
761 | 0 | { |
762 | 0 | mxPaperSidesBox->set_active( static_cast<sal_Int32>(eDuplex) - 1 ); |
763 | 0 | mxPaperSidesBox->set_sensitive( true ); |
764 | 0 | } |
765 | 0 | } |
766 | | |
767 | | void PrintDialog::storeToSettings() |
768 | 0 | { |
769 | 0 | std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); |
770 | |
|
771 | 0 | officecfg::VCL::VCLSettings::PrintDialog::LastPrinter::set( |
772 | 0 | isPrintToFile() ? Printer::GetDefaultPrinterName() |
773 | 0 | : mxPrinters->get_active_text(), batch ); |
774 | |
|
775 | 0 | officecfg::VCL::VCLSettings::PrintDialog::LastPage::set( |
776 | 0 | mxTabCtrl->get_tab_label_text(mxTabCtrl->get_current_page_ident()), batch); |
777 | |
|
778 | 0 | officecfg::VCL::VCLSettings::PrintDialog::WindowState::set( |
779 | 0 | m_xDialog->get_window_state(vcl::WindowDataMask::All).toStr(), batch); |
780 | |
|
781 | 0 | officecfg::VCL::VCLSettings::PrintDialog::Collate::set( mxCollateBox->get_active(), batch ); |
782 | |
|
783 | 0 | officecfg::VCL::VCLSettings::PrintDialog::CollateSingleJobs::set( |
784 | 0 | mxSingleJobsBox->get_active(), batch ); |
785 | |
|
786 | 0 | officecfg::VCL::VCLSettings::PrintDialog::HasPreview::set( hasPreview(), batch); |
787 | |
|
788 | 0 | batch->commit(); |
789 | 0 | } |
790 | | |
791 | | void PrintDialog::readFromSettings() |
792 | 0 | { |
793 | | // read last selected tab page; if it exists, activate it |
794 | 0 | OUString aValue = officecfg::VCL::VCLSettings::PrintDialog::LastPage::get(); |
795 | 0 | sal_uInt16 nCount = mxTabCtrl->get_n_pages(); |
796 | 0 | for (sal_uInt16 i = 0; i < nCount; ++i) |
797 | 0 | { |
798 | 0 | OUString sPageId = mxTabCtrl->get_page_ident(i); |
799 | 0 | if (aValue == mxTabCtrl->get_tab_label_text(sPageId)) |
800 | 0 | { |
801 | 0 | mxTabCtrl->set_current_page(sPageId); |
802 | 0 | break; |
803 | 0 | } |
804 | 0 | } |
805 | | |
806 | | // persistent window state |
807 | 0 | aValue = officecfg::VCL::VCLSettings::PrintDialog::WindowState::get(); |
808 | 0 | if (!aValue.isEmpty()) |
809 | 0 | m_xDialog->set_window_state(vcl::WindowData(aValue)); |
810 | | |
811 | | // collate |
812 | 0 | mxCollateBox->set_sensitive( officecfg::VCL::VCLSettings::PrintDialog::Collate::isReadOnly() ); |
813 | 0 | mxCollateBox->set_active( officecfg::VCL::VCLSettings::PrintDialog::Collate::get() ); |
814 | | |
815 | | // collate single jobs |
816 | 0 | mxSingleJobsBox->set_active( officecfg::VCL::VCLSettings::PrintDialog::CollateSingleJobs::get() ); |
817 | | |
818 | | // preview box |
819 | 0 | mxPreviewBox->set_active( officecfg::VCL::VCLSettings::PrintDialog::HasPreview::get() ); |
820 | |
|
821 | 0 | } |
822 | | |
823 | | void PrintDialog::setPaperSizes() |
824 | 0 | { |
825 | 0 | mxPaperSizeBox->clear(); |
826 | 0 | mxPaperSizeBox->set_active(-1); |
827 | 0 | mbHasCustomPaperEntry = false; |
828 | |
|
829 | 0 | VclPtr<Printer> aPrt( maPController->getPrinter() ); |
830 | 0 | mePaper = aPrt->GetPaper(); |
831 | | |
832 | | // Related: tdf#159995 allow setting the page size when printing to file |
833 | | // On macOS, printing to file just saves to PDF using a native print |
834 | | // job just like the native print dialog's PDF > Save as PDF... option. |
835 | | // Also, as noted in tdf#163558, the native print dialog could support |
836 | | // changing the page size eventually (and already does in Apple's |
837 | | // Safari and TextEdit applications) so allow changing of the page |
838 | | // size in the non-native print dialog on macOS as well. |
839 | 0 | #ifndef MACOSX |
840 | 0 | if ( isPrintToFile() ) |
841 | 0 | { |
842 | 0 | mxPaperSizeBox->set_sensitive( false ); |
843 | 0 | } |
844 | 0 | else |
845 | 0 | #endif |
846 | 0 | { |
847 | 0 | int nExactMatch = -1; |
848 | 0 | int nExactRotatedMatch = -1; |
849 | 0 | int nSizeMatch = -1; |
850 | 0 | int nRotatedSizeMatch = -1; |
851 | 0 | Size aSizeOfPaper = aPrt->GetSizeOfPaper(); |
852 | 0 | PaperInfo aPaperInfo(aSizeOfPaper.getWidth(), aSizeOfPaper.getHeight()); |
853 | | // coverity[swapped_arguments : FALSE] - this is in the correct order |
854 | 0 | PaperInfo aRotatedPaperInfo(aSizeOfPaper.getHeight(), aSizeOfPaper.getWidth()); |
855 | 0 | const LocaleDataWrapper& rLocWrap(Application::GetSettings().GetLocaleDataWrapper()); |
856 | 0 | o3tl::Length eUnit = o3tl::Length::mm; |
857 | 0 | int nDigits = 0; |
858 | 0 | if( rLocWrap.getMeasurementSystemEnum() == MeasurementSystem::US ) |
859 | 0 | { |
860 | 0 | eUnit = o3tl::Length::in100; |
861 | 0 | nDigits = 2; |
862 | 0 | } |
863 | | |
864 | | // Also match by document page dimensions, not just Paper enum |
865 | | // (e.g. a card printer whose paper has no matching enum). |
866 | 0 | Size aDocSize = getJobPageSize(); |
867 | 0 | PaperInfo aDocPaperInfo(aDocSize.getWidth(), aDocSize.getHeight()); |
868 | 0 | PaperInfo aDocRotatedInfo(aDocSize.getHeight(), aDocSize.getWidth()); |
869 | 0 | int nDocDimMatch = -1; |
870 | 0 | int nDocDimRotatedMatch = -1; |
871 | |
|
872 | 0 | for (int nPaper = 0; nPaper < aPrt->GetPaperInfoCount(); nPaper++) |
873 | 0 | { |
874 | 0 | PaperInfo aInfo = aPrt->GetPaperInfo( nPaper ); |
875 | 0 | aInfo.doSloppyFit(true); |
876 | 0 | Paper ePaper = aInfo.getPaper(); |
877 | | |
878 | | // Use PaperInfo directly (1/100th mm); GetPaperSize() uses |
879 | | // PixelToLogic which can return wrong values. |
880 | 0 | Size aSize(aInfo.getWidth(), aInfo.getHeight()); |
881 | 0 | Size aLogicPaperSize( o3tl::convert(aSize, o3tl::Length::mm100, eUnit) ); |
882 | |
|
883 | 0 | OUString aWidth( rLocWrap.getNum( aLogicPaperSize.Width(), nDigits ) ); |
884 | 0 | OUString aHeight( rLocWrap.getNum( aLogicPaperSize.Height(), nDigits ) ); |
885 | 0 | OUString aUnit = eUnit == o3tl::Length::mm ? u"mm"_ustr : u"in"_ustr; |
886 | 0 | OUString aPaperName; |
887 | | |
888 | | // Paper sizes that we don't know of but the system printer driver lists are not "User |
889 | | // Defined". Displaying them as such is just confusing. |
890 | 0 | if (ePaper != PAPER_USER) |
891 | 0 | aPaperName = Printer::GetPaperName( ePaper ) + " "; |
892 | |
|
893 | 0 | aPaperName += aWidth + aUnit + " x " + aHeight + aUnit; |
894 | |
|
895 | 0 | mxPaperSizeBox->append_text(aPaperName); |
896 | | |
897 | | // For exact match, check that paper orientation also matches |
898 | 0 | if (ePaper != PAPER_USER && ePaper == mePaper) |
899 | 0 | { |
900 | | // Only get the first match, in case there are multiple papers with the same size |
901 | 0 | if (nExactMatch == -1 && aInfo.sloppyEqual(aPaperInfo)) |
902 | 0 | nExactMatch = nPaper; |
903 | 0 | else if (nExactRotatedMatch == -1 && aInfo.sloppyEqual(aRotatedPaperInfo)) |
904 | 0 | nExactRotatedMatch = nPaper; |
905 | 0 | } |
906 | |
|
907 | 0 | if (ePaper == PAPER_USER && aInfo.sloppyEqual(aPaperInfo)) |
908 | 0 | nSizeMatch = nPaper; |
909 | |
|
910 | 0 | if (ePaper == PAPER_USER && aInfo.sloppyEqual(aRotatedPaperInfo)) |
911 | 0 | nRotatedSizeMatch = nPaper; |
912 | | |
913 | | // Match by document page dimensions |
914 | 0 | if (!aDocSize.IsEmpty()) |
915 | 0 | { |
916 | 0 | if (nDocDimMatch == -1 && aInfo.sloppyEqual(aDocPaperInfo)) |
917 | 0 | nDocDimMatch = nPaper; |
918 | 0 | if (nDocDimRotatedMatch == -1 && aInfo.sloppyEqual(aDocRotatedInfo)) |
919 | 0 | nDocDimRotatedMatch = nPaper; |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | | // Select the best match: exact enum > exact rotated > size > rotated size |
924 | 0 | if (nExactMatch != -1) |
925 | 0 | mxPaperSizeBox->set_active(nExactMatch); |
926 | 0 | else if (nExactRotatedMatch != -1) |
927 | 0 | mxPaperSizeBox->set_active(nExactRotatedMatch); |
928 | 0 | else if (nSizeMatch != -1) |
929 | 0 | mxPaperSizeBox->set_active(nSizeMatch); |
930 | 0 | else if (nRotatedSizeMatch != -1) |
931 | 0 | mxPaperSizeBox->set_active(nRotatedSizeMatch); |
932 | | |
933 | | // Override with document dimension match if enum matching failed. |
934 | 0 | if (nDocDimMatch != -1) |
935 | 0 | { |
936 | 0 | mxPaperSizeBox->set_active(nDocDimMatch); |
937 | 0 | } |
938 | 0 | else if (nDocDimRotatedMatch != -1) |
939 | 0 | { |
940 | 0 | mxPaperSizeBox->set_active(nDocDimRotatedMatch); |
941 | 0 | } |
942 | | |
943 | | // No printer paper matches — probe the driver for custom size. |
944 | | // If rejected (e.g. size below driver minimum), fall back to |
945 | | // the driver's chosen paper. |
946 | 0 | if (!aDocSize.IsEmpty() && nDocDimMatch == -1 && nDocDimRotatedMatch == -1) |
947 | 0 | { |
948 | | // Save orientation: SetPaperSizeUser forces Portrait. |
949 | 0 | Orientation eOrientBeforeProbe = aPrt->GetOrientation(); |
950 | 0 | { |
951 | 0 | auto popIt = aPrt->ScopedPush(); |
952 | 0 | aPrt->SetMapMode(MapMode(MapUnit::Map100thMM)); |
953 | 0 | aPrt->SetPaperSizeUser(aDocSize); |
954 | 0 | } |
955 | | // MapMode restored by ScopedPush; paper size persists. |
956 | 0 | Size aDriverSize = aPrt->GetSizeOfPaper(); |
957 | 0 | PaperInfo aDriverInfo(aDriverSize.getWidth(), aDriverSize.getHeight()); |
958 | 0 | aDriverInfo.doSloppyFit(true); |
959 | 0 | bool bDriverAccepted = aDriverInfo.sloppyEqual(aDocPaperInfo) |
960 | 0 | || aDriverInfo.sloppyEqual(aDocRotatedInfo); |
961 | |
|
962 | 0 | if (bDriverAccepted) |
963 | 0 | { |
964 | 0 | Size aLogicDocSize(o3tl::convert(aDocSize, o3tl::Length::mm100, eUnit)); |
965 | 0 | OUString aWidth(rLocWrap.getNum(aLogicDocSize.Width(), nDigits)); |
966 | 0 | OUString aHeight(rLocWrap.getNum(aLogicDocSize.Height(), nDigits)); |
967 | 0 | OUString aUnitStr = eUnit == o3tl::Length::mm ? u"mm"_ustr : u"in"_ustr; |
968 | |
|
969 | 0 | OUString aPaperName = Printer::GetPaperName(PAPER_USER) + " " |
970 | 0 | + aWidth + aUnitStr + " x " + aHeight + aUnitStr; |
971 | |
|
972 | 0 | mxPaperSizeBox->append_text(aPaperName); |
973 | 0 | mxPaperSizeBox->set_active(aPrt->GetPaperInfoCount()); |
974 | 0 | maCustomPaperSize = aDocSize; |
975 | 0 | mbHasCustomPaperEntry = true; |
976 | 0 | } |
977 | 0 | else |
978 | 0 | { |
979 | | // Driver rejected/clamped — fall back to driver's paper |
980 | | // and restore orientation clobbered by SetPaperSizeUser. |
981 | 0 | aPrt->SetOrientation(eOrientBeforeProbe); |
982 | 0 | mePaper = aPrt->GetPaper(); |
983 | 0 | PaperInfo aFallbackInfo(aDriverSize.getWidth(), aDriverSize.getHeight()); |
984 | 0 | PaperInfo aFallbackRotated(aDriverSize.getHeight(), aDriverSize.getWidth()); |
985 | 0 | for (int nPaper = 0; nPaper < aPrt->GetPaperInfoCount(); nPaper++) |
986 | 0 | { |
987 | 0 | PaperInfo aInfo = aPrt->GetPaperInfo(nPaper); |
988 | 0 | aInfo.doSloppyFit(true); |
989 | 0 | if (aInfo.sloppyEqual(aFallbackInfo) || aInfo.sloppyEqual(aFallbackRotated)) |
990 | 0 | { |
991 | 0 | mxPaperSizeBox->set_active(nPaper); |
992 | 0 | break; |
993 | 0 | } |
994 | 0 | } |
995 | 0 | } |
996 | 0 | } |
997 | |
|
998 | 0 | mxPaperSizeBox->set_sensitive( true ); |
999 | 0 | } |
1000 | 0 | } |
1001 | | |
1002 | | void PrintDialog::updatePrinterText() |
1003 | 0 | { |
1004 | 0 | const OUString aDefPrt( Printer::GetDefaultPrinterName() ); |
1005 | 0 | const QueueInfo* pInfo = Printer::GetQueueInfo( mxPrinters->get_active_text(), true ); |
1006 | 0 | if( pInfo ) |
1007 | 0 | { |
1008 | | // FIXME: status text |
1009 | 0 | OUString aStatus; |
1010 | 0 | if( aDefPrt == pInfo->GetPrinterName() ) |
1011 | 0 | aStatus = maDefPrtText; |
1012 | 0 | mxStatusTxt->set_label( aStatus ); |
1013 | 0 | } |
1014 | 0 | else |
1015 | 0 | { |
1016 | 0 | mxStatusTxt->set_label( OUString() ); |
1017 | 0 | } |
1018 | 0 | } |
1019 | | |
1020 | | void PrintDialog::setPreviewText() |
1021 | 0 | { |
1022 | 0 | OUString aNewText( maPageStr.replaceFirst( "%n", OUString::number( mnCachedPages ) ) ); |
1023 | 0 | mxNumPagesText->set_label( aNewText ); |
1024 | 0 | } |
1025 | | |
1026 | | void PrintDialog::schedulePreviewUpdate(bool i_bMayUseCache) |
1027 | 0 | { |
1028 | 0 | if (!i_bMayUseCache) |
1029 | 0 | mbUseCacheForPreview = false; // Disable cache once |
1030 | 0 | maUpdatePreviewIdle.Start(); |
1031 | 0 | } |
1032 | | |
1033 | | IMPL_LINK_NOARG(PrintDialog, updatePreviewIdle, Timer*, void) |
1034 | 0 | { |
1035 | | // cache is allowed, unless explicitly disabled for this update |
1036 | 0 | preparePreview(std::exchange(mbUseCacheForPreview, true)); |
1037 | 0 | } |
1038 | | |
1039 | | IMPL_LINK_NOARG(PrintDialog, PageRangeUpdateTimerHdl, Timer*, void) |
1040 | 0 | { |
1041 | 0 | schedulePreviewUpdate(false); |
1042 | 0 | } |
1043 | | |
1044 | | |
1045 | | void PrintDialog::preparePreview( bool i_bMayUseCache ) |
1046 | 0 | { |
1047 | 0 | VclPtr<Printer> aPrt( maPController->getPrinter() ); |
1048 | | // Prefer maSelectedPaperSize (stable 1/100th mm) over PixelToLogic |
1049 | | // which can return wrong values during MapMode transitions. |
1050 | 0 | Size aCurPageSize = !maSelectedPaperSize.IsEmpty() |
1051 | 0 | ? maSelectedPaperSize |
1052 | 0 | : aPrt->PixelToLogic( aPrt->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ); |
1053 | | // maSelectedPaperSize is always portrait-order; swap to landscape |
1054 | | // based on the orientation dropdown (not GetOrientation() which |
1055 | | // can be clobbered by SetPaper/SetPaperSizeUser). |
1056 | 0 | if (!maSelectedPaperSize.IsEmpty() |
1057 | 0 | && aCurPageSize.Width() < aCurPageSize.Height()) |
1058 | 0 | { |
1059 | 0 | int nOrient = mxOrientationBox->get_active(); |
1060 | 0 | bool bSwapToLandscape = false; |
1061 | 0 | if (nOrient == ORIENTATION_AUTOMATIC) |
1062 | 0 | { |
1063 | 0 | Size aDocPageSize = getJobPageSize(); |
1064 | 0 | bSwapToLandscape = !aDocPageSize.IsEmpty() |
1065 | 0 | && aDocPageSize.getWidth() > aDocPageSize.getHeight(); |
1066 | 0 | } |
1067 | 0 | else if (nOrient == ORIENTATION_LANDSCAPE) |
1068 | 0 | { |
1069 | 0 | bSwapToLandscape = true; |
1070 | 0 | } |
1071 | 0 | if (bSwapToLandscape) |
1072 | 0 | { |
1073 | | // coverity[swapped_arguments : FALSE] - this is in the correct order |
1074 | 0 | aCurPageSize = Size(aCurPageSize.Height(), aCurPageSize.Width()); |
1075 | 0 | } |
1076 | 0 | } |
1077 | | // tdf#123076 Get paper size for the preview top label |
1078 | 0 | mePaper = aPrt->GetPaper(); |
1079 | 0 | GDIMetaFile aMtf; |
1080 | | |
1081 | | // Use custom paper size for preview even if the driver rejected it |
1082 | | // (e.g. "Print to PDF" reverts DMPAPER_USER to A4). |
1083 | 0 | const bool bUseCustomPreviewSize = mbHasCustomPaperEntry |
1084 | 0 | && mxPaperSizeBox->get_active() == aPrt->GetPaperInfoCount(); |
1085 | 0 | if (bUseCustomPreviewSize) |
1086 | 0 | { |
1087 | 0 | aCurPageSize = maCustomPaperSize; |
1088 | 0 | mePaper = PAPER_USER; |
1089 | 0 | } |
1090 | | |
1091 | | // page range may have changed depending on options |
1092 | 0 | sal_Int32 nPages = maPController->getFilteredPageCount(); |
1093 | 0 | mnCachedPages = nPages; |
1094 | |
|
1095 | 0 | if (!i_bMayUseCache) |
1096 | 0 | updatePageRange(nPages); |
1097 | |
|
1098 | 0 | setPreviewText(); |
1099 | |
|
1100 | 0 | if ( !hasPreview() ) |
1101 | 0 | { |
1102 | 0 | mxPreview->setPreview( aMtf, aCurPageSize, |
1103 | 0 | Printer::GetPaperName( mePaper ), |
1104 | 0 | maNoPreviewStr, |
1105 | 0 | aPrt->GetDPIX(), aPrt->GetDPIY(), |
1106 | 0 | aPrt->GetPrinterOptions().IsConvertToGreyscales() |
1107 | 0 | ); |
1108 | |
|
1109 | 0 | mxForwardBtn->set_sensitive( false ); |
1110 | 0 | mxBackwardBtn->set_sensitive( false ); |
1111 | 0 | mxFirstBtn->set_sensitive( false ); |
1112 | 0 | mxLastBtn->set_sensitive( false ); |
1113 | |
|
1114 | 0 | mxPageEdit->set_sensitive( false ); |
1115 | |
|
1116 | 0 | return; |
1117 | 0 | } |
1118 | | |
1119 | 0 | if( mnCurPage >= nPages ) |
1120 | 0 | mnCurPage = nPages-1; |
1121 | 0 | if( mnCurPage < 0 ) |
1122 | 0 | mnCurPage = 0; |
1123 | 0 | mxPageEdit->set_text(OUString::number(mnCurPage + 1)); |
1124 | |
|
1125 | 0 | if( nPages > 0 ) |
1126 | 0 | { |
1127 | 0 | PrinterController::PageSize aPageSize = |
1128 | 0 | maPController->getFilteredPageFile( mnCurPage, aMtf, i_bMayUseCache ); |
1129 | |
|
1130 | 0 | if (!bUseCustomPreviewSize |
1131 | 0 | && mxOrientationBox->get_active() == ORIENTATION_AUTOMATIC) |
1132 | 0 | { |
1133 | | // tdf#173544: with N-up, getFilteredPageFile() has just composed |
1134 | | // the sheet and returns its size. Same condition getRealPaperSize() |
1135 | | // uses to pick the sheet. |
1136 | 0 | const PrinterController::MultiPageSetup& rMPS = maPController->getMultipage(); |
1137 | 0 | if (rMPS.nRows * rMPS.nColumns > 1 && !aPageSize.aSize.IsEmpty()) |
1138 | 0 | { |
1139 | 0 | aCurPageSize = aPageSize.aSize; |
1140 | 0 | } |
1141 | 0 | else |
1142 | 0 | { |
1143 | 0 | aCurPageSize = !maSelectedPaperSize.IsEmpty() |
1144 | 0 | ? maSelectedPaperSize |
1145 | 0 | : aPrt->PixelToLogic(aPrt->GetPaperSizePixel(), MapMode(MapUnit::Map100thMM)); |
1146 | | // Swap to landscape if document requires it. |
1147 | 0 | if (!maSelectedPaperSize.IsEmpty()) |
1148 | 0 | { |
1149 | 0 | Size aDocPageSize = getJobPageSize(); |
1150 | 0 | bool bDocLandscape = !aDocPageSize.IsEmpty() |
1151 | 0 | && aDocPageSize.getWidth() > aDocPageSize.getHeight(); |
1152 | 0 | if (bDocLandscape && aCurPageSize.Width() < aCurPageSize.Height()) |
1153 | 0 | aCurPageSize = Size(aCurPageSize.Height(), aCurPageSize.Width()); |
1154 | 0 | } |
1155 | 0 | } |
1156 | 0 | } |
1157 | |
|
1158 | 0 | if( ! aPageSize.bFullPaper ) |
1159 | 0 | { |
1160 | 0 | const MapMode aMapMode( MapUnit::Map100thMM ); |
1161 | 0 | Point aOff( aPrt->PixelToLogic( aPrt->GetPageOffsetPixel(), aMapMode ) ); |
1162 | 0 | aMtf.Move( aOff.X(), aOff.Y() ); |
1163 | 0 | } |
1164 | | // tdf#150561: page size may have changed so sync mePaper with it |
1165 | 0 | if (!bUseCustomPreviewSize) |
1166 | 0 | mePaper = aPrt->GetPaper(); |
1167 | 0 | } |
1168 | |
|
1169 | 0 | mxPreview->setPreview( aMtf, aCurPageSize, |
1170 | 0 | Printer::GetPaperName( mePaper ), |
1171 | 0 | nPages > 0 ? OUString() : maNoPageStr, |
1172 | 0 | aPrt->GetDPIX(), aPrt->GetDPIY(), |
1173 | 0 | aPrt->GetPrinterOptions().IsConvertToGreyscales() |
1174 | 0 | ); |
1175 | |
|
1176 | 0 | mxForwardBtn->set_sensitive( mnCurPage < nPages-1 ); |
1177 | 0 | mxBackwardBtn->set_sensitive( mnCurPage != 0 ); |
1178 | 0 | mxFirstBtn->set_sensitive( mnCurPage != 0 ); |
1179 | 0 | mxLastBtn->set_sensitive( mnCurPage < nPages-1 ); |
1180 | 0 | mxPageEdit->set_sensitive( nPages > 1 ); |
1181 | 0 | } |
1182 | | |
1183 | | void PrintDialog::updatePageRange(sal_Int32 nPages) |
1184 | 0 | { |
1185 | 0 | if (nPages <= 0) |
1186 | 0 | return; |
1187 | | |
1188 | 0 | PropertyValue* pContentVal = maPController->getValue(u"PrintContent"_ustr); |
1189 | 0 | sal_Int32 nContent = -1; |
1190 | 0 | if (pContentVal) |
1191 | 0 | pContentVal->Value >>= nContent; |
1192 | |
|
1193 | 0 | if (nContent == 1) |
1194 | 0 | return; // User-controlled page range |
1195 | | |
1196 | 0 | OUString sRange; |
1197 | |
|
1198 | 0 | if (nContent == 3) |
1199 | 0 | { |
1200 | | // Current page: preserve the document page selected when |
1201 | | // the print dialog was opened. |
1202 | 0 | sRange = OUString::number(mnInitialPage); |
1203 | 0 | } |
1204 | 0 | else if (nContent == 0) |
1205 | 0 | { |
1206 | | // All pages |
1207 | 0 | OUStringBuffer aBuf(32); |
1208 | 0 | aBuf.append("1"); |
1209 | 0 | if (nPages > 1) |
1210 | 0 | aBuf.append("-" + OUString::number(nPages)); |
1211 | 0 | sRange = aBuf.makeStringAndClear(); |
1212 | 0 | } |
1213 | 0 | else |
1214 | 0 | { |
1215 | 0 | return; |
1216 | 0 | } |
1217 | | |
1218 | 0 | maPController->setValue(u"PageRange"_ustr, Any(sRange)); |
1219 | 0 | } |
1220 | | |
1221 | | void PrintDialog::updatePageSize(int nOrientation) |
1222 | 0 | { |
1223 | 0 | VclPtr<Printer> aPrt(maPController->getPrinter()); |
1224 | |
|
1225 | 0 | Size aSize; |
1226 | 0 | if (mxNupPagesBox->get_active_id() == "1") |
1227 | 0 | { |
1228 | 0 | int nActive = mxPaperSizeBox->get_active(); |
1229 | | // Custom entry is beyond GetPaperInfoCount(); use stored size. |
1230 | 0 | if (mbHasCustomPaperEntry && nActive == aPrt->GetPaperInfoCount()) |
1231 | 0 | { |
1232 | 0 | aSize = maCustomPaperSize; |
1233 | 0 | } |
1234 | 0 | else if (nActive >= 0 && nActive < aPrt->GetPaperInfoCount()) |
1235 | 0 | { |
1236 | 0 | PaperInfo aInfo = aPrt->GetPaperInfo(nActive); |
1237 | 0 | aSize = Size(aInfo.getWidth(), aInfo.getHeight()); |
1238 | 0 | } |
1239 | 0 | if (aSize.IsEmpty()) |
1240 | 0 | aSize = aPrt->GetSizeOfPaper(); |
1241 | |
|
1242 | 0 | if (nOrientation != ORIENTATION_AUTOMATIC) |
1243 | 0 | { |
1244 | 0 | if ((nOrientation == ORIENTATION_PORTRAIT && aSize.Width() > aSize.Height()) |
1245 | 0 | || (nOrientation == ORIENTATION_LANDSCAPE && aSize.Width() < aSize.Height())) |
1246 | 0 | { |
1247 | | // coverity[swapped_arguments : FALSE] - this is in the intended order |
1248 | 0 | aSize = Size(aSize.Height(), aSize.Width()); |
1249 | 0 | } |
1250 | 0 | } |
1251 | 0 | } |
1252 | 0 | else |
1253 | 0 | aSize = getJobPageSize(); |
1254 | |
|
1255 | 0 | aPrt->SetPrintPageSize(aSize); |
1256 | 0 | aPrt->SetUsePrintDialogSetting(nOrientation != ORIENTATION_AUTOMATIC); |
1257 | 0 | } |
1258 | | |
1259 | | void PrintDialog::updateOrientationBox( const bool bAutomatic ) |
1260 | 0 | { |
1261 | 0 | if ( !bAutomatic ) |
1262 | 0 | { |
1263 | 0 | Orientation eOrientation = maPController->getPrinter()->GetOrientation(); |
1264 | 0 | mxOrientationBox->set_active( static_cast<sal_Int32>(eOrientation) + 1 ); |
1265 | 0 | } |
1266 | 0 | else if ( hasOrientationChanged() ) |
1267 | 0 | { |
1268 | 0 | mxOrientationBox->set_active( ORIENTATION_AUTOMATIC ); |
1269 | 0 | } |
1270 | 0 | } |
1271 | | |
1272 | | void PrintDialog::updatePaperSizeBox() |
1273 | 0 | { |
1274 | 0 | VclPtr<Printer> aPrt( maPController->getPrinter() ); |
1275 | | |
1276 | | // The custom entry lives beyond GetPaperInfoCount() and has no |
1277 | | // PaperInfo to match against, so leave it alone. |
1278 | 0 | if (mbHasCustomPaperEntry && mxPaperSizeBox->get_active() == aPrt->GetPaperInfoCount()) |
1279 | 0 | return; |
1280 | | |
1281 | 0 | mePaper = aPrt->GetPaper(); |
1282 | 0 | const Size aCurPaperSize(aPrt->GetSizeOfPaper()); |
1283 | 0 | PaperInfo aCurInfo(aCurPaperSize.getWidth(), aCurPaperSize.getHeight()); |
1284 | 0 | aCurInfo.doSloppyFit(true); |
1285 | | |
1286 | | // Dimensions first: a paper picked by document size may carry a Paper |
1287 | | // enum that matches some other entry, and matching on the enum would |
1288 | | // then select that wrong entry. |
1289 | 0 | int nMatch = -1; |
1290 | 0 | int nEnumMatch = -1; |
1291 | 0 | for (int nPaper = 0; nPaper < aPrt->GetPaperInfoCount(); nPaper++) |
1292 | 0 | { |
1293 | 0 | PaperInfo aInfo = aPrt->GetPaperInfo(nPaper); |
1294 | 0 | aInfo.doSloppyFit(true); |
1295 | |
|
1296 | 0 | if (!aCurPaperSize.IsEmpty() && aInfo.sloppyEqual(aCurInfo)) |
1297 | 0 | { |
1298 | 0 | nMatch = nPaper; |
1299 | 0 | break; |
1300 | 0 | } |
1301 | 0 | if (nEnumMatch == -1 && mePaper != PAPER_USER && aInfo.getPaper() == mePaper) |
1302 | 0 | nEnumMatch = nPaper; |
1303 | 0 | } |
1304 | |
|
1305 | 0 | if (nMatch == -1) |
1306 | 0 | nMatch = nEnumMatch; |
1307 | 0 | if (nMatch != -1) |
1308 | 0 | mxPaperSizeBox->set_active(nMatch); |
1309 | 0 | } |
1310 | | |
1311 | | bool PrintDialog::hasOrientationChanged() const |
1312 | 0 | { |
1313 | 0 | const int nOrientation = mxOrientationBox->get_active(); |
1314 | 0 | const Orientation eOrientation = maPController->getPrinter()->GetOrientation(); |
1315 | |
|
1316 | 0 | return (nOrientation == ORIENTATION_LANDSCAPE && eOrientation == Orientation::Portrait) |
1317 | 0 | || (nOrientation == ORIENTATION_PORTRAIT && eOrientation == Orientation::Landscape); |
1318 | 0 | } |
1319 | | |
1320 | | // Always use this function to set paper orientation to make sure everything behaves well |
1321 | | void PrintDialog::setPaperOrientation( Orientation eOrientation, bool fromUser ) |
1322 | 0 | { |
1323 | 0 | VclPtr<Printer> aPrt( maPController->getPrinter() ); |
1324 | 0 | aPrt->SetOrientation( eOrientation ); |
1325 | 0 | maPController->setOrientationFromUser( eOrientation, fromUser ); |
1326 | 0 | } |
1327 | | |
1328 | | void PrintDialog::checkControlDependencies() |
1329 | 0 | { |
1330 | 0 | if (mxCopyCountField->get_value() > 1) |
1331 | 0 | { |
1332 | 0 | mxCollateBox->set_sensitive( officecfg::VCL::VCLSettings::PrintDialog::Collate::isReadOnly() ); |
1333 | 0 | mxSingleJobsBox->set_sensitive( mxCollateBox->get_active() ); |
1334 | 0 | } |
1335 | 0 | else |
1336 | 0 | { |
1337 | 0 | mxCollateBox->set_sensitive( false ); |
1338 | 0 | mxSingleJobsBox->set_sensitive( false ); |
1339 | 0 | } |
1340 | |
|
1341 | 0 | OUString aImg(mxCollateBox->get_active() ? SV_PRINT_COLLATE_BMP : SV_PRINT_NOCOLLATE_BMP); |
1342 | |
|
1343 | 0 | mxCollateImage->set_from_icon_name(aImg); |
1344 | | |
1345 | | // enable setup button only for printers that can be setup |
1346 | 0 | bool bHaveSetup = maPController->getPrinter()->HasSupport( PrinterSupport::SetupDialog ); |
1347 | 0 | mxSetupButton->set_sensitive(bHaveSetup); |
1348 | 0 | } |
1349 | | |
1350 | | void PrintDialog::checkOptionalControlDependencies() |
1351 | 0 | { |
1352 | 0 | for( const auto& rEntry : maControlToPropertyMap ) |
1353 | 0 | { |
1354 | 0 | assert(rEntry.first); |
1355 | |
|
1356 | 0 | bool bShouldbeEnabled = maPController->isUIOptionEnabled( rEntry.second ); |
1357 | |
|
1358 | 0 | if (bShouldbeEnabled && dynamic_cast<weld::RadioButton*>(rEntry.first)) |
1359 | 0 | { |
1360 | 0 | auto r_it = maControlToNumValMap.find( rEntry.first ); |
1361 | 0 | if( r_it != maControlToNumValMap.end() ) |
1362 | 0 | { |
1363 | 0 | bShouldbeEnabled = maPController->isUIChoiceEnabled( rEntry.second, r_it->second ); |
1364 | 0 | } |
1365 | 0 | } |
1366 | |
|
1367 | 0 | bool bIsEnabled = rEntry.first->get_sensitive(); |
1368 | | // Enable does not do a change check first, so can be less cheap than expected |
1369 | 0 | if (bShouldbeEnabled != bIsEnabled) |
1370 | 0 | rEntry.first->set_sensitive( bShouldbeEnabled ); |
1371 | 0 | } |
1372 | 0 | } |
1373 | | |
1374 | | void PrintDialog::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& i_rMPS ) |
1375 | 0 | { |
1376 | 0 | mxNupOrderWin->show(); |
1377 | 0 | mxPagesBtn->set_active(true); |
1378 | 0 | mxBrochureBtn->hide(); |
1379 | | |
1380 | | // setup field units for metric fields |
1381 | 0 | const LocaleDataWrapper& rLocWrap(Application::GetSettings().GetLocaleDataWrapper()); |
1382 | 0 | FieldUnit eUnit = FieldUnit::MM; |
1383 | 0 | sal_uInt16 nDigits = 0; |
1384 | 0 | if( rLocWrap.getMeasurementSystemEnum() == MeasurementSystem::US ) |
1385 | 0 | { |
1386 | 0 | eUnit = FieldUnit::INCH; |
1387 | 0 | nDigits = 2; |
1388 | 0 | } |
1389 | | // set units |
1390 | 0 | mxPageMarginEdt->set_unit( eUnit ); |
1391 | 0 | mxSheetMarginEdt->set_unit( eUnit ); |
1392 | | |
1393 | | // set precision |
1394 | 0 | mxPageMarginEdt->set_digits( nDigits ); |
1395 | 0 | mxSheetMarginEdt->set_digits( nDigits ); |
1396 | |
|
1397 | 0 | mxSheetMarginEdt->set_value( mxSheetMarginEdt->normalize( i_rMPS.nLeftMargin ), FieldUnit::MM_100TH ); |
1398 | 0 | mxPageMarginEdt->set_value( mxPageMarginEdt->normalize( i_rMPS.nHorizontalSpacing ), FieldUnit::MM_100TH ); |
1399 | 0 | mxBorderCB->set_active( i_rMPS.bDrawBorder ); |
1400 | 0 | mxNupRowsEdt->set_value( i_rMPS.nRows ); |
1401 | 0 | mxNupColEdt->set_value( i_rMPS.nColumns ); |
1402 | 0 | mxNupOrderBox->set_active( static_cast<sal_Int32>(i_rMPS.nOrder) ); |
1403 | 0 | if( i_rMPS.nRows != 1 || i_rMPS.nColumns != 1 ) |
1404 | 0 | { |
1405 | 0 | mxNupPagesBox->set_active( mxNupPagesBox->get_count()-1 ); |
1406 | 0 | showAdvancedControls( true ); |
1407 | 0 | mxNupOrder->setValues( i_rMPS.nOrder, i_rMPS.nColumns, i_rMPS.nRows ); |
1408 | 0 | } |
1409 | 0 | } |
1410 | | |
1411 | | void PrintDialog::updateNup( bool i_bMayUseCache ) |
1412 | 0 | { |
1413 | 0 | int nRows = mxNupRowsEdt->get_value(); |
1414 | 0 | int nCols = mxNupColEdt->get_value(); |
1415 | 0 | tools::Long nPageMargin = mxPageMarginEdt->denormalize(mxPageMarginEdt->get_value( FieldUnit::MM_100TH )); |
1416 | 0 | tools::Long nSheetMargin = mxSheetMarginEdt->denormalize(mxSheetMarginEdt->get_value( FieldUnit::MM_100TH )); |
1417 | |
|
1418 | 0 | PrinterController::MultiPageSetup aMPS; |
1419 | 0 | aMPS.nRows = nRows; |
1420 | 0 | aMPS.nColumns = nCols; |
1421 | 0 | aMPS.nLeftMargin = |
1422 | 0 | aMPS.nTopMargin = |
1423 | 0 | aMPS.nRightMargin = |
1424 | 0 | aMPS.nBottomMargin = nSheetMargin; |
1425 | |
|
1426 | 0 | aMPS.nHorizontalSpacing = |
1427 | 0 | aMPS.nVerticalSpacing = nPageMargin; |
1428 | |
|
1429 | 0 | aMPS.bDrawBorder = mxBorderCB->get_active(); |
1430 | |
|
1431 | 0 | aMPS.nOrder = static_cast<NupOrderType>(mxNupOrderBox->get_active()); |
1432 | |
|
1433 | 0 | int nOrientationMode = mxOrientationBox->get_active(); |
1434 | 0 | if( nOrientationMode == ORIENTATION_LANDSCAPE ) |
1435 | 0 | aMPS.aPaperSize = maNupLandscapeSize; |
1436 | 0 | else if( nOrientationMode == ORIENTATION_PORTRAIT ) |
1437 | 0 | aMPS.aPaperSize = maNupPortraitSize; |
1438 | 0 | else // automatic mode |
1439 | 0 | { |
1440 | | // get size of first real page to see if it is portrait or landscape |
1441 | | // we assume same page sizes for all the pages for this |
1442 | 0 | Size aPageSize = getJobPageSize(); |
1443 | |
|
1444 | 0 | Size aMultiSize( aPageSize.Width() * nCols, aPageSize.Height() * nRows ); |
1445 | 0 | if( aMultiSize.Width() > aMultiSize.Height() ) // fits better on landscape |
1446 | 0 | { |
1447 | 0 | aMPS.aPaperSize = maNupLandscapeSize; |
1448 | 0 | setPaperOrientation( Orientation::Landscape, false ); |
1449 | 0 | } |
1450 | 0 | else |
1451 | 0 | { |
1452 | 0 | aMPS.aPaperSize = maNupPortraitSize; |
1453 | 0 | setPaperOrientation( Orientation::Portrait, false ); |
1454 | 0 | } |
1455 | 0 | } |
1456 | |
|
1457 | 0 | maPController->setMultipage( aMPS ); |
1458 | |
|
1459 | 0 | mxNupOrder->setValues( aMPS.nOrder, nCols, nRows ); |
1460 | |
|
1461 | 0 | schedulePreviewUpdate(i_bMayUseCache); |
1462 | 0 | } |
1463 | | |
1464 | | void PrintDialog::updateNupFromPages( bool i_bMayUseCache ) |
1465 | 0 | { |
1466 | 0 | int nPages = mxNupPagesBox->get_active_id().toInt32(); |
1467 | 0 | int nRows = mxNupRowsEdt->get_value(); |
1468 | 0 | int nCols = mxNupColEdt->get_value(); |
1469 | 0 | tools::Long nPageMargin = mxPageMarginEdt->denormalize(mxPageMarginEdt->get_value( FieldUnit::MM_100TH )); |
1470 | 0 | tools::Long nSheetMargin = mxSheetMarginEdt->denormalize(mxSheetMarginEdt->get_value( FieldUnit::MM_100TH )); |
1471 | 0 | bool bCustom = false; |
1472 | |
|
1473 | 0 | if( nPages == 1 ) |
1474 | 0 | { |
1475 | 0 | nRows = nCols = 1; |
1476 | 0 | nSheetMargin = 0; |
1477 | 0 | nPageMargin = 0; |
1478 | 0 | } |
1479 | 0 | else if( nPages == 2 || nPages == 4 || nPages == 6 || nPages == 9 || nPages == 16 ) |
1480 | 0 | { |
1481 | 0 | Size aJobPageSize( getJobPageSize() ); |
1482 | 0 | bool bPortrait = aJobPageSize.Width() < aJobPageSize.Height(); |
1483 | 0 | if( nPages == 2 ) |
1484 | 0 | { |
1485 | 0 | if( bPortrait ) |
1486 | 0 | { |
1487 | 0 | nRows = 1; |
1488 | 0 | nCols = 2; |
1489 | 0 | } |
1490 | 0 | else |
1491 | 0 | { |
1492 | 0 | nRows = 2; |
1493 | 0 | nCols = 1; |
1494 | 0 | } |
1495 | 0 | } |
1496 | 0 | else if( nPages == 4 ) |
1497 | 0 | nRows = nCols = 2; |
1498 | 0 | else if( nPages == 6 ) |
1499 | 0 | { |
1500 | 0 | if( bPortrait ) |
1501 | 0 | { |
1502 | 0 | nRows = 2; |
1503 | 0 | nCols = 3; |
1504 | 0 | } |
1505 | 0 | else |
1506 | 0 | { |
1507 | 0 | nRows = 3; |
1508 | 0 | nCols = 2; |
1509 | 0 | } |
1510 | 0 | } |
1511 | 0 | else if( nPages == 9 ) |
1512 | 0 | nRows = nCols = 3; |
1513 | 0 | else if( nPages == 16 ) |
1514 | 0 | nRows = nCols = 4; |
1515 | 0 | nPageMargin = 0; |
1516 | 0 | nSheetMargin = 0; |
1517 | 0 | } |
1518 | 0 | else |
1519 | 0 | bCustom = true; |
1520 | |
|
1521 | 0 | if( nPages > 1 ) |
1522 | 0 | { |
1523 | | // set upper limits for margins based on job page size and rows/columns |
1524 | 0 | Size aSize( getJobPageSize() ); |
1525 | | |
1526 | | // maximum sheet distance: 1/2 sheet |
1527 | 0 | tools::Long nHorzMax = aSize.Width()/2; |
1528 | 0 | tools::Long nVertMax = aSize.Height()/2; |
1529 | 0 | if( nSheetMargin > nHorzMax ) |
1530 | 0 | nSheetMargin = nHorzMax; |
1531 | 0 | if( nSheetMargin > nVertMax ) |
1532 | 0 | nSheetMargin = nVertMax; |
1533 | |
|
1534 | 0 | mxSheetMarginEdt->set_max( |
1535 | 0 | mxSheetMarginEdt->normalize( |
1536 | 0 | std::min(nHorzMax, nVertMax) ), FieldUnit::MM_100TH ); |
1537 | | |
1538 | | // maximum page distance |
1539 | 0 | nHorzMax = (aSize.Width() - 2*nSheetMargin); |
1540 | 0 | if( nCols > 1 ) |
1541 | 0 | nHorzMax /= (nCols-1); |
1542 | 0 | nVertMax = (aSize.Height() - 2*nSheetMargin); |
1543 | 0 | if( nRows > 1 ) |
1544 | 0 | nHorzMax /= (nRows-1); |
1545 | |
|
1546 | 0 | if( nPageMargin > nHorzMax ) |
1547 | 0 | nPageMargin = nHorzMax; |
1548 | 0 | if( nPageMargin > nVertMax ) |
1549 | 0 | nPageMargin = nVertMax; |
1550 | |
|
1551 | 0 | mxPageMarginEdt->set_max( |
1552 | 0 | mxSheetMarginEdt->normalize( |
1553 | 0 | std::min(nHorzMax, nVertMax ) ), FieldUnit::MM_100TH ); |
1554 | 0 | } |
1555 | |
|
1556 | 0 | mxNupRowsEdt->set_value( nRows ); |
1557 | 0 | mxNupColEdt->set_value( nCols ); |
1558 | 0 | mxPageMarginEdt->set_value( mxPageMarginEdt->normalize( nPageMargin ), FieldUnit::MM_100TH ); |
1559 | 0 | mxSheetMarginEdt->set_value( mxSheetMarginEdt->normalize( nSheetMargin ), FieldUnit::MM_100TH ); |
1560 | |
|
1561 | 0 | showAdvancedControls( bCustom ); |
1562 | 0 | updateNup( i_bMayUseCache ); |
1563 | 0 | } |
1564 | | |
1565 | | void PrintDialog::enableNupControls( bool bEnable ) |
1566 | 0 | { |
1567 | 0 | mxNupPagesBox->set_sensitive( bEnable ); |
1568 | 0 | mxNupNumPagesTxt->set_sensitive( bEnable ); |
1569 | 0 | mxNupColEdt->set_sensitive( bEnable ); |
1570 | 0 | mxNupTimesTxt->set_sensitive( bEnable ); |
1571 | 0 | mxNupRowsEdt->set_sensitive( bEnable ); |
1572 | 0 | mxPageMarginTxt1->set_sensitive( bEnable ); |
1573 | 0 | mxPageMarginEdt->set_sensitive( bEnable ); |
1574 | 0 | mxPageMarginTxt2->set_sensitive( bEnable ); |
1575 | 0 | mxSheetMarginTxt1->set_sensitive( bEnable ); |
1576 | 0 | mxSheetMarginEdt->set_sensitive( bEnable ); |
1577 | 0 | mxSheetMarginTxt2->set_sensitive( bEnable ); |
1578 | 0 | mxNupOrderTxt->set_sensitive( bEnable ); |
1579 | 0 | mxNupOrderBox->set_sensitive( bEnable ); |
1580 | 0 | mxNupOrderWin->set_sensitive( bEnable ); |
1581 | 0 | mxBorderCB->set_sensitive( bEnable ); |
1582 | 0 | } |
1583 | | |
1584 | | void PrintDialog::showAdvancedControls( bool i_bShow ) |
1585 | 0 | { |
1586 | 0 | mxNupNumPagesTxt->set_visible( i_bShow ); |
1587 | 0 | mxNupColEdt->set_visible( i_bShow ); |
1588 | 0 | mxNupTimesTxt->set_visible( i_bShow ); |
1589 | 0 | mxNupRowsEdt->set_visible( i_bShow ); |
1590 | 0 | mxPageMarginTxt1->set_visible( i_bShow ); |
1591 | 0 | mxPageMarginEdt->set_visible( i_bShow ); |
1592 | 0 | mxPageMarginTxt2->set_visible( i_bShow ); |
1593 | 0 | mxSheetMarginTxt1->set_visible( i_bShow ); |
1594 | 0 | mxSheetMarginEdt->set_visible( i_bShow ); |
1595 | 0 | mxSheetMarginTxt2->set_visible( i_bShow ); |
1596 | 0 | } |
1597 | | |
1598 | | namespace |
1599 | | { |
1600 | | void setHelpId( weld::Widget* i_pWindow, const Sequence< OUString >& i_rHelpIds, sal_Int32 i_nIndex ) |
1601 | 0 | { |
1602 | 0 | if( i_nIndex >= 0 && i_nIndex < i_rHelpIds.getLength() ) |
1603 | 0 | i_pWindow->set_help_id( i_rHelpIds.getConstArray()[i_nIndex] ); |
1604 | 0 | } |
1605 | | |
1606 | | void setHelpText( weld::Widget* i_pWindow, const Sequence< OUString >& i_rHelpTexts, sal_Int32 i_nIndex ) |
1607 | 0 | { |
1608 | | // without a help text set and the correct smartID, |
1609 | | // help texts will be retrieved from the online help system |
1610 | 0 | if( i_nIndex >= 0 && i_nIndex < i_rHelpTexts.getLength() ) |
1611 | 0 | i_pWindow->set_tooltip_text(i_rHelpTexts.getConstArray()[i_nIndex]); |
1612 | 0 | } |
1613 | | } |
1614 | | |
1615 | | void PrintDialog::setupOptionalUI() |
1616 | 0 | { |
1617 | 0 | const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() ); |
1618 | 0 | for( const auto& rOption : rOptions ) |
1619 | 0 | { |
1620 | 0 | if (rOption.Name == "OptionsUIFile") |
1621 | 0 | { |
1622 | 0 | OUString sOptionsUIFile; |
1623 | 0 | rOption.Value >>= sOptionsUIFile; |
1624 | 0 | mxCustomOptionsUIBuilder = Application::CreateBuilder(mxCustom.get(), sOptionsUIFile); |
1625 | 0 | std::unique_ptr<weld::Container> xWindow = mxCustomOptionsUIBuilder->weld_container(u"box"_ustr); |
1626 | 0 | xWindow->set_help_id(u"vcl/ui/printdialog/PrintDialog"_ustr); |
1627 | 0 | xWindow->show(); |
1628 | 0 | continue; |
1629 | 0 | } |
1630 | | |
1631 | 0 | Sequence< beans::PropertyValue > aOptProp; |
1632 | 0 | rOption.Value >>= aOptProp; |
1633 | | |
1634 | | // extract ui element |
1635 | 0 | OUString aCtrlType; |
1636 | 0 | OUString aID; |
1637 | 0 | OUString aText; |
1638 | 0 | OUString aPropertyName; |
1639 | 0 | Sequence< OUString > aChoices; |
1640 | 0 | Sequence< sal_Bool > aChoicesDisabled; |
1641 | 0 | Sequence< OUString > aHelpTexts; |
1642 | 0 | Sequence< OUString > aIDs; |
1643 | 0 | Sequence< OUString > aHelpIds; |
1644 | 0 | sal_Int64 nMinValue = 0, nMaxValue = 0; |
1645 | 0 | OUString aGroupingHint; |
1646 | |
|
1647 | 0 | for (const beans::PropertyValue& rEntry : aOptProp) |
1648 | 0 | { |
1649 | 0 | if ( rEntry.Name == "ID" ) |
1650 | 0 | { |
1651 | 0 | rEntry.Value >>= aIDs; |
1652 | 0 | aID = aIDs[0]; |
1653 | 0 | } |
1654 | 0 | if ( rEntry.Name == "Text" ) |
1655 | 0 | { |
1656 | 0 | rEntry.Value >>= aText; |
1657 | 0 | } |
1658 | 0 | else if ( rEntry.Name == "ControlType" ) |
1659 | 0 | { |
1660 | 0 | rEntry.Value >>= aCtrlType; |
1661 | 0 | } |
1662 | 0 | else if ( rEntry.Name == "Choices" ) |
1663 | 0 | { |
1664 | 0 | rEntry.Value >>= aChoices; |
1665 | 0 | } |
1666 | 0 | else if ( rEntry.Name == "ChoicesDisabled" ) |
1667 | 0 | { |
1668 | 0 | rEntry.Value >>= aChoicesDisabled; |
1669 | 0 | } |
1670 | 0 | else if ( rEntry.Name == "Property" ) |
1671 | 0 | { |
1672 | 0 | PropertyValue aVal; |
1673 | 0 | rEntry.Value >>= aVal; |
1674 | 0 | aPropertyName = aVal.Name; |
1675 | 0 | } |
1676 | 0 | else if ( rEntry.Name == "Enabled" ) |
1677 | 0 | { |
1678 | 0 | } |
1679 | 0 | else if ( rEntry.Name == "GroupingHint" ) |
1680 | 0 | { |
1681 | 0 | rEntry.Value >>= aGroupingHint; |
1682 | 0 | } |
1683 | 0 | else if ( rEntry.Name == "DependsOnName" ) |
1684 | 0 | { |
1685 | 0 | } |
1686 | 0 | else if ( rEntry.Name == "DependsOnEntry" ) |
1687 | 0 | { |
1688 | 0 | } |
1689 | 0 | else if ( rEntry.Name == "AttachToDependency" ) |
1690 | 0 | { |
1691 | 0 | } |
1692 | 0 | else if ( rEntry.Name == "MinValue" ) |
1693 | 0 | { |
1694 | 0 | rEntry.Value >>= nMinValue; |
1695 | 0 | } |
1696 | 0 | else if ( rEntry.Name == "MaxValue" ) |
1697 | 0 | { |
1698 | 0 | rEntry.Value >>= nMaxValue; |
1699 | 0 | } |
1700 | 0 | else if ( rEntry.Name == "HelpText" ) |
1701 | 0 | { |
1702 | 0 | if( ! (rEntry.Value >>= aHelpTexts) ) |
1703 | 0 | { |
1704 | 0 | OUString aHelpText; |
1705 | 0 | if( rEntry.Value >>= aHelpText ) |
1706 | 0 | { |
1707 | 0 | aHelpTexts.realloc( 1 ); |
1708 | 0 | *aHelpTexts.getArray() = aHelpText; |
1709 | 0 | } |
1710 | 0 | } |
1711 | 0 | } |
1712 | 0 | else if ( rEntry.Name == "HelpId" ) |
1713 | 0 | { |
1714 | 0 | if( ! (rEntry.Value >>= aHelpIds ) ) |
1715 | 0 | { |
1716 | 0 | OUString aHelpId; |
1717 | 0 | if( rEntry.Value >>= aHelpId ) |
1718 | 0 | { |
1719 | 0 | aHelpIds.realloc( 1 ); |
1720 | 0 | *aHelpIds.getArray() = aHelpId; |
1721 | 0 | } |
1722 | 0 | } |
1723 | 0 | } |
1724 | 0 | else if ( rEntry.Name == "HintNoLayoutPage" ) |
1725 | 0 | { |
1726 | 0 | bool bHasLayoutFrame = false; |
1727 | 0 | rEntry.Value >>= bHasLayoutFrame; |
1728 | 0 | mbShowLayoutFrame = !bHasLayoutFrame; |
1729 | 0 | } |
1730 | 0 | } |
1731 | |
|
1732 | 0 | if (aCtrlType == "Group") |
1733 | 0 | { |
1734 | 0 | aID = "custom"; |
1735 | |
|
1736 | 0 | weld::Container* pPage = mxTabCtrl->get_page(aID); |
1737 | 0 | if (!pPage) |
1738 | 0 | continue; |
1739 | | |
1740 | 0 | mxTabCtrl->set_tab_label_text(aID, aText); |
1741 | | |
1742 | | // set help id |
1743 | 0 | if (aHelpIds.hasElements()) |
1744 | 0 | pPage->set_help_id(aHelpIds[0]); |
1745 | | |
1746 | | // set help text |
1747 | 0 | if (aHelpTexts.hasElements()) |
1748 | 0 | pPage->set_tooltip_text(aHelpTexts[0]); |
1749 | |
|
1750 | 0 | pPage->show(); |
1751 | 0 | } |
1752 | 0 | else if (aCtrlType == "Subgroup" && !aID.isEmpty()) |
1753 | 0 | { |
1754 | 0 | std::unique_ptr<weld::Widget> xWidget; |
1755 | | // since 'New Print Dialog Design' fromwhich in calc is not a frame anymore |
1756 | 0 | if (aID == "fromwhich") |
1757 | 0 | { |
1758 | 0 | std::unique_ptr<weld::Label> xLabel = m_xBuilder->weld_label(aID); |
1759 | 0 | xLabel->set_label(aText); |
1760 | 0 | xWidget = std::move(xLabel); |
1761 | 0 | } |
1762 | 0 | else |
1763 | 0 | { |
1764 | 0 | std::unique_ptr<weld::Frame> xFrame = m_xBuilder->weld_frame(aID); |
1765 | 0 | if (!xFrame && mxCustomOptionsUIBuilder) |
1766 | 0 | xFrame = mxCustomOptionsUIBuilder->weld_frame(aID); |
1767 | 0 | if (xFrame) |
1768 | 0 | { |
1769 | 0 | xFrame->set_label(aText); |
1770 | 0 | xWidget = std::move(xFrame); |
1771 | 0 | } |
1772 | 0 | } |
1773 | |
|
1774 | 0 | if (!xWidget) |
1775 | 0 | continue; |
1776 | | |
1777 | | // set help id |
1778 | 0 | setHelpId(xWidget.get(), aHelpIds, 0); |
1779 | | // set help text |
1780 | 0 | setHelpText(xWidget.get(), aHelpTexts, 0); |
1781 | |
|
1782 | 0 | xWidget->show(); |
1783 | 0 | } |
1784 | | // EVIL |
1785 | 0 | else if( aCtrlType == "Bool" && aGroupingHint == "LayoutPage" && aPropertyName == "PrintProspect" ) |
1786 | 0 | { |
1787 | 0 | mxBrochureBtn->set_label(aText); |
1788 | 0 | mxBrochureBtn->show(); |
1789 | |
|
1790 | 0 | bool bVal = false; |
1791 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1792 | 0 | if( pVal ) |
1793 | 0 | pVal->Value >>= bVal; |
1794 | 0 | mxBrochureBtn->set_active( bVal ); |
1795 | 0 | mxBrochureBtn->set_sensitive( maPController->isUIOptionEnabled( aPropertyName ) && pVal != nullptr ); |
1796 | |
|
1797 | 0 | maPropertyToWindowMap[aPropertyName].emplace_back(mxBrochureBtn.get()); |
1798 | 0 | maControlToPropertyMap[mxBrochureBtn.get()] = aPropertyName; |
1799 | | |
1800 | | // set help id |
1801 | 0 | setHelpId( mxBrochureBtn.get(), aHelpIds, 0 ); |
1802 | | // set help text |
1803 | 0 | setHelpText( mxBrochureBtn.get(), aHelpTexts, 0 ); |
1804 | 0 | } |
1805 | 0 | else if (aCtrlType == "Bool") |
1806 | 0 | { |
1807 | | // add a check box |
1808 | 0 | std::unique_ptr<weld::CheckButton> xNewBox = m_xBuilder->weld_check_button(aID); |
1809 | 0 | if (!xNewBox && mxCustomOptionsUIBuilder) |
1810 | 0 | xNewBox = mxCustomOptionsUIBuilder->weld_check_button(aID); |
1811 | 0 | if (!xNewBox) |
1812 | 0 | continue; |
1813 | | |
1814 | 0 | xNewBox->set_label( aText ); |
1815 | 0 | xNewBox->show(); |
1816 | |
|
1817 | 0 | bool bVal = false; |
1818 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1819 | 0 | if( pVal ) |
1820 | 0 | pVal->Value >>= bVal; |
1821 | 0 | xNewBox->set_active( bVal ); |
1822 | 0 | xNewBox->connect_toggled( LINK( this, PrintDialog, UIOption_CheckHdl ) ); |
1823 | |
|
1824 | 0 | maExtraControls.emplace_back(std::move(xNewBox)); |
1825 | |
|
1826 | 0 | weld::Widget* pWidget = maExtraControls.back().get(); |
1827 | |
|
1828 | 0 | maPropertyToWindowMap[aPropertyName].emplace_back(pWidget); |
1829 | 0 | maControlToPropertyMap[pWidget] = aPropertyName; |
1830 | | |
1831 | | // set help id |
1832 | 0 | setHelpId(pWidget, aHelpIds, 0); |
1833 | | // set help text |
1834 | 0 | setHelpText(pWidget, aHelpTexts, 0); |
1835 | 0 | } |
1836 | 0 | else if (aCtrlType == "Radio") |
1837 | 0 | { |
1838 | 0 | sal_Int32 nCurHelpText = 0; |
1839 | | |
1840 | | // iterate options |
1841 | 0 | sal_Int32 nSelectVal = 0; |
1842 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1843 | 0 | if( pVal && pVal->Value.hasValue() ) |
1844 | 0 | pVal->Value >>= nSelectVal; |
1845 | 0 | for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) |
1846 | 0 | { |
1847 | 0 | aID = aIDs[m]; |
1848 | 0 | std::unique_ptr<weld::RadioButton> xBtn = m_xBuilder->weld_radio_button(aID); |
1849 | 0 | if (!xBtn && mxCustomOptionsUIBuilder) |
1850 | 0 | xBtn = mxCustomOptionsUIBuilder->weld_radio_button(aID); |
1851 | 0 | if (!xBtn) |
1852 | 0 | continue; |
1853 | | |
1854 | 0 | xBtn->set_label( aChoices[m] ); |
1855 | 0 | xBtn->set_active( m == nSelectVal ); |
1856 | 0 | xBtn->connect_toggled( LINK( this, PrintDialog, UIOption_RadioHdl ) ); |
1857 | 0 | if( aChoicesDisabled.getLength() > m && aChoicesDisabled[m] ) |
1858 | 0 | xBtn->set_sensitive( false ); |
1859 | 0 | xBtn->show(); |
1860 | |
|
1861 | 0 | maExtraControls.emplace_back(std::move(xBtn)); |
1862 | |
|
1863 | 0 | weld::Widget* pWidget = maExtraControls.back().get(); |
1864 | |
|
1865 | 0 | maPropertyToWindowMap[ aPropertyName ].emplace_back(pWidget); |
1866 | 0 | maControlToPropertyMap[pWidget] = aPropertyName; |
1867 | 0 | maControlToNumValMap[pWidget] = m; |
1868 | | |
1869 | | // set help id |
1870 | 0 | setHelpId( pWidget, aHelpIds, nCurHelpText ); |
1871 | | // set help text |
1872 | 0 | setHelpText( pWidget, aHelpTexts, nCurHelpText ); |
1873 | 0 | nCurHelpText++; |
1874 | 0 | } |
1875 | 0 | } |
1876 | 0 | else if ( aCtrlType == "List" ) |
1877 | 0 | { |
1878 | 0 | std::unique_ptr<weld::ComboBox> xList = m_xBuilder->weld_combo_box(aID); |
1879 | 0 | if (!xList && mxCustomOptionsUIBuilder) |
1880 | 0 | xList = mxCustomOptionsUIBuilder->weld_combo_box(aID); |
1881 | 0 | if (!xList) |
1882 | 0 | continue; |
1883 | | |
1884 | | // iterate options |
1885 | 0 | for (const auto& rChoice : aChoices) |
1886 | 0 | xList->append_text(rChoice); |
1887 | |
|
1888 | 0 | sal_Int32 nSelectVal = 0; |
1889 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1890 | 0 | if( pVal && pVal->Value.hasValue() ) |
1891 | 0 | pVal->Value >>= nSelectVal; |
1892 | 0 | xList->set_active(nSelectVal); |
1893 | 0 | xList->connect_changed( LINK( this, PrintDialog, UIOption_SelectHdl ) ); |
1894 | 0 | xList->show(); |
1895 | |
|
1896 | 0 | maExtraControls.emplace_back(std::move(xList)); |
1897 | |
|
1898 | 0 | weld::Widget* pWidget = maExtraControls.back().get(); |
1899 | |
|
1900 | 0 | maPropertyToWindowMap[ aPropertyName ].emplace_back(pWidget); |
1901 | 0 | maControlToPropertyMap[pWidget] = aPropertyName; |
1902 | | |
1903 | | // set help id |
1904 | 0 | setHelpId( pWidget, aHelpIds, 0 ); |
1905 | | // set help text |
1906 | 0 | setHelpText( pWidget, aHelpTexts, 0 ); |
1907 | 0 | } |
1908 | 0 | else if ( aCtrlType == "Range" ) |
1909 | 0 | { |
1910 | 0 | std::unique_ptr<weld::SpinButton> xField = m_xBuilder->weld_spin_button(aID); |
1911 | 0 | if (!xField && mxCustomOptionsUIBuilder) |
1912 | 0 | xField = mxCustomOptionsUIBuilder->weld_spin_button(aID); |
1913 | 0 | if (!xField) |
1914 | 0 | continue; |
1915 | | |
1916 | | // set min/max and current value |
1917 | 0 | if(nMinValue != nMaxValue) |
1918 | 0 | xField->set_range(nMinValue, nMaxValue); |
1919 | |
|
1920 | 0 | sal_Int64 nCurVal = 0; |
1921 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1922 | 0 | if( pVal && pVal->Value.hasValue() ) |
1923 | 0 | pVal->Value >>= nCurVal; |
1924 | 0 | xField->set_value( nCurVal ); |
1925 | 0 | xField->connect_value_changed( LINK( this, PrintDialog, UIOption_SpinModifyHdl ) ); |
1926 | 0 | xField->show(); |
1927 | |
|
1928 | 0 | maExtraControls.emplace_back(std::move(xField)); |
1929 | |
|
1930 | 0 | weld::Widget* pWidget = maExtraControls.back().get(); |
1931 | |
|
1932 | 0 | maPropertyToWindowMap[ aPropertyName ].emplace_back(pWidget); |
1933 | 0 | maControlToPropertyMap[pWidget] = aPropertyName; |
1934 | | |
1935 | | // set help id |
1936 | 0 | setHelpId( pWidget, aHelpIds, 0 ); |
1937 | | // set help text |
1938 | 0 | setHelpText( pWidget, aHelpTexts, 0 ); |
1939 | 0 | } |
1940 | 0 | else if (aCtrlType == "Edit") |
1941 | 0 | { |
1942 | 0 | std::unique_ptr<weld::Entry> xField = m_xBuilder->weld_entry(aID); |
1943 | 0 | if (!xField && mxCustomOptionsUIBuilder) |
1944 | 0 | xField = mxCustomOptionsUIBuilder->weld_entry(aID); |
1945 | 0 | if (!xField) |
1946 | 0 | continue; |
1947 | | |
1948 | 0 | OUString aCurVal; |
1949 | 0 | PropertyValue* pVal = maPController->getValue( aPropertyName ); |
1950 | 0 | if( pVal && pVal->Value.hasValue() ) |
1951 | 0 | pVal->Value >>= aCurVal; |
1952 | 0 | if (aPropertyName != "PageRange") |
1953 | 0 | { |
1954 | 0 | xField->set_text( aCurVal ); |
1955 | 0 | } |
1956 | 0 | xField->connect_changed( LINK( this, PrintDialog, UIOption_EntryModifyHdl ) ); |
1957 | 0 | xField->show(); |
1958 | |
|
1959 | 0 | maExtraControls.emplace_back(std::move(xField)); |
1960 | |
|
1961 | 0 | weld::Widget* pWidget = maExtraControls.back().get(); |
1962 | |
|
1963 | 0 | maPropertyToWindowMap[ aPropertyName ].emplace_back(pWidget); |
1964 | 0 | maControlToPropertyMap[pWidget] = aPropertyName; |
1965 | | |
1966 | | // set help id |
1967 | 0 | setHelpId( pWidget, aHelpIds, 0 ); |
1968 | | // set help text |
1969 | 0 | setHelpText( pWidget, aHelpTexts, 0 ); |
1970 | 0 | } |
1971 | 0 | else |
1972 | 0 | { |
1973 | 0 | SAL_WARN( "vcl", "Unsupported UI option: \"" << aCtrlType << '"'); |
1974 | 0 | } |
1975 | 0 | } |
1976 | | |
1977 | | // #i106506# if no brochure button, then the singular Pages radio button |
1978 | | // makes no sense, so replace it by a FixedText label |
1979 | 0 | if (!mxBrochureBtn->get_visible() && mxPagesBtn->get_visible()) |
1980 | 0 | { |
1981 | 0 | mxPagesBoxTitleTxt->set_label(mxPagesBtn->get_label()); |
1982 | 0 | mxPagesBoxTitleTxt->show(); |
1983 | 0 | mxPagesBtn->hide(); |
1984 | |
|
1985 | 0 | mxNupPagesBox->set_accessible_relation_labeled_by(mxPagesBoxTitleTxt.get()); |
1986 | 0 | } |
1987 | | |
1988 | | // update enable states |
1989 | 0 | checkOptionalControlDependencies(); |
1990 | | |
1991 | | // print range not shown (currently math only) -> hide spacer line and reverse order |
1992 | 0 | if (!mxPageRangeEdit->get_visible()) |
1993 | 0 | { |
1994 | 0 | mxReverseOrderBox->hide(); |
1995 | 0 | } |
1996 | |
|
1997 | 0 | if (!mxCustomOptionsUIBuilder) |
1998 | 0 | mxTabCtrl->remove_page(mxTabCtrl->get_page_ident(1)); |
1999 | 0 | } |
2000 | | |
2001 | | void PrintDialog::makeEnabled( weld::Widget* i_pWindow ) |
2002 | 0 | { |
2003 | 0 | auto it = maControlToPropertyMap.find( i_pWindow ); |
2004 | 0 | if( it != maControlToPropertyMap.end() ) |
2005 | 0 | { |
2006 | 0 | OUString aDependency( maPController->makeEnabled( it->second ) ); |
2007 | 0 | if( !aDependency.isEmpty() ) |
2008 | 0 | updateWindowFromProperty( aDependency ); |
2009 | 0 | } |
2010 | 0 | } |
2011 | | |
2012 | | void PrintDialog::updateWindowFromProperty( const OUString& i_rProperty ) |
2013 | 0 | { |
2014 | 0 | beans::PropertyValue* pValue = maPController->getValue( i_rProperty ); |
2015 | 0 | auto it = maPropertyToWindowMap.find( i_rProperty ); |
2016 | 0 | if( !(pValue && it != maPropertyToWindowMap.end()) ) |
2017 | 0 | return; |
2018 | | |
2019 | 0 | const auto& rWindows( it->second ); |
2020 | 0 | if( rWindows.empty() ) |
2021 | 0 | return; |
2022 | | |
2023 | 0 | bool bVal = false; |
2024 | 0 | sal_Int32 nVal = -1; |
2025 | 0 | if( pValue->Value >>= bVal ) |
2026 | 0 | { |
2027 | | // we should have a CheckBox for this one |
2028 | 0 | weld::CheckButton* pBox = dynamic_cast<weld::CheckButton*>(rWindows.front()); |
2029 | 0 | if( pBox ) |
2030 | 0 | { |
2031 | 0 | pBox->set_active( bVal ); |
2032 | 0 | } |
2033 | 0 | else if ( i_rProperty == "PrintProspect" ) |
2034 | 0 | { |
2035 | | // EVIL special case |
2036 | 0 | if( bVal ) |
2037 | 0 | mxBrochureBtn->set_active(true); |
2038 | 0 | else |
2039 | 0 | mxPagesBtn->set_active(true); |
2040 | 0 | } |
2041 | 0 | else |
2042 | 0 | { |
2043 | 0 | SAL_WARN( "vcl", "missing a checkbox" ); |
2044 | 0 | } |
2045 | 0 | } |
2046 | 0 | else if( pValue->Value >>= nVal ) |
2047 | 0 | { |
2048 | | // this could be a ListBox or a RadioButtonGroup |
2049 | 0 | weld::ComboBox* pList = dynamic_cast<weld::ComboBox*>(rWindows.front()); |
2050 | 0 | if( pList ) |
2051 | 0 | { |
2052 | 0 | pList->set_active( static_cast< sal_uInt16 >(nVal) ); |
2053 | 0 | } |
2054 | 0 | else if( nVal >= 0 && o3tl::make_unsigned(nVal) < rWindows.size() ) |
2055 | 0 | { |
2056 | 0 | weld::RadioButton* pBtn = dynamic_cast<weld::RadioButton*>(rWindows[nVal]); |
2057 | 0 | SAL_WARN_IF( !pBtn, "vcl", "unexpected control for property" ); |
2058 | 0 | if( pBtn ) |
2059 | 0 | pBtn->set_active(true); |
2060 | 0 | } |
2061 | 0 | } |
2062 | 0 | } |
2063 | | |
2064 | | bool PrintDialog::isPrintToFile() const |
2065 | 0 | { |
2066 | 0 | return ( mxPrinters->get_active() == 0 ); |
2067 | 0 | } |
2068 | | |
2069 | | bool PrintDialog::isCollate() const |
2070 | 0 | { |
2071 | 0 | return mxCopyCountField->get_value() > 1 && mxCollateBox->get_active(); |
2072 | 0 | } |
2073 | | |
2074 | | bool PrintDialog::isSingleJobs() const |
2075 | 0 | { |
2076 | 0 | return mxSingleJobsBox->get_active(); |
2077 | 0 | } |
2078 | | |
2079 | | bool PrintDialog::hasPreview() const |
2080 | 0 | { |
2081 | 0 | return mxPreviewBox->get_active(); |
2082 | 0 | } |
2083 | | |
2084 | | PropertyValue* PrintDialog::getValueForWindow( weld::Widget* i_pWindow ) const |
2085 | 0 | { |
2086 | 0 | PropertyValue* pVal = nullptr; |
2087 | 0 | auto it = maControlToPropertyMap.find( i_pWindow ); |
2088 | 0 | if( it != maControlToPropertyMap.end() ) |
2089 | 0 | { |
2090 | 0 | pVal = maPController->getValue( it->second ); |
2091 | 0 | SAL_WARN_IF( !pVal, "vcl", "property value not found" ); |
2092 | 0 | } |
2093 | 0 | else |
2094 | 0 | { |
2095 | 0 | OSL_FAIL( "changed control not in property map" ); |
2096 | 0 | } |
2097 | 0 | return pVal; |
2098 | 0 | } |
2099 | | |
2100 | | IMPL_LINK_NOARG(PrintDialog, TogglePreviewHdl, weld::Toggleable&, void) |
2101 | 0 | { |
2102 | 0 | schedulePreviewUpdate(true); |
2103 | 0 | } |
2104 | | |
2105 | | IMPL_LINK_NOARG(PrintDialog, ToggleBorderHdl, weld::Toggleable&, void) |
2106 | 0 | { |
2107 | 0 | updateNup(); |
2108 | 0 | } |
2109 | | |
2110 | | IMPL_LINK_NOARG(PrintDialog, ToggleSingleJobsHdl, weld::Toggleable&, void) |
2111 | 0 | { |
2112 | 0 | maPController->setValue(u"SinglePrintJobs"_ustr, Any(isSingleJobs())); |
2113 | 0 | checkControlDependencies(); |
2114 | 0 | } |
2115 | | |
2116 | | IMPL_LINK_NOARG(PrintDialog, ToggleCollateHdl, weld::Toggleable&, void) |
2117 | 0 | { |
2118 | 0 | maPController->setValue(u"Collate"_ustr, Any(isCollate())); |
2119 | 0 | checkControlDependencies(); |
2120 | 0 | } |
2121 | | |
2122 | | IMPL_LINK_NOARG(PrintDialog, ToggleReverseOrderHdl, weld::Toggleable&, void) |
2123 | 0 | { |
2124 | 0 | bool bChecked = mxReverseOrderBox->get_active(); |
2125 | 0 | maPController->setReversePrint(bChecked); |
2126 | 0 | maPController->setValue(u"PrintReverse"_ustr, Any(bChecked)); |
2127 | 0 | schedulePreviewUpdate(true); |
2128 | 0 | } |
2129 | | |
2130 | | IMPL_LINK_NOARG(PrintDialog, ToggleBrochureHdl, weld::Toggleable&, void) |
2131 | 0 | { |
2132 | 0 | PropertyValue* pVal = getValueForWindow(mxBrochureBtn.get()); |
2133 | 0 | if (pVal) |
2134 | 0 | { |
2135 | 0 | bool bVal = mxBrochureBtn->get_active(); |
2136 | 0 | pVal->Value <<= bVal; |
2137 | |
|
2138 | 0 | checkOptionalControlDependencies(); |
2139 | | |
2140 | | // update preview and page settings |
2141 | 0 | schedulePreviewUpdate(false); |
2142 | 0 | } |
2143 | 0 | if (mxBrochureBtn->get_active()) |
2144 | 0 | { |
2145 | 0 | mxOrientationBox->set_sensitive(false); |
2146 | 0 | mxOrientationBox->set_active(ORIENTATION_LANDSCAPE); |
2147 | 0 | mxNupPagesBox->set_active(0); |
2148 | 0 | updateNupFromPages(); |
2149 | 0 | showAdvancedControls(false); |
2150 | 0 | enableNupControls(false); |
2151 | 0 | } |
2152 | 0 | else |
2153 | 0 | { |
2154 | 0 | mxOrientationBox->set_sensitive(true); |
2155 | 0 | mxOrientationBox->set_active(ORIENTATION_AUTOMATIC); |
2156 | 0 | updatePageSize(mxOrientationBox->get_active()); |
2157 | 0 | enableNupControls(true); |
2158 | 0 | updateNupFromPages(); |
2159 | 0 | } |
2160 | 0 | } |
2161 | | |
2162 | | IMPL_LINK(PrintDialog, ClickOKCancelHdl, weld::Button&, rButton, void) |
2163 | 0 | { |
2164 | 0 | storeToSettings(); |
2165 | 0 | m_xDialog->response(&rButton == mxOKButton.get() ? RET_OK : RET_CANCEL); |
2166 | 0 | } |
2167 | | |
2168 | | IMPL_LINK_NOARG(PrintDialog, ClickForwardHdl, weld::Button&, void) |
2169 | 0 | { |
2170 | 0 | previewForward(); |
2171 | 0 | } |
2172 | | |
2173 | | IMPL_LINK_NOARG(PrintDialog, ClickBackwardHdl, weld::Button&, void) |
2174 | 0 | { |
2175 | 0 | previewBackward(); |
2176 | 0 | } |
2177 | | |
2178 | | IMPL_LINK_NOARG(PrintDialog, ClickFirstHdl, weld::Button&, void) |
2179 | 0 | { |
2180 | 0 | previewFirst(); |
2181 | 0 | } |
2182 | | |
2183 | | IMPL_LINK_NOARG(PrintDialog, ClickLastHdl, weld::Button&, void) |
2184 | 0 | { |
2185 | 0 | previewLast(); |
2186 | 0 | } |
2187 | | |
2188 | | IMPL_LINK_NOARG(PrintDialog, ClickSetupHdl, weld::Button&, void) |
2189 | 0 | { |
2190 | 0 | const Size aSavedCustomSize = maCustomPaperSize; |
2191 | 0 | const bool bHadCustomEntry = mbHasCustomPaperEntry; |
2192 | | // Save orientation dropdown — Properties dialog can clobber it. |
2193 | 0 | const int nSavedOrient = mxOrientationBox->get_active(); |
2194 | |
|
2195 | 0 | maPController->setupPrinter(m_xDialog.get()); |
2196 | |
|
2197 | 0 | if (!isPrintToFile()) |
2198 | 0 | { |
2199 | | // Rebuild paper size list to restore custom entry if needed. |
2200 | 0 | setPaperSizes(); |
2201 | | |
2202 | | // Restore lost custom entry from saved document page size. |
2203 | 0 | if (bHadCustomEntry && !mbHasCustomPaperEntry |
2204 | 0 | && !aSavedCustomSize.IsEmpty()) |
2205 | 0 | { |
2206 | 0 | maFirstPageSize = aSavedCustomSize; |
2207 | 0 | setPaperSizes(); |
2208 | 0 | } |
2209 | | |
2210 | | // tdf#173642: setPaperSizes() selects the paper matching the document, |
2211 | | // which would discard a paper picked in the dropdown. |
2212 | 0 | updatePaperSizeBox(); |
2213 | 0 | } |
2214 | | |
2215 | | // Sync maSelectedPaperSize with current combobox selection. |
2216 | 0 | if (mxPaperSizeBox->get_sensitive() && mxPaperSizeBox->get_active() >= 0) |
2217 | 0 | SelectPaperSizeHdl(*mxPaperSizeBox); |
2218 | |
|
2219 | 0 | updateOrientationBox(false); |
2220 | | |
2221 | | // Restore orientation dropdown — Properties dialog may have |
2222 | | // clobbered the printer's orientation as a side effect. |
2223 | 0 | if (mxOrientationBox->get_active() != nSavedOrient) |
2224 | 0 | { |
2225 | 0 | mxOrientationBox->set_active(nSavedOrient); |
2226 | 0 | } |
2227 | |
|
2228 | 0 | updatePageSize(mxOrientationBox->get_active()); |
2229 | |
|
2230 | 0 | setupPaperSidesBox(); |
2231 | | |
2232 | | // tdf#63905 don't use cache: page size may change |
2233 | 0 | schedulePreviewUpdate(false); |
2234 | 0 | checkControlDependencies(); |
2235 | 0 | } |
2236 | | |
2237 | | IMPL_LINK_NOARG( PrintDialog, SelectPrinterHdl, weld::ComboBox&, void ) |
2238 | 0 | { |
2239 | | // Save custom size — setPrinter() resets mbPapersizeFromUser. |
2240 | 0 | const Size aSavedCustomSize = maCustomPaperSize; |
2241 | 0 | const bool bHadCustomEntry = mbHasCustomPaperEntry; |
2242 | |
|
2243 | 0 | if (!isPrintToFile()) |
2244 | 0 | { |
2245 | 0 | OUString aNewPrinter(mxPrinters->get_active_text()); |
2246 | | // set new printer |
2247 | 0 | maPController->setPrinter(VclPtrInstance<Printer>(aNewPrinter)); |
2248 | 0 | maPController->resetPrinterOptions(false); |
2249 | | // invalidate page cache and start fresh |
2250 | 0 | maPController->invalidatePageCache(); |
2251 | 0 | maFirstPageSize = Size(); |
2252 | |
|
2253 | 0 | updateOrientationBox(); |
2254 | | |
2255 | | // update text fields |
2256 | 0 | mxOKButton->set_label(maPrintText); |
2257 | 0 | updatePrinterText(); |
2258 | 0 | updateNup(false); |
2259 | 0 | setPaperSizes(); |
2260 | | |
2261 | | // Restore lost custom entry from saved document page size. |
2262 | 0 | if (bHadCustomEntry && !mbHasCustomPaperEntry |
2263 | 0 | && !aSavedCustomSize.IsEmpty()) |
2264 | 0 | { |
2265 | 0 | maCustomPaperSize = aSavedCustomSize; |
2266 | 0 | maFirstPageSize = aSavedCustomSize; |
2267 | 0 | setPaperSizes(); |
2268 | 0 | } |
2269 | |
|
2270 | 0 | schedulePreviewUpdate(true); |
2271 | 0 | } |
2272 | 0 | else // print to file |
2273 | 0 | { |
2274 | | // use the default printer or FIXME: the last used one? |
2275 | 0 | maPController->setPrinter(VclPtrInstance<Printer>(Printer::GetDefaultPrinterName())); |
2276 | 0 | mxOKButton->set_label(maPrintToFileText); |
2277 | 0 | maPController->resetPrinterOptions(true); |
2278 | |
|
2279 | 0 | setPaperSizes(); |
2280 | |
|
2281 | 0 | if (bHadCustomEntry && !mbHasCustomPaperEntry |
2282 | 0 | && !aSavedCustomSize.IsEmpty()) |
2283 | 0 | { |
2284 | 0 | maCustomPaperSize = aSavedCustomSize; |
2285 | 0 | maFirstPageSize = aSavedCustomSize; |
2286 | 0 | setPaperSizes(); |
2287 | 0 | } |
2288 | |
|
2289 | 0 | updateOrientationBox(); |
2290 | 0 | schedulePreviewUpdate(true); |
2291 | 0 | } |
2292 | |
|
2293 | 0 | setupPaperSidesBox(); |
2294 | | |
2295 | | // Related: tdf#159995 changing a listbox's active item does not |
2296 | | // trigger an update to the preview so force an update to the |
2297 | | // preview by calling each active listbox's select handler after |
2298 | | // changing the active printer. |
2299 | 0 | if (mxOrientationBox->get_sensitive()) |
2300 | 0 | SelectOrientationHdl(*mxOrientationBox); |
2301 | 0 | if (mxPaperSizeBox->get_sensitive()) |
2302 | 0 | SelectPaperSizeHdl(*mxPaperSizeBox); |
2303 | 0 | } |
2304 | | |
2305 | | IMPL_LINK_NOARG(PrintDialog, SelectPaperSidesHdl, weld::ComboBox&, void) |
2306 | 0 | { |
2307 | 0 | DuplexMode eDuplex = static_cast<DuplexMode>(mxPaperSidesBox->get_active() + 1); |
2308 | 0 | maPController->getPrinter()->SetDuplexMode(eDuplex); |
2309 | 0 | } |
2310 | | |
2311 | | IMPL_LINK_NOARG(PrintDialog, SelectOrientationHdl, weld::ComboBox&, void) |
2312 | 0 | { |
2313 | 0 | int nOrientation = mxOrientationBox->get_active(); |
2314 | 0 | if (nOrientation != ORIENTATION_AUTOMATIC) |
2315 | 0 | setPaperOrientation(static_cast<Orientation>(nOrientation - 1), true); |
2316 | |
|
2317 | 0 | updatePageSize(nOrientation); |
2318 | 0 | updateNup(false); |
2319 | 0 | } |
2320 | | |
2321 | | IMPL_LINK_NOARG(PrintDialog, SelectNupOrderHdl, weld::ComboBox&, void) |
2322 | 0 | { |
2323 | 0 | updateNup(); |
2324 | 0 | } |
2325 | | |
2326 | | IMPL_LINK_NOARG(PrintDialog, SelectNupPagesHdl, weld::ComboBox&, void) |
2327 | 0 | { |
2328 | 0 | if (!mxPagesBtn->get_active()) |
2329 | 0 | mxPagesBtn->set_active(true); |
2330 | 0 | updatePageSize(mxOrientationBox->get_active()); |
2331 | 0 | updateNupFromPages(false); |
2332 | 0 | } |
2333 | | |
2334 | | IMPL_LINK_NOARG(PrintDialog, SelectPaperSizeHdl, weld::ComboBox&, void) |
2335 | 0 | { |
2336 | 0 | VclPtr<Printer> aPrt(maPController->getPrinter()); |
2337 | 0 | int nActive = mxPaperSizeBox->get_active(); |
2338 | | |
2339 | | // Save orientation — SetPaper/SetPaperSizeUser can clobber it. |
2340 | 0 | Orientation eOrientBefore = aPrt->GetOrientation(); |
2341 | | |
2342 | | // Custom entry is beyond GetPaperInfoCount(); handle separately. |
2343 | 0 | if (mbHasCustomPaperEntry && nActive == aPrt->GetPaperInfoCount()) |
2344 | 0 | { |
2345 | 0 | mePaper = PAPER_USER; |
2346 | | // SetPaperSizeUser needs logical units; set Map100thMM. |
2347 | 0 | { |
2348 | 0 | auto popIt = aPrt->ScopedPush(); |
2349 | 0 | aPrt->SetMapMode(MapMode(MapUnit::Map100thMM)); |
2350 | 0 | aPrt->SetPaperSizeUser(maCustomPaperSize); |
2351 | 0 | } |
2352 | 0 | maPController->setPaperSizeFromUser(maCustomPaperSize); |
2353 | 0 | maSelectedPaperSize = maCustomPaperSize; |
2354 | 0 | } |
2355 | 0 | else |
2356 | 0 | { |
2357 | 0 | PaperInfo aInfo = aPrt->GetPaperInfo(nActive); |
2358 | 0 | aInfo.doSloppyFit(true); |
2359 | 0 | mePaper = aInfo.getPaper(); |
2360 | 0 | Size aSelectedSize(aInfo.getWidth(), aInfo.getHeight()); |
2361 | 0 | if (mePaper == PAPER_USER) |
2362 | 0 | aPrt->SetPaperSizeUser(aSelectedSize); |
2363 | 0 | else |
2364 | 0 | aPrt->SetPaper(mePaper); |
2365 | |
|
2366 | 0 | maPController->setPaperSizeFromUser(aSelectedSize); |
2367 | 0 | maSelectedPaperSize = aSelectedSize; |
2368 | 0 | } |
2369 | | |
2370 | | // In Automatic mode, restore orientation that SetPaper/SetPaperSizeUser |
2371 | | // may have changed — orientation should follow the document. |
2372 | 0 | if (mxOrientationBox->get_active() == ORIENTATION_AUTOMATIC |
2373 | 0 | && aPrt->GetOrientation() != eOrientBefore) |
2374 | 0 | { |
2375 | 0 | aPrt->SetOrientation(eOrientBefore); |
2376 | 0 | } |
2377 | |
|
2378 | 0 | updatePageSize(mxOrientationBox->get_active()); |
2379 | |
|
2380 | 0 | schedulePreviewUpdate(false); |
2381 | 0 | } |
2382 | | |
2383 | | IMPL_LINK_NOARG(PrintDialog, MetricSpinModifyHdl, weld::MetricSpinButton&, void) |
2384 | 0 | { |
2385 | 0 | checkControlDependencies(); |
2386 | 0 | updateNupFromPages(); |
2387 | 0 | } |
2388 | | |
2389 | | IMPL_LINK_NOARG(PrintDialog, FocusOutHdl, weld::Widget&, void) |
2390 | 0 | { |
2391 | 0 | ActivateHdl(*mxPageEdit); |
2392 | 0 | } |
2393 | | |
2394 | | IMPL_LINK_NOARG(PrintDialog, ActivateHdl, weld::Entry&, bool) |
2395 | 0 | { |
2396 | 0 | sal_Int32 nPage = mxPageEdit->get_text().toInt32(); |
2397 | 0 | if (nPage < 1) |
2398 | 0 | { |
2399 | 0 | nPage = 1; |
2400 | 0 | mxPageEdit->set_text(u"1"_ustr); |
2401 | 0 | } |
2402 | 0 | else if (nPage > mnCachedPages) |
2403 | 0 | { |
2404 | 0 | nPage = mnCachedPages; |
2405 | 0 | mxPageEdit->set_text(OUString::number(mnCachedPages)); |
2406 | 0 | } |
2407 | 0 | int nNewCurPage = nPage - 1; |
2408 | 0 | if (nNewCurPage != mnCurPage) |
2409 | 0 | { |
2410 | 0 | mnCurPage = nNewCurPage; |
2411 | 0 | schedulePreviewUpdate(true); |
2412 | 0 | } |
2413 | 0 | return true; |
2414 | 0 | } |
2415 | | |
2416 | | IMPL_LINK( PrintDialog, SpinModifyHdl, weld::SpinButton&, rEdit, void ) |
2417 | 0 | { |
2418 | 0 | checkControlDependencies(); |
2419 | 0 | if (&rEdit == mxNupRowsEdt.get() || &rEdit == mxNupColEdt.get()) |
2420 | 0 | { |
2421 | 0 | updateNupFromPages(); |
2422 | 0 | } |
2423 | 0 | else if( &rEdit == mxCopyCountField.get() ) |
2424 | 0 | { |
2425 | 0 | maPController->setValue( u"CopyCount"_ustr, |
2426 | 0 | Any( sal_Int32(mxCopyCountField->get_value()) ) ); |
2427 | 0 | maPController->setValue( u"Collate"_ustr, |
2428 | 0 | Any( isCollate() ) ); |
2429 | 0 | } |
2430 | 0 | } |
2431 | | |
2432 | | IMPL_LINK( PrintDialog, UIOption_CheckHdl, weld::Toggleable&, i_rBox, void ) |
2433 | 0 | { |
2434 | 0 | PropertyValue* pVal = getValueForWindow( &i_rBox ); |
2435 | 0 | if( pVal ) |
2436 | 0 | { |
2437 | 0 | makeEnabled( &i_rBox ); |
2438 | |
|
2439 | 0 | bool bVal = i_rBox.get_active(); |
2440 | 0 | pVal->Value <<= bVal; |
2441 | |
|
2442 | 0 | checkOptionalControlDependencies(); |
2443 | | |
2444 | | // update preview and page settings |
2445 | 0 | schedulePreviewUpdate(false); |
2446 | 0 | } |
2447 | 0 | } |
2448 | | |
2449 | | IMPL_LINK( PrintDialog, UIOption_RadioHdl, weld::Toggleable&, i_rBtn, void ) |
2450 | 0 | { |
2451 | | // this handler gets called for all radiobuttons that get unchecked, too |
2452 | | // however we only want one notification for the new value (that is for |
2453 | | // the button that gets checked) |
2454 | 0 | if( !i_rBtn.get_active() ) |
2455 | 0 | return; |
2456 | | |
2457 | 0 | PropertyValue* pVal = getValueForWindow( &i_rBtn ); |
2458 | 0 | auto it = maControlToNumValMap.find( &i_rBtn ); |
2459 | 0 | if( !(pVal && it != maControlToNumValMap.end()) ) |
2460 | 0 | return; |
2461 | | |
2462 | 0 | makeEnabled( &i_rBtn ); |
2463 | |
|
2464 | 0 | sal_Int32 nVal = it->second; |
2465 | 0 | pVal->Value <<= nVal; |
2466 | | |
2467 | | // Writer-specific handling |
2468 | 0 | if (pVal->Name == "PrintContent") |
2469 | 0 | { |
2470 | 0 | PropertyValue* pPageRange = maPController->getValue(u"PageRange"_ustr); |
2471 | 0 | if (pPageRange) |
2472 | 0 | { |
2473 | 0 | if (nVal == 1) |
2474 | 0 | pPageRange->Value <<= mxPageRangeEdit->get_text(); |
2475 | 0 | else if (nVal == 3) |
2476 | 0 | pPageRange->Value <<= OUString::number(mnInitialPage); |
2477 | 0 | } |
2478 | 0 | } |
2479 | |
|
2480 | 0 | updateOrientationBox(); |
2481 | |
|
2482 | 0 | checkOptionalControlDependencies(); |
2483 | | |
2484 | | // tdf#41205 give focus to the page range edit if the corresponding radio button was selected |
2485 | 0 | if (pVal->Name == "PrintContent" && mxPageRangesRadioButton->get_active()) |
2486 | 0 | mxPageRangeEdit->grab_focus(); |
2487 | | |
2488 | | // update preview and page settings |
2489 | 0 | schedulePreviewUpdate(false); |
2490 | 0 | } |
2491 | | |
2492 | | IMPL_LINK( PrintDialog, UIOption_SelectHdl, weld::ComboBox&, i_rBox, void ) |
2493 | 0 | { |
2494 | 0 | PropertyValue* pVal = getValueForWindow( &i_rBox ); |
2495 | 0 | if( !pVal ) |
2496 | 0 | return; |
2497 | | |
2498 | 0 | makeEnabled( &i_rBox ); |
2499 | |
|
2500 | 0 | sal_Int32 nVal( i_rBox.get_active() ); |
2501 | 0 | pVal->Value <<= nVal; |
2502 | | |
2503 | | //If we are in impress we start in print slides mode and get a |
2504 | | //maFirstPageSize for slides which are usually landscape mode, if we |
2505 | | //change to notes which are usually in portrait mode, and then visit |
2506 | | //n-up print, we will assume notes are in landscape unless we throw |
2507 | | //away maFirstPageSize when we change page content type |
2508 | 0 | if (pVal->Name == "PageContentType") |
2509 | 0 | { |
2510 | 0 | maFirstPageSize = Size(); |
2511 | |
|
2512 | 0 | css::uno::Sequence<sal_Bool> aChoicesDisabled{ |
2513 | 0 | false, // Original size |
2514 | 0 | false, // Fit to printable page |
2515 | 0 | (nVal == 2) /*Notes*/ ? true : false, // disable/enable Multiple sheets of paper |
2516 | 0 | (nVal == 2) /*Notes*/ ? true : false // disable/enable Tile sheet of paper |
2517 | 0 | }; |
2518 | 0 | maPController->setUIChoicesDisabled(u"PageOptions"_ustr, aChoicesDisabled); |
2519 | 0 | } |
2520 | |
|
2521 | 0 | checkOptionalControlDependencies(); |
2522 | |
|
2523 | 0 | updatePageSize(mxOrientationBox->get_active()); |
2524 | | |
2525 | | // update preview and page settings |
2526 | 0 | schedulePreviewUpdate(false); |
2527 | 0 | } |
2528 | | |
2529 | | IMPL_LINK( PrintDialog, UIOption_SpinModifyHdl, weld::SpinButton&, i_rBox, void ) |
2530 | 0 | { |
2531 | 0 | PropertyValue* pVal = getValueForWindow( &i_rBox ); |
2532 | 0 | if( pVal ) |
2533 | 0 | { |
2534 | 0 | makeEnabled( &i_rBox ); |
2535 | |
|
2536 | 0 | sal_Int64 nVal = i_rBox.get_value(); |
2537 | 0 | pVal->Value <<= nVal; |
2538 | |
|
2539 | 0 | checkOptionalControlDependencies(); |
2540 | | |
2541 | | // update preview and page settings |
2542 | 0 | schedulePreviewUpdate(false); |
2543 | 0 | } |
2544 | 0 | } |
2545 | | |
2546 | | IMPL_LINK(PrintDialog, UIOption_EntryModifyHdl, weld::TextWidget&, i_rBox, void) |
2547 | 0 | { |
2548 | 0 | PropertyValue* pVal = getValueForWindow( &i_rBox ); |
2549 | 0 | if( pVal && mxPageRangesRadioButton->get_active() ) |
2550 | 0 | { |
2551 | 0 | makeEnabled( &i_rBox ); |
2552 | |
|
2553 | 0 | OUString aVal( i_rBox.get_text() ); |
2554 | 0 | pVal->Value <<= aVal; |
2555 | |
|
2556 | 0 | checkOptionalControlDependencies(); |
2557 | |
|
2558 | 0 | if (pVal->Name == "PageRange") |
2559 | 0 | maPageRangeUpdateTimer.Start(); |
2560 | 0 | else |
2561 | 0 | schedulePreviewUpdate(false); |
2562 | |
|
2563 | 0 | } |
2564 | 0 | } |
2565 | | |
2566 | | void PrintDialog::previewForward() |
2567 | 0 | { |
2568 | 0 | sal_Int32 nValue = mxPageEdit->get_text().toInt32() + 1; |
2569 | 0 | if (nValue <= mnCachedPages) |
2570 | 0 | { |
2571 | 0 | mxPageEdit->set_text(OUString::number(nValue)); |
2572 | 0 | ActivateHdl(*mxPageEdit); |
2573 | 0 | } |
2574 | 0 | } |
2575 | | |
2576 | | void PrintDialog::previewBackward() |
2577 | 0 | { |
2578 | 0 | sal_Int32 nValue = mxPageEdit->get_text().toInt32() - 1; |
2579 | 0 | if (nValue >= 1) |
2580 | 0 | { |
2581 | 0 | mxPageEdit->set_text(OUString::number(nValue)); |
2582 | 0 | ActivateHdl(*mxPageEdit); |
2583 | 0 | } |
2584 | 0 | } |
2585 | | |
2586 | | void PrintDialog::previewFirst() |
2587 | 0 | { |
2588 | 0 | mxPageEdit->set_text(u"1"_ustr); |
2589 | 0 | ActivateHdl(*mxPageEdit); |
2590 | 0 | } |
2591 | | |
2592 | | void PrintDialog::previewLast() |
2593 | 0 | { |
2594 | 0 | mxPageEdit->set_text(OUString::number(mnCachedPages)); |
2595 | 0 | ActivateHdl(*mxPageEdit); |
2596 | 0 | } |
2597 | | |
2598 | | |
2599 | | static OUString getNewLabel(const OUString& aLabel, int i_nCurr, int i_nMax) |
2600 | 0 | { |
2601 | 0 | OUString aNewText( aLabel.replaceFirst( "%p", OUString::number( i_nCurr ) ) ); |
2602 | 0 | aNewText = aNewText.replaceFirst( "%n", OUString::number( i_nMax ) ); |
2603 | |
|
2604 | 0 | return aNewText; |
2605 | 0 | } |
2606 | | |
2607 | | // PrintProgressDialog |
2608 | | PrintProgressDialog::PrintProgressDialog(weld::Window* i_pParent, int i_nMax) |
2609 | 0 | : GenericDialogController(i_pParent, u"vcl/ui/printprogressdialog.ui"_ustr, u"PrintProgressDialog"_ustr) |
2610 | 0 | , mbCanceled(false) |
2611 | 0 | , mnCur(0) |
2612 | 0 | , mnMax(i_nMax) |
2613 | 0 | , mxText(m_xBuilder->weld_label(u"label"_ustr)) |
2614 | 0 | , mxProgress(m_xBuilder->weld_progress_bar(u"progressbar"_ustr)) |
2615 | 0 | , mxButton(m_xBuilder->weld_button(u"cancel"_ustr)) |
2616 | 0 | { |
2617 | 0 | if( mnMax < 1 ) |
2618 | 0 | mnMax = 1; |
2619 | |
|
2620 | 0 | maStr = mxText->get_label(); |
2621 | | |
2622 | | //just multiply largest value by 10 and take the width of that string as |
2623 | | //the max size we will want |
2624 | 0 | mxText->set_label(getNewLabel(maStr, mnMax * 10, mnMax * 10)); |
2625 | 0 | mxText->set_size_request(mxText->get_preferred_size().Width(), -1); |
2626 | | |
2627 | | //Pick a useful max width |
2628 | 0 | mxProgress->set_size_request(mxProgress->get_approximate_digit_width() * 25, -1); |
2629 | |
|
2630 | 0 | mxButton->connect_clicked( LINK( this, PrintProgressDialog, ClickHdl ) ); |
2631 | | |
2632 | | // after this patch f7157f04fab298423e2c4f6a7e5f8e361164b15f, we have seen the calc Max string (sometimes) look above |
2633 | | // now init to the right start values |
2634 | 0 | mxText->set_label(getNewLabel(maStr, mnCur, mnMax)); |
2635 | 0 | } |
2636 | | |
2637 | | PrintProgressDialog::~PrintProgressDialog() |
2638 | 0 | { |
2639 | 0 | } |
2640 | | |
2641 | | IMPL_LINK_NOARG(PrintProgressDialog, ClickHdl, weld::Button&, void) |
2642 | 0 | { |
2643 | 0 | mbCanceled = true; |
2644 | 0 | } |
2645 | | |
2646 | | void PrintProgressDialog::setProgress( int i_nCurrent ) |
2647 | 0 | { |
2648 | 0 | mnCur = i_nCurrent; |
2649 | |
|
2650 | 0 | if( mnMax < 1 ) |
2651 | 0 | mnMax = 1; |
2652 | |
|
2653 | 0 | mxText->set_label(getNewLabel(maStr, mnCur, mnMax)); |
2654 | | |
2655 | | // here view the dialog, with the right label |
2656 | 0 | mxProgress->set_percentage(mnCur*100/mnMax); |
2657 | 0 | } |
2658 | | |
2659 | | void PrintProgressDialog::tick() |
2660 | 0 | { |
2661 | 0 | if( mnCur < mnMax ) |
2662 | 0 | setProgress( ++mnCur ); |
2663 | 0 | } |
2664 | | |
2665 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |