Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / gdi / print3.cxx
blob50b20930cf19f3764d004ffefbbb1844db5bc11d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/weld.hxx>
21 #include <vcl/print.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/metaact.hxx>
24 #include <vcl/configsettings.hxx>
25 #include <tools/urlobj.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <sal/types.h>
29 #include <sal/log.hxx>
30 #include <tools/debug.hxx>
32 #include <printdlg.hxx>
33 #include <svdata.hxx>
34 #include <salinst.hxx>
35 #include <salprn.hxx>
36 #include <strings.hrc>
38 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
39 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
40 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
41 #include <com/sun/star/view/DuplexMode.hpp>
42 #include <com/sun/star/lang/IllegalArgumentException.hpp>
43 #include <com/sun/star/awt/Size.hpp>
45 #include <unordered_map>
46 #include <unordered_set>
48 using namespace vcl;
50 class ImplPageCache
52 struct CacheEntry
54 GDIMetaFile aPage;
55 PrinterController::PageSize aSize;
58 std::vector< CacheEntry > maPages;
59 std::vector< sal_Int32 > maPageNumbers;
60 std::vector< sal_Int32 > maCacheRanking;
62 static const sal_Int32 nCacheSize = 6;
64 void updateRanking( sal_Int32 nLastHit )
66 if( maCacheRanking[0] != nLastHit )
68 for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
69 maCacheRanking[i] = maCacheRanking[i-1];
70 maCacheRanking[0] = nLastHit;
74 public:
75 ImplPageCache()
76 : maPages( nCacheSize )
77 , maPageNumbers( nCacheSize, -1 )
78 , maCacheRanking( nCacheSize )
80 for( sal_Int32 i = 0; i < nCacheSize; i++ )
81 maCacheRanking[i] = nCacheSize - i - 1;
84 // caution: does not ensure uniqueness
85 void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
87 sal_Int32 nReplacePage = maCacheRanking.back();
88 maPages[ nReplacePage ].aPage = i_rPage;
89 maPages[ nReplacePage ].aSize = i_rSize;
90 maPageNumbers[ nReplacePage ] = i_nPageNo;
91 // cache insertion means in our case, the page was just queried
92 // so update the ranking
93 updateRanking( nReplacePage );
96 // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
97 // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
98 // whole pages can be rather memory intensive
99 bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
101 for( sal_Int32 i = 0; i < nCacheSize; ++i )
103 if( maPageNumbers[i] == i_nPageNo )
105 updateRanking( i );
106 o_rPageFile = maPages[i].aPage;
107 o_rSize = maPages[i].aSize;
108 return true;
111 return false;
114 void invalidate()
116 for( sal_Int32 i = 0; i < nCacheSize; ++i )
118 maPageNumbers[i] = -1;
119 maPages[i].aPage.Clear();
120 maCacheRanking[i] = nCacheSize - i - 1;
125 class vcl::ImplPrinterControllerData
127 public:
128 struct ControlDependency
130 OUString maDependsOnName;
131 sal_Int32 mnDependsOnEntry;
133 ControlDependency() : mnDependsOnEntry( -1 ) {}
136 typedef std::unordered_map< OUString, size_t > PropertyToIndexMap;
137 typedef std::unordered_map< OUString, ControlDependency > ControlDependencyMap;
138 typedef std::unordered_map< OUString, css::uno::Sequence< sal_Bool > > ChoiceDisableMap;
140 VclPtr< Printer > mxPrinter;
141 weld::Window* mpWindow;
142 css::uno::Sequence< css::beans::PropertyValue > maUIOptions;
143 std::vector< css::beans::PropertyValue > maUIProperties;
144 std::vector< bool > maUIPropertyEnabled;
145 PropertyToIndexMap maPropertyToIndex;
146 ControlDependencyMap maControlDependencies;
147 ChoiceDisableMap maChoiceDisableMap;
148 bool mbFirstPage;
149 bool mbLastPage;
150 bool mbReversePageOrder;
151 bool mbPapersizeFromSetup;
152 bool mbPapersizeFromUser;
153 bool mbPrinterModified;
154 css::view::PrintableState meJobState;
156 vcl::PrinterController::MultiPageSetup maMultiPage;
158 std::shared_ptr<vcl::PrintProgressDialog> mxProgress;
160 ImplPageCache maPageCache;
162 // set by user through printer properties subdialog of printer settings dialog
163 Size maDefaultPageSize;
164 // set by user through print dialog
165 Size maUserPageSize;
166 // set by user through printer properties subdialog of printer settings dialog
167 sal_Int32 mnDefaultPaperBin;
168 // Set by user through printer properties subdialog of print dialog.
169 // Overrides application-set tray for a page.
170 sal_Int32 mnFixedPaperBin;
172 // N.B. Apparently we have three levels of paper tray settings
173 // (latter overrides former):
174 // 1. default tray
175 // 2. tray set for a concrete page by an application, e.g., writer
176 // allows setting a printer tray (for the default printer) for a
177 // page style. This setting can be overridden by user by selecting
178 // "Use only paper tray from printer preferences" on the Options
179 // page in the print dialog, in which case the default tray is
180 // used for all pages.
181 // 3. tray set in printer properties the printer dialog
182 // I'm not quite sure why 1. and 3. are distinct, but the commit
183 // history suggests this is intentional...
185 ImplPrinterControllerData() :
186 mpWindow( nullptr ),
187 mbFirstPage( true ),
188 mbLastPage( false ),
189 mbReversePageOrder( false ),
190 mbPapersizeFromSetup( false ),
191 mbPapersizeFromUser( false ),
192 mbPrinterModified( false ),
193 meJobState( css::view::PrintableState_JOB_STARTED ),
194 mnDefaultPaperBin( -1 ),
195 mnFixedPaperBin( -1 )
198 ~ImplPrinterControllerData()
200 if (mxProgress)
202 mxProgress->response(RET_CANCEL);
203 mxProgress.reset();
207 const Size& getRealPaperSize( const Size& i_rPageSize, bool bNoNUP ) const
209 if ( mbPapersizeFromUser )
210 return maUserPageSize;
211 if( mbPapersizeFromSetup )
212 return maDefaultPageSize;
213 if( maMultiPage.nRows * maMultiPage.nColumns > 1 && ! bNoNUP )
214 return maMultiPage.aPaperSize;
215 return i_rPageSize;
217 bool isFixedPageSize() const
218 { return mbPapersizeFromSetup; }
219 PrinterController::PageSize modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps );
220 void resetPaperToLastConfigured();
223 PrinterController::PrinterController(const VclPtr<Printer>& i_xPrinter, weld::Window* i_pWindow)
224 : mpImplData( new ImplPrinterControllerData )
226 mpImplData->mxPrinter = i_xPrinter;
227 mpImplData->mpWindow = i_pWindow;
230 static OUString queryFile( Printer const * pPrinter )
232 OUString aResult;
234 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
235 css::uno::Reference< css::ui::dialogs::XFilePicker3 > xFilePicker = css::ui::dialogs::FilePicker::createWithMode(xContext, css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION);
239 #ifdef UNX
240 // add PostScript and PDF
241 bool bPS = true, bPDF = true;
242 if( pPrinter )
244 if( pPrinter->GetCapabilities( PrinterCapType::PDF ) )
245 bPS = false;
246 else
247 bPDF = false;
249 if( bPS )
250 xFilePicker->appendFilter( "PostScript", "*.ps" );
251 if( bPDF )
252 xFilePicker->appendFilter( "Portable Document Format", "*.pdf" );
253 #elif defined WNT
254 (void)pPrinter;
255 xFilePicker->appendFilter( "*.PRN", "*.prn" );
256 #endif
257 // add arbitrary files
258 xFilePicker->appendFilter(VclResId(SV_STDTEXT_ALLFILETYPES), "*.*");
260 catch (const css::lang::IllegalArgumentException&)
262 SAL_WARN( "vcl.gdi", "caught IllegalArgumentException when registering filter" );
265 if( xFilePicker->execute() == css::ui::dialogs::ExecutableDialogResults::OK )
267 css::uno::Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
268 INetURLObject aObj( aPathSeq[0] );
269 aResult = aObj.PathToFileName();
271 return aResult;
274 struct PrintJobAsync
276 std::shared_ptr<PrinterController> mxController;
277 JobSetup const maInitSetup;
279 PrintJobAsync(const std::shared_ptr<PrinterController>& i_xController,
280 const JobSetup& i_rInitSetup)
281 : mxController( i_xController ), maInitSetup( i_rInitSetup )
284 DECL_LINK( ExecJob, void*, void );
287 IMPL_LINK_NOARG(PrintJobAsync, ExecJob, void*, void)
289 Printer::ImplPrintJob(mxController, maInitSetup);
291 // clean up, do not access members after this
292 delete this;
295 void Printer::PrintJob(const std::shared_ptr<PrinterController>& i_xController,
296 const JobSetup& i_rInitSetup)
298 bool bSynchronous = false;
299 css::beans::PropertyValue* pVal = i_xController->getValue( "Wait" );
300 if( pVal )
301 pVal->Value >>= bSynchronous;
303 if( bSynchronous )
304 ImplPrintJob(i_xController, i_rInitSetup);
305 else
307 PrintJobAsync* pAsync = new PrintJobAsync(i_xController, i_rInitSetup);
308 Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) );
312 bool Printer::PreparePrintJob(std::shared_ptr<PrinterController> xController,
313 const JobSetup& i_rInitSetup)
315 // check if there is a default printer; if not, show an error box (if appropriate)
316 if( GetDefaultPrinterName().isEmpty() )
318 if (xController->isShowDialogs())
320 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(xController->getWindow(), "vcl/ui/errornoprinterdialog.ui"));
321 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorNoPrinterDialog"));
322 xBox->run();
324 xController->setValue( "IsDirect",
325 css::uno::makeAny( false ) );
328 // setup printer
330 // #i114306# changed behavior back from persistence
331 // if no specific printer is already set, create the default printer
332 if (!xController->getPrinter())
334 OUString aPrinterName( i_rInitSetup.GetPrinterName() );
335 VclPtrInstance<Printer> xPrinter( aPrinterName );
336 xPrinter->SetJobSetup(i_rInitSetup);
337 xController->setPrinter(xPrinter);
338 xController->setPapersizeFromSetup(xPrinter->GetPrinterSettingsPreferred());
341 // reset last page property
342 xController->setLastPage(false);
344 // update "PageRange" property inferring from other properties:
345 // case 1: "Pages" set from UNO API ->
346 // setup "Print Selection" and insert "PageRange" attribute
347 // case 2: "All pages" is selected
348 // update "Page range" attribute to have a sensible default,
349 // but leave "All" as selected
351 // "Pages" attribute from API is now equivalent to "PageRange"
352 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
353 // Argh ! That sure needs cleaning up
354 css::beans::PropertyValue* pContentVal = xController->getValue("PrintRange");
355 if( ! pContentVal )
356 pContentVal = xController->getValue("PrintContent");
358 // case 1: UNO API has set "Pages"
359 css::beans::PropertyValue* pPagesVal = xController->getValue("Pages");
360 if( pPagesVal )
362 OUString aPagesVal;
363 pPagesVal->Value >>= aPagesVal;
364 if( !aPagesVal.isEmpty() )
366 // "Pages" attribute from API is now equivalent to "PageRange"
367 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
368 // Argh ! That sure needs cleaning up
369 if( pContentVal )
371 pContentVal->Value <<= sal_Int32( 1 );
372 xController->setValue("PageRange", pPagesVal->Value);
376 // case 2: is "All" selected ?
377 else if( pContentVal )
379 sal_Int32 nContent = -1;
380 if( pContentVal->Value >>= nContent )
382 if( nContent == 0 )
384 // do not overwrite PageRange if it is already set
385 css::beans::PropertyValue* pRangeVal = xController->getValue("PageRange");
386 OUString aRange;
387 if( pRangeVal )
388 pRangeVal->Value >>= aRange;
389 if( aRange.isEmpty() )
391 sal_Int32 nPages = xController->getPageCount();
392 if( nPages > 0 )
394 OUStringBuffer aBuf( 32 );
395 aBuf.append( "1" );
396 if( nPages > 1 )
398 aBuf.append( "-" );
399 aBuf.append( nPages );
401 xController->setValue("PageRange", css::uno::makeAny(aBuf.makeStringAndClear()));
408 css::beans::PropertyValue* pReverseVal = xController->getValue("PrintReverse");
409 if( pReverseVal )
411 bool bReverse = false;
412 pReverseVal->Value >>= bReverse;
413 xController->setReversePrint( bReverse );
416 css::beans::PropertyValue* pPapersizeFromSetupVal = xController->getValue("PapersizeFromSetup");
417 if( pPapersizeFromSetupVal )
419 bool bPapersizeFromSetup = false;
420 pPapersizeFromSetupVal->Value >>= bPapersizeFromSetup;
421 xController->setPapersizeFromSetup(bPapersizeFromSetup);
424 // setup NUp printing from properties
425 sal_Int32 nRows = xController->getIntProperty("NUpRows", 1);
426 sal_Int32 nCols = xController->getIntProperty("NUpColumns", 1);
427 if( nRows > 1 || nCols > 1 )
429 PrinterController::MultiPageSetup aMPS;
430 aMPS.nRows = std::max<sal_Int32>(nRows, 1);
431 aMPS.nColumns = std::max<sal_Int32>(nCols, 1);
432 sal_Int32 nValue = xController->getIntProperty("NUpPageMarginLeft", aMPS.nLeftMargin);
433 if( nValue >= 0 )
434 aMPS.nLeftMargin = nValue;
435 nValue = xController->getIntProperty("NUpPageMarginRight", aMPS.nRightMargin);
436 if( nValue >= 0 )
437 aMPS.nRightMargin = nValue;
438 nValue = xController->getIntProperty( "NUpPageMarginTop", aMPS.nTopMargin );
439 if( nValue >= 0 )
440 aMPS.nTopMargin = nValue;
441 nValue = xController->getIntProperty( "NUpPageMarginBottom", aMPS.nBottomMargin );
442 if( nValue >= 0 )
443 aMPS.nBottomMargin = nValue;
444 nValue = xController->getIntProperty( "NUpHorizontalSpacing", aMPS.nHorizontalSpacing );
445 if( nValue >= 0 )
446 aMPS.nHorizontalSpacing = nValue;
447 nValue = xController->getIntProperty( "NUpVerticalSpacing", aMPS.nVerticalSpacing );
448 if( nValue >= 0 )
449 aMPS.nVerticalSpacing = nValue;
450 aMPS.bDrawBorder = xController->getBoolProperty( "NUpDrawBorder", aMPS.bDrawBorder );
451 aMPS.nOrder = static_cast<NupOrderType>(xController->getIntProperty( "NUpSubPageOrder", static_cast<sal_Int32>(aMPS.nOrder) ));
452 aMPS.aPaperSize = xController->getPrinter()->PixelToLogic( xController->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) );
453 css::beans::PropertyValue* pPgSizeVal = xController->getValue( "NUpPaperSize" );
454 css::awt::Size aSizeVal;
455 if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
457 aMPS.aPaperSize.setWidth( aSizeVal.Width );
458 aMPS.aPaperSize.setHeight( aSizeVal.Height );
461 xController->setMultipage( aMPS );
464 // in direct print case check whether there is anything to print.
465 // if not, show an errorbox (if appropriate)
466 if( xController->isShowDialogs() && xController->isDirectPrint() )
468 if( xController->getFilteredPageCount() == 0 )
470 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(xController->getWindow(), "vcl/ui/errornocontentdialog.ui"));
471 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorNoContentDialog"));
472 xBox->run();
473 return false;
477 // check if the printer brings up its own dialog
478 // in that case leave the work to that dialog
479 if( ! xController->getPrinter()->GetCapabilities( PrinterCapType::ExternalDialog ) &&
480 ! xController->isDirectPrint() &&
481 xController->isShowDialogs()
486 PrintDialog aDlg(xController->getWindow(), xController);
487 if (!aDlg.run())
489 xController->abortJob();
490 return false;
492 if (aDlg.isPrintToFile())
494 OUString aFile = queryFile( xController->getPrinter().get() );
495 if( aFile.isEmpty() )
497 xController->abortJob();
498 return false;
500 xController->setValue( "LocalFileName",
501 css::uno::makeAny( aFile ) );
503 else if (aDlg.isSingleJobs())
505 xController->setValue( "PrintCollateAsSingleJobs",
506 css::uno::makeAny( true ) );
509 catch (const std::bad_alloc&)
514 xController->pushPropertiesToPrinter();
515 return true;
518 bool Printer::ExecutePrintJob(const std::shared_ptr<PrinterController>& xController)
520 OUString aJobName;
521 css::beans::PropertyValue* pJobNameVal = xController->getValue( "JobName" );
522 if( pJobNameVal )
523 pJobNameVal->Value >>= aJobName;
525 return xController->getPrinter()->StartJob( aJobName, xController );
528 void Printer::FinishPrintJob(const std::shared_ptr<PrinterController>& xController)
530 xController->resetPaperToLastConfigured();
531 xController->jobFinished( xController->getJobState() );
534 void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& xController,
535 const JobSetup& i_rInitSetup)
537 if (PreparePrintJob(xController, i_rInitSetup))
539 ExecutePrintJob(xController);
541 FinishPrintJob(xController);
544 bool Printer::StartJob( const OUString& i_rJobName, std::shared_ptr<vcl::PrinterController> const & i_xController)
546 mnError = ERRCODE_NONE;
548 if ( IsDisplayPrinter() )
549 return false;
551 if ( IsJobActive() || IsPrinting() )
552 return false;
554 sal_uInt32 nCopies = mnCopyCount;
555 bool bCollateCopy = mbCollateCopy;
556 bool bUserCopy = false;
558 if ( nCopies > 1 )
560 const sal_uInt32 nDevCopy = GetCapabilities( bCollateCopy
561 ? PrinterCapType::CollateCopies
562 : PrinterCapType::Copies );
564 // need to do copies by hand ?
565 if ( nCopies > nDevCopy )
567 bUserCopy = true;
568 nCopies = 1;
569 bCollateCopy = false;
572 else
573 bCollateCopy = false;
575 ImplSVData* pSVData = ImplGetSVData();
576 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
578 if (!mpPrinter)
579 return false;
581 bool bSinglePrintJobs = false;
582 css::beans::PropertyValue* pSingleValue = i_xController->getValue("PrintCollateAsSingleJobs");
583 if( pSingleValue )
585 pSingleValue->Value >>= bSinglePrintJobs;
588 css::beans::PropertyValue* pFileValue = i_xController->getValue("LocalFileName");
589 if( pFileValue )
591 OUString aFile;
592 pFileValue->Value >>= aFile;
593 if( !aFile.isEmpty() )
595 mbPrintFile = true;
596 maPrintFile = aFile;
597 bSinglePrintJobs = false;
601 OUString* pPrintFile = nullptr;
602 if ( mbPrintFile )
603 pPrintFile = &maPrintFile;
604 mpPrinterOptions->ReadFromConfig( mbPrintFile );
606 mbPrinting = true;
607 if( GetCapabilities( PrinterCapType::UsePullModel ) )
609 mbJobActive = true;
610 // SAL layer does all necessary page printing
611 // and also handles showing a dialog
612 // that also means it must call jobStarted when the dialog is finished
613 // it also must set the JobState of the Controller
614 if( mpPrinter->StartJob( pPrintFile,
615 i_rJobName,
616 Application::GetDisplayName(),
617 &maJobSetup.ImplGetData(),
618 *i_xController) )
620 EndJob();
622 else
624 mnError = ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode());
625 if ( !mnError )
626 mnError = PRINTER_GENERALERROR;
627 mbPrinting = false;
628 mpPrinter.reset();
629 mbJobActive = false;
631 GDIMetaFile aDummyFile;
632 i_xController->setLastPage(true);
633 i_xController->getFilteredPageFile(0, aDummyFile);
635 return false;
638 else
640 // possibly a dialog has been shown
641 // now the real job starts
642 i_xController->setJobState( css::view::PrintableState_JOB_STARTED );
643 i_xController->jobStarted();
645 int nJobs = 1;
646 int nOuterRepeatCount = 1;
647 int nInnerRepeatCount = 1;
648 if( bUserCopy )
650 if( mbCollateCopy )
651 nOuterRepeatCount = mnCopyCount;
652 else
653 nInnerRepeatCount = mnCopyCount;
655 if( bSinglePrintJobs )
657 nJobs = mnCopyCount;
658 nCopies = 1;
659 nOuterRepeatCount = nInnerRepeatCount = 1;
662 for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
664 bool bError = false;
665 if( mpPrinter->StartJob( pPrintFile,
666 i_rJobName,
667 Application::GetDisplayName(),
668 nCopies,
669 bCollateCopy,
670 i_xController->isDirectPrint(),
671 &maJobSetup.ImplGetData() ) )
673 bool bAborted = false;
674 mbJobActive = true;
675 i_xController->createProgressDialog();
676 const int nPages = i_xController->getFilteredPageCount();
677 // abort job, if no pages will be printed.
678 if ( nPages == 0 )
680 i_xController->abortJob();
681 bAborted = true;
683 for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ )
685 for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ )
687 for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ )
689 if( nPage == nPages-1 &&
690 nOuterIteration == nOuterRepeatCount-1 &&
691 nInnerIteration == nInnerRepeatCount-1 &&
692 nJobIteration == nJobs-1 )
694 i_xController->setLastPage(true);
696 i_xController->printFilteredPage(nPage);
697 if (i_xController->isProgressCanceled())
699 i_xController->abortJob();
701 if (i_xController->getJobState() ==
702 css::view::PrintableState_JOB_ABORTED)
704 bAborted = true;
708 // FIXME: duplex ?
710 EndJob();
712 if( nJobIteration < nJobs-1 )
714 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
716 if ( mpPrinter )
717 mbPrinting = true;
718 else
719 bError = true;
722 else
723 bError = true;
725 if( bError )
727 mnError = mpPrinter ? ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode()) : ERRCODE_NONE;
728 if ( !mnError )
729 mnError = PRINTER_GENERALERROR;
730 i_xController->setJobState( mnError == PRINTER_ABORT
731 ? css::view::PrintableState_JOB_ABORTED
732 : css::view::PrintableState_JOB_FAILED );
733 mbPrinting = false;
734 mpPrinter.reset();
736 return false;
740 if (i_xController->getJobState() == css::view::PrintableState_JOB_STARTED)
741 i_xController->setJobState(css::view::PrintableState_JOB_SPOOLED);
744 // make last used printer persistent for UI jobs
745 if (i_xController->isShowDialogs() && !i_xController->isDirectPrint())
747 SettingsConfigItem* pItem = SettingsConfigItem::get();
748 pItem->setValue( "PrintDialog",
749 "LastPrinterUsed",
750 GetName()
754 return true;
757 PrinterController::~PrinterController()
761 css::view::PrintableState PrinterController::getJobState() const
763 return mpImplData->meJobState;
766 void PrinterController::setJobState( css::view::PrintableState i_eState )
768 mpImplData->meJobState = i_eState;
771 const VclPtr<Printer>& PrinterController::getPrinter() const
773 return mpImplData->mxPrinter;
776 weld::Window* PrinterController::getWindow() const
778 return mpImplData->mpWindow;
781 void PrinterController::setPrinter( const VclPtr<Printer>& i_rPrinter )
783 mpImplData->mxPrinter = i_rPrinter;
784 setValue( "Name",
785 css::uno::makeAny( i_rPrinter->GetName() ) );
786 mpImplData->mnDefaultPaperBin = mpImplData->mxPrinter->GetPaperBin();
787 mpImplData->mxPrinter->Push();
788 mpImplData->mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
789 mpImplData->maDefaultPageSize = mpImplData->mxPrinter->GetPaperSize();
790 mpImplData->mbPapersizeFromUser = false;
791 mpImplData->mxPrinter->Pop();
792 mpImplData->mnFixedPaperBin = -1;
795 void PrinterController::resetPrinterOptions( bool i_bFileOutput )
797 PrinterOptions aOpt;
798 aOpt.ReadFromConfig( i_bFileOutput );
799 mpImplData->mxPrinter->SetPrinterOptions( aOpt );
802 void PrinterController::setupPrinter( weld::Window* i_pParent )
804 bool bRet = false;
806 // Important to hold printer alive while doing setup etc.
807 VclPtr< Printer > xPrinter = mpImplData->mxPrinter;
809 if( xPrinter.get() )
811 xPrinter->Push();
812 xPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
814 // get current data
815 Size aPaperSize(xPrinter->GetPaperSize());
816 Orientation eOrientation = xPrinter->GetOrientation();
817 sal_uInt16 nPaperBin = xPrinter->GetPaperBin();
819 // reset paper size back to last configured size, not
820 // whatever happens to be the current page
821 // (but only if the printer config has changed, otherwise
822 // don't override printer page auto-detection - tdf#91362)
823 if (getPrinterModified() || getPapersizeFromSetup())
825 resetPaperToLastConfigured();
828 // call driver setup
829 bRet = xPrinter->Setup( i_pParent, PrinterSetupMode::SingleJob );
830 SAL_WARN_IF(xPrinter != mpImplData->mxPrinter, "vcl.gdi",
831 "Printer changed underneath us during setup");
832 xPrinter = mpImplData->mxPrinter;
834 Size aNewPaperSize(xPrinter->GetPaperSize());
835 if (bRet)
837 bool bInvalidateCache = false;
838 setPapersizeFromSetup(xPrinter->GetPrinterSettingsPreferred());
840 // was papersize overridden ? if so we need to take action if we're
841 // configured to use the driver papersize
842 if (aNewPaperSize != mpImplData->maDefaultPageSize)
844 mpImplData->maDefaultPageSize = aNewPaperSize;
845 bInvalidateCache = getPapersizeFromSetup();
848 // was bin overridden ? if so we need to take action
849 sal_uInt16 nNewPaperBin = xPrinter->GetPaperBin();
850 if (nNewPaperBin != nPaperBin)
852 mpImplData->mnFixedPaperBin = nNewPaperBin;
853 bInvalidateCache = true;
856 if (bInvalidateCache)
858 mpImplData->maPageCache.invalidate();
861 else
863 //restore to whatever it was before we entered this method
864 xPrinter->SetOrientation( eOrientation );
865 if (aPaperSize != aNewPaperSize)
866 xPrinter->SetPaperSizeUser(aPaperSize, !mpImplData->isFixedPageSize());
868 xPrinter->Pop();
872 PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps )
874 PrinterController::PageSize aPageSize;
875 aPageSize.aSize = mxPrinter->GetPaperSize();
876 css::awt::Size aSetSize, aIsSize;
877 sal_Int32 nPaperBin = mnDefaultPaperBin;
878 for( const auto& rProp : i_rProps )
880 if ( rProp.Name == "PreferredPageSize" )
882 rProp.Value >>= aSetSize;
884 else if ( rProp.Name == "PageSize" )
886 rProp.Value >>= aIsSize;
888 else if ( rProp.Name == "PageIncludesNonprintableArea" )
890 bool bVal = false;
891 rProp.Value >>= bVal;
892 aPageSize.bFullPaper = bVal;
894 else if ( rProp.Name == "PrinterPaperTray" )
896 sal_Int32 nBin = -1;
897 rProp.Value >>= nBin;
898 if( nBin >= 0 && nBin < static_cast<sal_Int32>(mxPrinter->GetPaperBinCount()) )
899 nPaperBin = nBin;
903 Size aCurSize( mxPrinter->GetPaperSize() );
904 if( aSetSize.Width && aSetSize.Height )
906 Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
907 Size aRealPaperSize( getRealPaperSize( aSetPaperSize, true/*bNoNUP*/ ) );
908 if( aRealPaperSize != aCurSize )
909 aIsSize = aSetSize;
912 if( aIsSize.Width && aIsSize.Height )
914 aPageSize.aSize.setWidth( aIsSize.Width );
915 aPageSize.aSize.setHeight( aIsSize.Height );
917 Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, true/*bNoNUP*/ ) );
918 if( aRealPaperSize != aCurSize )
919 mxPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() );
922 // paper bin set from properties in print dialog overrides
923 // application default for a page
924 if ( mnFixedPaperBin != -1 )
925 nPaperBin = mnFixedPaperBin;
927 if( nPaperBin != -1 && nPaperBin != mxPrinter->GetPaperBin() )
928 mxPrinter->SetPaperBin( nPaperBin );
930 return aPageSize;
933 //fdo#61886
935 //when printing is finished, set the paper size of the printer to either what
936 //the user explicitly set as the desired paper size, or fallback to whatever
937 //the printer had before printing started. That way it doesn't contain the last
938 //paper size of a multiple paper size using document when we are in our normal
939 //auto accept document paper size mode and end up overwriting the original
940 //paper size setting for file->printer_settings just by pressing "ok" in the
941 //print dialog
942 void vcl::ImplPrinterControllerData::resetPaperToLastConfigured()
944 mxPrinter->Push();
945 mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
946 Size aCurSize(mxPrinter->GetPaperSize());
947 if (aCurSize != maDefaultPageSize)
948 mxPrinter->SetPaperSizeUser(maDefaultPageSize, !isFixedPageSize());
949 mxPrinter->Pop();
952 int PrinterController::getPageCountProtected() const
954 const MapMode aMapMode( MapUnit::Map100thMM );
956 mpImplData->mxPrinter->Push();
957 mpImplData->mxPrinter->SetMapMode( aMapMode );
958 int nPages = getPageCount();
959 mpImplData->mxPrinter->Pop();
960 return nPages;
963 css::uno::Sequence< css::beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
965 const MapMode aMapMode( MapUnit::Map100thMM );
967 mpImplData->mxPrinter->Push();
968 mpImplData->mxPrinter->SetMapMode( aMapMode );
969 css::uno::Sequence< css::beans::PropertyValue > aResult( getPageParameters( i_nPage ) );
970 mpImplData->mxPrinter->Pop();
971 return aResult;
974 PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
976 // update progress if necessary
977 if( mpImplData->mxProgress )
979 // do nothing if printing is canceled
980 if( mpImplData->mxProgress->isCanceled() )
981 return PrinterController::PageSize();
982 mpImplData->mxProgress->tick();
983 Application::Reschedule( true );
986 if( i_bMayUseCache )
988 PrinterController::PageSize aPageSize;
989 if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
991 return aPageSize;
994 else
995 mpImplData->maPageCache.invalidate();
997 o_rMtf.Clear();
999 // get page parameters
1000 css::uno::Sequence< css::beans::PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
1001 const MapMode aMapMode( MapUnit::Map100thMM );
1003 mpImplData->mxPrinter->Push();
1004 mpImplData->mxPrinter->SetMapMode( aMapMode );
1006 // modify job setup if necessary
1007 PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm );
1009 o_rMtf.SetPrefSize( aPageSize.aSize );
1010 o_rMtf.SetPrefMapMode( aMapMode );
1012 mpImplData->mxPrinter->EnableOutput( false );
1014 o_rMtf.Record( mpImplData->mxPrinter.get() );
1016 printPage( i_nUnfilteredPage );
1018 o_rMtf.Stop();
1019 o_rMtf.WindStart();
1020 mpImplData->mxPrinter->Pop();
1022 if( i_bMayUseCache )
1023 mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
1025 // reset "FirstPage" property to false now we've gotten at least our first one
1026 mpImplData->mbFirstPage = false;
1028 return aPageSize;
1031 static void appendSubPage( GDIMetaFile& o_rMtf, const tools::Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
1033 // intersect all clipregion actions with our clip rect
1034 io_rSubPage.WindStart();
1035 io_rSubPage.Clip( i_rClipRect );
1037 // save gstate
1038 o_rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1040 // clip to page rect
1041 o_rMtf.AddAction( new MetaClipRegionAction( vcl::Region( i_rClipRect ), true ) );
1043 // append the subpage
1044 io_rSubPage.WindStart();
1045 io_rSubPage.Play( o_rMtf );
1047 // restore gstate
1048 o_rMtf.AddAction( new MetaPopAction() );
1050 // draw a border
1051 if( i_bDrawBorder )
1053 // save gstate
1054 o_rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::CLIPREGION | PushFlags::MAPMODE ) );
1055 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1057 tools::Rectangle aBorderRect( i_rClipRect );
1058 o_rMtf.AddAction( new MetaLineColorAction( COL_BLACK, true ) );
1059 o_rMtf.AddAction( new MetaFillColorAction( COL_TRANSPARENT, false ) );
1060 o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
1062 // restore gstate
1063 o_rMtf.AddAction( new MetaPopAction() );
1067 PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
1069 const MultiPageSetup& rMPS( mpImplData->maMultiPage );
1070 int nSubPages = rMPS.nRows * rMPS.nColumns;
1071 if( nSubPages < 1 )
1072 nSubPages = 1;
1074 // reverse sheet order
1075 if( mpImplData->mbReversePageOrder )
1077 int nDocPages = getFilteredPageCount();
1078 i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
1081 // there is no filtering to be done (and possibly the page size of the
1082 // original page is to be set), when N-Up is "neutral" that is there is
1083 // only one subpage and the margins are 0
1084 if( nSubPages == 1 &&
1085 rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
1086 rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
1088 PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
1089 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1090 { // rhbz#657394: check that we are still printing...
1091 return PrinterController::PageSize();
1093 Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true );
1094 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1095 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1096 if( aPaperSize != aPageSize.aSize )
1098 // user overridden page size, center Metafile
1099 o_rMtf.WindStart();
1100 long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
1101 long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
1102 o_rMtf.Move( nDX, nDY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1103 o_rMtf.WindStart();
1104 o_rMtf.SetPrefSize( aPaperSize );
1105 aPageSize.aSize = aPaperSize;
1107 return aPageSize;
1110 // set last page property really only on the very last page to be rendered
1111 // that is on the last subpage of a NUp run
1112 bool bIsLastPage = mpImplData->mbLastPage;
1113 mpImplData->mbLastPage = false;
1115 Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) );
1117 // multi page area: page size minus margins + one time spacing right and down
1118 // the added spacing is so each subpage can be calculated including its spacing
1119 Size aMPArea( aPaperSize );
1120 aMPArea.AdjustWidth( -(rMPS.nLeftMargin + rMPS.nRightMargin) );
1121 aMPArea.AdjustWidth(rMPS.nHorizontalSpacing );
1122 aMPArea.AdjustHeight( -(rMPS.nTopMargin + rMPS.nBottomMargin) );
1123 aMPArea.AdjustHeight(rMPS.nVerticalSpacing );
1125 // determine offsets
1126 long nAdvX = aMPArea.Width() / rMPS.nColumns;
1127 long nAdvY = aMPArea.Height() / rMPS.nRows;
1129 // determine size of a "cell" subpage, leave a little space around pages
1130 Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
1132 o_rMtf.Clear();
1133 o_rMtf.SetPrefSize( aPaperSize );
1134 o_rMtf.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
1135 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1137 int nDocPages = getPageCountProtected();
1138 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1139 { // rhbz#657394: check that we are still printing...
1140 return PrinterController::PageSize();
1142 for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
1144 // map current sub page to real page
1145 int nPage = i_nFilteredPage * nSubPages + nSubPage;
1146 if( nSubPage == nSubPages-1 ||
1147 nPage == nDocPages-1 )
1149 mpImplData->mbLastPage = bIsLastPage;
1151 if( nPage >= 0 && nPage < nDocPages )
1153 GDIMetaFile aPageFile;
1154 PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
1155 if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
1157 long nCellX = 0, nCellY = 0;
1158 switch( rMPS.nOrder )
1160 case NupOrderType::LRTB:
1161 nCellX = (nSubPage % rMPS.nColumns);
1162 nCellY = (nSubPage / rMPS.nColumns);
1163 break;
1164 case NupOrderType::TBLR:
1165 nCellX = (nSubPage / rMPS.nRows);
1166 nCellY = (nSubPage % rMPS.nRows);
1167 break;
1168 case NupOrderType::RLTB:
1169 nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns);
1170 nCellY = (nSubPage / rMPS.nColumns);
1171 break;
1172 case NupOrderType::TBRL:
1173 nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows);
1174 nCellY = (nSubPage % rMPS.nRows);
1175 break;
1177 // scale the metafile down to a sub page size
1178 double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
1179 double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
1180 double fScale = std::min( fScaleX, fScaleY );
1181 aPageFile.Scale( fScale, fScale );
1182 aPageFile.WindStart();
1184 // move the subpage so it is centered in its "cell"
1185 long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
1186 long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
1187 long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
1188 long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
1189 aPageFile.Move( nX, nY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1190 aPageFile.WindStart();
1191 // calculate border rectangle
1192 tools::Rectangle aSubPageRect( Point( nX, nY ),
1193 Size( long(double(aPageSize.aSize.Width())*fScale),
1194 long(double(aPageSize.aSize.Height())*fScale) ) );
1196 // append subpage to page
1197 appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
1201 o_rMtf.WindStart();
1203 // subsequent getPageFile calls have changed the paper, reset it to current value
1204 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1205 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1207 return PrinterController::PageSize( aPaperSize, true );
1210 int PrinterController::getFilteredPageCount() const
1212 int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
1213 if( nDiv < 1 )
1214 nDiv = 1;
1215 return (getPageCountProtected() + (nDiv-1)) / nDiv;
1218 DrawModeFlags PrinterController::removeTransparencies( GDIMetaFile const & i_rIn, GDIMetaFile& o_rOut )
1220 DrawModeFlags nRestoreDrawMode = mpImplData->mxPrinter->GetDrawMode();
1221 sal_Int32 nMaxBmpDPIX = mpImplData->mxPrinter->GetDPIX();
1222 sal_Int32 nMaxBmpDPIY = mpImplData->mxPrinter->GetDPIY();
1224 const PrinterOptions& rPrinterOptions = mpImplData->mxPrinter->GetPrinterOptions();
1226 static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
1227 static const sal_Int32 NORMAL_BMP_RESOLUTION = 200;
1229 if( rPrinterOptions.IsReduceBitmaps() )
1231 // calculate maximum resolution for bitmap graphics
1232 if( PrinterBitmapMode::Optimal == rPrinterOptions.GetReducedBitmapMode() )
1234 nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1235 nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1237 else if( PrinterBitmapMode::Normal == rPrinterOptions.GetReducedBitmapMode() )
1239 nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1240 nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1242 else
1244 nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
1245 nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
1249 // convert to greyscales
1250 if( rPrinterOptions.IsConvertToGreyscales() )
1252 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() |
1253 ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText |
1254 DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) );
1257 // disable transparency output
1258 if( rPrinterOptions.IsReduceTransparency() && ( PrinterTransparencyMode::NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
1260 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() | DrawModeFlags::NoTransparency );
1263 Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
1264 if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
1266 // in N-Up printing we have no "page" background operation
1267 // we also have no way to determine the paper color
1268 // so let's go for white, which will kill 99.9% of the real cases
1269 aBg = COL_WHITE;
1271 mpImplData->mxPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
1272 rPrinterOptions.IsReduceTransparency(),
1273 rPrinterOptions.GetReducedTransparencyMode() == PrinterTransparencyMode::Auto,
1274 rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
1277 return nRestoreDrawMode;
1280 void PrinterController::printFilteredPage( int i_nPage )
1282 if( mpImplData->meJobState != css::view::PrintableState_JOB_STARTED )
1283 return; // rhbz#657394: check that we are still printing...
1285 GDIMetaFile aPageFile;
1286 PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
1288 if( mpImplData->mxProgress )
1290 // do nothing if printing is canceled
1291 if( mpImplData->mxProgress->isCanceled() )
1293 setJobState( css::view::PrintableState_JOB_ABORTED );
1294 return;
1298 // in N-Up printing set the correct page size
1299 mpImplData->mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
1300 // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
1301 mpImplData->mxPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() );
1302 if( mpImplData->mnFixedPaperBin != -1 &&
1303 mpImplData->mxPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin )
1305 mpImplData->mxPrinter->SetPaperBin( mpImplData->mnFixedPaperBin );
1308 // if full paper is meant to be used, move the output to accommodate for pageoffset
1309 if( aPageSize.bFullPaper )
1311 Point aPageOffset( mpImplData->mxPrinter->GetPageOffset() );
1312 aPageFile.WindStart();
1313 aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1316 GDIMetaFile aCleanedFile;
1317 DrawModeFlags nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
1319 mpImplData->mxPrinter->EnableOutput();
1321 // actually print the page
1322 mpImplData->mxPrinter->ImplStartPage();
1324 mpImplData->mxPrinter->Push();
1325 aCleanedFile.WindStart();
1326 aCleanedFile.Play( mpImplData->mxPrinter.get() );
1327 mpImplData->mxPrinter->Pop();
1329 mpImplData->mxPrinter->ImplEndPage();
1331 mpImplData->mxPrinter->SetDrawMode( nRestoreDrawMode );
1334 void PrinterController::jobStarted()
1338 void PrinterController::jobFinished( css::view::PrintableState )
1342 void PrinterController::abortJob()
1344 setJobState( css::view::PrintableState_JOB_ABORTED );
1345 // applications (well, sw) depend on a page request with "IsLastPage" = true
1346 // to free resources, else they (well, sw) will crash eventually
1347 setLastPage( true );
1349 if (mpImplData->mxProgress)
1351 mpImplData->mxProgress->response(RET_CANCEL);
1352 mpImplData->mxProgress.reset();
1355 GDIMetaFile aMtf;
1356 getPageFile( 0, aMtf );
1359 void PrinterController::setLastPage( bool i_bLastPage )
1361 mpImplData->mbLastPage = i_bLastPage;
1364 void PrinterController::setReversePrint( bool i_bReverse )
1366 mpImplData->mbReversePageOrder = i_bReverse;
1369 void PrinterController::setPapersizeFromSetup( bool i_bPapersizeFromSetup )
1371 mpImplData->mbPapersizeFromSetup = i_bPapersizeFromSetup;
1372 mpImplData->mxPrinter->SetPrinterSettingsPreferred( i_bPapersizeFromSetup );
1373 if ( i_bPapersizeFromSetup )
1374 mpImplData->mbPapersizeFromUser = !i_bPapersizeFromSetup;
1377 bool PrinterController::getPapersizeFromSetup() const
1379 return mpImplData->mbPapersizeFromSetup;
1382 Size& PrinterController::getPaperSizeSetup() const
1384 return mpImplData->maDefaultPageSize;
1387 void PrinterController::setPaperSizeFromUser( Size i_aUserSize )
1389 mpImplData->mbPapersizeFromUser = true;
1390 mpImplData->mbPapersizeFromSetup = false;
1391 mpImplData->mxPrinter->SetPrinterSettingsPreferred( false );
1393 mpImplData->maUserPageSize = i_aUserSize;
1396 Size& PrinterController::getPaperSizeFromUser() const
1398 return mpImplData->maUserPageSize;
1401 bool PrinterController::isPaperSizeFromUser() const
1403 return mpImplData->mbPapersizeFromUser;
1406 void PrinterController::setPrinterModified( bool i_bPrinterModified )
1408 mpImplData->mbPrinterModified = i_bPrinterModified;
1411 bool PrinterController::getPrinterModified() const
1413 return mpImplData->mbPrinterModified;
1416 css::uno::Sequence< css::beans::PropertyValue > PrinterController::getJobProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rMergeList ) const
1418 std::unordered_set< OUString > aMergeSet;
1419 size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
1420 for( const auto& rPropVal : i_rMergeList )
1421 aMergeSet.insert( rPropVal.Name );
1423 css::uno::Sequence< css::beans::PropertyValue > aResult( nResultLen );
1424 std::copy(i_rMergeList.begin(), i_rMergeList.end(), aResult.begin());
1425 int nCur = i_rMergeList.getLength();
1426 for(const css::beans::PropertyValue & rPropVal : mpImplData->maUIProperties)
1428 if( aMergeSet.find( rPropVal.Name ) == aMergeSet.end() )
1429 aResult[nCur++] = rPropVal;
1431 // append IsFirstPage
1432 if( aMergeSet.find( "IsFirstPage" ) == aMergeSet.end() )
1434 css::beans::PropertyValue aVal;
1435 aVal.Name = "IsFirstPage";
1436 aVal.Value <<= mpImplData->mbFirstPage;
1437 aResult[nCur++] = aVal;
1439 // append IsLastPage
1440 if( aMergeSet.find( "IsLastPage" ) == aMergeSet.end() )
1442 css::beans::PropertyValue aVal;
1443 aVal.Name = "IsLastPage";
1444 aVal.Value <<= mpImplData->mbLastPage;
1445 aResult[nCur++] = aVal;
1447 // append IsPrinter
1448 if( aMergeSet.find( "IsPrinter" ) == aMergeSet.end() )
1450 css::beans::PropertyValue aVal;
1451 aVal.Name = "IsPrinter";
1452 aVal.Value <<= true;
1453 aResult[nCur++] = aVal;
1455 aResult.realloc( nCur );
1456 return aResult;
1459 const css::uno::Sequence< css::beans::PropertyValue >& PrinterController::getUIOptions() const
1461 return mpImplData->maUIOptions;
1464 css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty )
1466 std::unordered_map< OUString, size_t >::const_iterator it =
1467 mpImplData->maPropertyToIndex.find( i_rProperty );
1468 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1471 const css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty ) const
1473 std::unordered_map< OUString, size_t >::const_iterator it =
1474 mpImplData->maPropertyToIndex.find( i_rProperty );
1475 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1478 void PrinterController::setValue( const OUString& i_rPropertyName, const css::uno::Any& i_rValue )
1480 css::beans::PropertyValue aVal;
1481 aVal.Name = i_rPropertyName;
1482 aVal.Value = i_rValue;
1484 setValue( aVal );
1487 void PrinterController::setValue( const css::beans::PropertyValue& i_rPropertyValue )
1489 std::unordered_map< OUString, size_t >::const_iterator it =
1490 mpImplData->maPropertyToIndex.find( i_rPropertyValue.Name );
1491 if( it != mpImplData->maPropertyToIndex.end() )
1492 mpImplData->maUIProperties[ it->second ] = i_rPropertyValue;
1493 else
1495 // insert correct index into property map
1496 mpImplData->maPropertyToIndex[ i_rPropertyValue.Name ] = mpImplData->maUIProperties.size();
1497 mpImplData->maUIProperties.push_back( i_rPropertyValue );
1498 mpImplData->maUIPropertyEnabled.push_back( true );
1502 void PrinterController::setUIOptions( const css::uno::Sequence< css::beans::PropertyValue >& i_rOptions )
1504 SAL_WARN_IF( mpImplData->maUIOptions.hasElements(), "vcl.gdi", "setUIOptions called twice !" );
1506 mpImplData->maUIOptions = i_rOptions;
1508 for( const auto& rOpt : i_rOptions )
1510 css::uno::Sequence< css::beans::PropertyValue > aOptProp;
1511 rOpt.Value >>= aOptProp;
1512 bool bIsEnabled = true;
1513 bool bHaveProperty = false;
1514 OUString aPropName;
1515 vcl::ImplPrinterControllerData::ControlDependency aDep;
1516 css::uno::Sequence< sal_Bool > aChoicesDisabled;
1517 for( const css::beans::PropertyValue& rEntry : std::as_const(aOptProp) )
1519 if ( rEntry.Name == "Property" )
1521 css::beans::PropertyValue aVal;
1522 rEntry.Value >>= aVal;
1523 DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )
1524 == mpImplData->maPropertyToIndex.end(), "duplicate property entry" );
1525 setValue( aVal );
1526 aPropName = aVal.Name;
1527 bHaveProperty = true;
1529 else if ( rEntry.Name == "Enabled" )
1531 bool bValue = true;
1532 rEntry.Value >>= bValue;
1533 bIsEnabled = bValue;
1535 else if ( rEntry.Name == "DependsOnName" )
1537 rEntry.Value >>= aDep.maDependsOnName;
1539 else if ( rEntry.Name == "DependsOnEntry" )
1541 rEntry.Value >>= aDep.mnDependsOnEntry;
1543 else if ( rEntry.Name == "ChoicesDisabled" )
1545 rEntry.Value >>= aChoicesDisabled;
1548 if( bHaveProperty )
1550 vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
1551 mpImplData->maPropertyToIndex.find( aPropName );
1552 // sanity check
1553 if( it != mpImplData->maPropertyToIndex.end() )
1555 mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
1557 if( !aDep.maDependsOnName.isEmpty() )
1558 mpImplData->maControlDependencies[ aPropName ] = aDep;
1559 if( aChoicesDisabled.hasElements() )
1560 mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled;
1565 bool PrinterController::isUIOptionEnabled( const OUString& i_rProperty ) const
1567 bool bEnabled = false;
1568 std::unordered_map< OUString, size_t >::const_iterator prop_it =
1569 mpImplData->maPropertyToIndex.find( i_rProperty );
1570 if( prop_it != mpImplData->maPropertyToIndex.end() )
1572 bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
1574 if( bEnabled )
1576 // check control dependencies
1577 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1578 mpImplData->maControlDependencies.find( i_rProperty );
1579 if( it != mpImplData->maControlDependencies.end() )
1581 // check if the dependency is enabled
1582 // if the dependency is disabled, we are too
1583 bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
1585 if( bEnabled )
1587 // does the dependency have the correct value ?
1588 const css::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
1589 OSL_ENSURE( pVal, "unknown property in dependency" );
1590 if( pVal )
1592 sal_Int32 nDepVal = 0;
1593 bool bDepVal = false;
1594 if( pVal->Value >>= nDepVal )
1596 bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
1598 else if( pVal->Value >>= bDepVal )
1600 // could be a dependency on a checked boolean
1601 // in this case the dependency is on a non zero for checked value
1602 bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) ||
1603 ( ! bDepVal && it->second.mnDependsOnEntry == 0);
1605 else
1607 // if the type does not match something is awry
1608 OSL_FAIL( "strange type in control dependency" );
1609 bEnabled = false;
1616 return bEnabled;
1619 bool PrinterController::isUIChoiceEnabled( const OUString& i_rProperty, sal_Int32 i_nValue ) const
1621 bool bEnabled = true;
1622 ImplPrinterControllerData::ChoiceDisableMap::const_iterator it =
1623 mpImplData->maChoiceDisableMap.find( i_rProperty );
1624 if(it != mpImplData->maChoiceDisableMap.end() )
1626 const css::uno::Sequence< sal_Bool >& rDisabled( it->second );
1627 if( i_nValue >= 0 && i_nValue < rDisabled.getLength() )
1628 bEnabled = ! rDisabled[i_nValue];
1630 return bEnabled;
1633 OUString PrinterController::makeEnabled( const OUString& i_rProperty )
1635 OUString aDependency;
1637 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1638 mpImplData->maControlDependencies.find( i_rProperty );
1639 if( it != mpImplData->maControlDependencies.end() )
1641 if( isUIOptionEnabled( it->second.maDependsOnName ) )
1643 aDependency = it->second.maDependsOnName;
1644 const css::beans::PropertyValue* pVal = getValue( aDependency );
1645 OSL_ENSURE( pVal, "unknown property in dependency" );
1646 if( pVal )
1648 sal_Int32 nDepVal = 0;
1649 bool bDepVal = false;
1650 if( pVal->Value >>= nDepVal )
1652 if( it->second.mnDependsOnEntry != -1 )
1654 setValue( aDependency, css::uno::makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
1657 else if( pVal->Value >>= bDepVal )
1659 setValue( aDependency, css::uno::makeAny( it->second.mnDependsOnEntry != 0 ) );
1661 else
1663 // if the type does not match something is awry
1664 OSL_FAIL( "strange type in control dependency" );
1670 return aDependency;
1673 void PrinterController::createProgressDialog()
1675 if (!mpImplData->mxProgress)
1677 bool bShow = true;
1678 css::beans::PropertyValue* pMonitor = getValue( "MonitorVisible" );
1679 if( pMonitor )
1680 pMonitor->Value >>= bShow;
1681 else
1683 const css::beans::PropertyValue* pVal = getValue( "IsApi" );
1684 if( pVal )
1686 bool bApi = false;
1687 pVal->Value >>= bApi;
1688 bShow = ! bApi;
1692 if( bShow && ! Application::IsHeadlessModeEnabled() )
1694 mpImplData->mxProgress.reset(new PrintProgressDialog(getWindow(), getPageCountProtected()));
1695 weld::DialogController::runAsync(mpImplData->mxProgress, [](sal_Int32 /*nResult*/){});
1698 else
1700 mpImplData->mxProgress->response(RET_CANCEL);
1701 mpImplData->mxProgress.reset();
1705 bool PrinterController::isProgressCanceled() const
1707 return mpImplData->mxProgress && mpImplData->mxProgress->isCanceled();
1710 void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
1712 mpImplData->maMultiPage = i_rMPS;
1715 const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
1717 return mpImplData->maMultiPage;
1720 void PrinterController::resetPaperToLastConfigured()
1722 mpImplData->resetPaperToLastConfigured();
1725 void PrinterController::pushPropertiesToPrinter()
1727 sal_Int32 nCopyCount = 1;
1728 // set copycount and collate
1729 const css::beans::PropertyValue* pVal = getValue( "CopyCount" );
1730 if( pVal )
1731 pVal->Value >>= nCopyCount;
1732 bool bCollate = false;
1733 pVal = getValue( "Collate" );
1734 if( pVal )
1735 pVal->Value >>= bCollate;
1736 mpImplData->mxPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate );
1738 // duplex mode
1739 pVal = getValue( "DuplexMode" );
1740 if( pVal )
1742 sal_Int16 nDuplex = css::view::DuplexMode::UNKNOWN;
1743 pVal->Value >>= nDuplex;
1744 switch( nDuplex )
1746 case css::view::DuplexMode::OFF: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::Off ); break;
1747 case css::view::DuplexMode::LONGEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::LongEdge ); break;
1748 case css::view::DuplexMode::SHORTEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::ShortEdge ); break;
1753 bool PrinterController::isShowDialogs() const
1755 bool bApi = getBoolProperty( "IsApi", false );
1756 return ! bApi && ! Application::IsHeadlessModeEnabled();
1759 bool PrinterController::isDirectPrint() const
1761 bool bDirect = getBoolProperty( "IsDirect", false );
1762 return bDirect;
1765 bool PrinterController::getBoolProperty( const OUString& i_rProperty, bool i_bFallback ) const
1767 bool bRet = i_bFallback;
1768 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1769 if( pVal )
1770 pVal->Value >>= bRet;
1771 return bRet;
1774 sal_Int32 PrinterController::getIntProperty( const OUString& i_rProperty, sal_Int32 i_nFallback ) const
1776 sal_Int32 nRet = i_nFallback;
1777 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1778 if( pVal )
1779 pVal->Value >>= nRet;
1780 return nRet;
1784 * PrinterOptionsHelper
1786 css::uno::Any PrinterOptionsHelper::getValue( const OUString& i_rPropertyName ) const
1788 css::uno::Any aRet;
1789 std::unordered_map< OUString, css::uno::Any >::const_iterator it =
1790 m_aPropertyMap.find( i_rPropertyName );
1791 if( it != m_aPropertyMap.end() )
1792 aRet = it->second;
1793 return aRet;
1796 bool PrinterOptionsHelper::getBoolValue( const OUString& i_rPropertyName, bool i_bDefault ) const
1798 bool bRet = false;
1799 css::uno::Any aVal( getValue( i_rPropertyName ) );
1800 return (aVal >>= bRet) ? bRet : i_bDefault;
1803 sal_Int64 PrinterOptionsHelper::getIntValue( const OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
1805 sal_Int64 nRet = 0;
1806 css::uno::Any aVal( getValue( i_rPropertyName ) );
1807 return (aVal >>= nRet) ? nRet : i_nDefault;
1810 OUString PrinterOptionsHelper::getStringValue( const OUString& i_rPropertyName ) const
1812 OUString aRet;
1813 css::uno::Any aVal( getValue( i_rPropertyName ) );
1814 return (aVal >>= aRet) ? aRet : OUString();
1817 bool PrinterOptionsHelper::processProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rNewProp )
1819 bool bChanged = false;
1821 for( const auto& rVal : i_rNewProp )
1823 std::unordered_map< OUString, css::uno::Any >::iterator it =
1824 m_aPropertyMap.find( rVal.Name );
1826 bool bElementChanged = (it == m_aPropertyMap.end()) || (it->second != rVal.Value);
1827 if( bElementChanged )
1829 m_aPropertyMap[ rVal.Name ] = rVal.Value;
1830 bChanged = true;
1833 return bChanged;
1836 void PrinterOptionsHelper::appendPrintUIOptions( css::uno::Sequence< css::beans::PropertyValue >& io_rProps ) const
1838 if( !m_aUIProperties.empty() )
1840 sal_Int32 nIndex = io_rProps.getLength();
1841 io_rProps.realloc( nIndex+1 );
1842 css::beans::PropertyValue aVal;
1843 aVal.Name = "ExtraPrintUIOptions";
1844 aVal.Value <<= comphelper::containerToSequence(m_aUIProperties);
1845 io_rProps[ nIndex ] = aVal;
1849 css::uno::Any PrinterOptionsHelper::setUIControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1850 const OUString& i_rTitle,
1851 const css::uno::Sequence< OUString >& i_rHelpIds,
1852 const OUString& i_rType,
1853 const css::beans::PropertyValue* i_pVal,
1854 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1856 sal_Int32 nElements =
1857 2 // ControlType + ID
1858 + (i_rTitle.isEmpty() ? 0 : 1) // Text
1859 + (i_rHelpIds.hasElements() ? 1 : 0) // HelpId
1860 + (i_pVal ? 1 : 0) // Property
1861 + i_rControlOptions.maAddProps.size() // additional props
1862 + (i_rControlOptions.maGroupHint.isEmpty() ? 0 : 1) // grouping
1863 + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint
1864 + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled
1866 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1868 nElements += 1;
1869 if( i_rControlOptions.mnDependsOnEntry != -1 )
1870 nElements += 1;
1871 if( i_rControlOptions.mbAttachToDependency )
1872 nElements += 1;
1875 css::uno::Sequence< css::beans::PropertyValue > aCtrl( nElements );
1876 sal_Int32 nUsed = 0;
1877 if( !i_rTitle.isEmpty() )
1879 aCtrl[nUsed ].Name = "Text";
1880 aCtrl[nUsed++].Value <<= i_rTitle;
1882 if( i_rHelpIds.hasElements() )
1884 aCtrl[nUsed ].Name = "HelpId";
1885 aCtrl[nUsed++].Value <<= i_rHelpIds;
1887 aCtrl[nUsed ].Name = "ControlType";
1888 aCtrl[nUsed++].Value <<= i_rType;
1889 aCtrl[nUsed ].Name = "ID";
1890 aCtrl[nUsed++].Value <<= i_rIDs;
1891 if( i_pVal )
1893 aCtrl[nUsed ].Name = "Property";
1894 aCtrl[nUsed++].Value <<= *i_pVal;
1896 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1898 aCtrl[nUsed ].Name = "DependsOnName";
1899 aCtrl[nUsed++].Value <<= i_rControlOptions.maDependsOnName;
1900 if( i_rControlOptions.mnDependsOnEntry != -1 )
1902 aCtrl[nUsed ].Name = "DependsOnEntry";
1903 aCtrl[nUsed++].Value <<= i_rControlOptions.mnDependsOnEntry;
1905 if( i_rControlOptions.mbAttachToDependency )
1907 aCtrl[nUsed ].Name = "AttachToDependency";
1908 aCtrl[nUsed++].Value <<= i_rControlOptions.mbAttachToDependency;
1911 if( !i_rControlOptions.maGroupHint.isEmpty() )
1913 aCtrl[nUsed ].Name = "GroupingHint";
1914 aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
1916 if( i_rControlOptions.mbInternalOnly )
1918 aCtrl[nUsed ].Name = "InternalUIOnly";
1919 aCtrl[nUsed++].Value <<= true;
1921 if( ! i_rControlOptions.mbEnabled )
1923 aCtrl[nUsed ].Name = "Enabled";
1924 aCtrl[nUsed++].Value <<= false;
1927 sal_Int32 nAddProps = i_rControlOptions.maAddProps.size();
1928 for( sal_Int32 i = 0; i < nAddProps; i++ )
1929 aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
1931 SAL_WARN_IF( nUsed != nElements, "vcl.gdi", "nUsed != nElements, probable heap corruption" );
1933 return css::uno::makeAny( aCtrl );
1936 css::uno::Any PrinterOptionsHelper::setGroupControlOpt(const OUString& i_rID,
1937 const OUString& i_rTitle,
1938 const OUString& i_rHelpId)
1940 css::uno::Sequence< OUString > aHelpId;
1941 if( !i_rHelpId.isEmpty() )
1943 aHelpId.realloc( 1 );
1944 *aHelpId.getArray() = i_rHelpId;
1946 css::uno::Sequence< OUString > aIds { i_rID };
1947 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Group");
1950 css::uno::Any PrinterOptionsHelper::setSubgroupControlOpt(const OUString& i_rID,
1951 const OUString& i_rTitle,
1952 const OUString& i_rHelpId,
1953 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1955 css::uno::Sequence< OUString > aHelpId;
1956 if( !i_rHelpId.isEmpty() )
1958 aHelpId.realloc( 1 );
1959 *aHelpId.getArray() = i_rHelpId;
1961 css::uno::Sequence< OUString > aIds { i_rID };
1962 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Subgroup", nullptr, i_rControlOptions);
1965 css::uno::Any PrinterOptionsHelper::setBoolControlOpt(const OUString& i_rID,
1966 const OUString& i_rTitle,
1967 const OUString& i_rHelpId,
1968 const OUString& i_rProperty,
1969 bool i_bValue,
1970 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1972 css::uno::Sequence< OUString > aHelpId;
1973 if( !i_rHelpId.isEmpty() )
1975 aHelpId.realloc( 1 );
1976 *aHelpId.getArray() = i_rHelpId;
1978 css::beans::PropertyValue aVal;
1979 aVal.Name = i_rProperty;
1980 aVal.Value <<= i_bValue;
1981 css::uno::Sequence< OUString > aIds { i_rID };
1982 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Bool", &aVal, i_rControlOptions);
1985 css::uno::Any PrinterOptionsHelper::setChoiceRadiosControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1986 const OUString& i_rTitle,
1987 const css::uno::Sequence< OUString >& i_rHelpId,
1988 const OUString& i_rProperty,
1989 const css::uno::Sequence< OUString >& i_rChoices,
1990 sal_Int32 i_nValue,
1991 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
1992 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1994 UIControlOptions aOpt( i_rControlOptions );
1995 sal_Int32 nUsed = aOpt.maAddProps.size();
1996 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.hasElements() ? 1 : 0) );
1997 aOpt.maAddProps[nUsed].Name = "Choices";
1998 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
1999 if( i_rDisabledChoices.hasElements() )
2001 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2002 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
2005 css::beans::PropertyValue aVal;
2006 aVal.Name = i_rProperty;
2007 aVal.Value <<= i_nValue;
2008 return setUIControlOpt(i_rIDs, i_rTitle, i_rHelpId, "Radio", &aVal, aOpt);
2011 css::uno::Any PrinterOptionsHelper::setChoiceListControlOpt(const OUString& i_rID,
2012 const OUString& i_rTitle,
2013 const css::uno::Sequence< OUString >& i_rHelpId,
2014 const OUString& i_rProperty,
2015 const css::uno::Sequence< OUString >& i_rChoices,
2016 sal_Int32 i_nValue,
2017 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
2018 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2020 UIControlOptions aOpt( i_rControlOptions );
2021 sal_Int32 nUsed = aOpt.maAddProps.size();
2022 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.hasElements() ? 1 : 0) );
2023 aOpt.maAddProps[nUsed].Name = "Choices";
2024 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
2025 if( i_rDisabledChoices.hasElements() )
2027 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2028 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
2031 css::beans::PropertyValue aVal;
2032 aVal.Name = i_rProperty;
2033 aVal.Value <<= i_nValue;
2034 css::uno::Sequence< OUString > aIds { i_rID };
2035 return setUIControlOpt(aIds, i_rTitle, i_rHelpId, "List", &aVal, aOpt);
2038 css::uno::Any PrinterOptionsHelper::setRangeControlOpt(const OUString& i_rID,
2039 const OUString& i_rTitle,
2040 const OUString& i_rHelpId,
2041 const OUString& i_rProperty,
2042 sal_Int32 i_nValue,
2043 sal_Int32 i_nMinValue,
2044 sal_Int32 i_nMaxValue,
2045 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2047 UIControlOptions aOpt( i_rControlOptions );
2048 if( i_nMaxValue >= i_nMinValue )
2050 sal_Int32 nUsed = aOpt.maAddProps.size();
2051 aOpt.maAddProps.resize( nUsed + 2 );
2052 aOpt.maAddProps[nUsed ].Name = "MinValue";
2053 aOpt.maAddProps[nUsed++].Value <<= i_nMinValue;
2054 aOpt.maAddProps[nUsed ].Name = "MaxValue";
2055 aOpt.maAddProps[nUsed++].Value <<= i_nMaxValue;
2058 css::uno::Sequence< OUString > aHelpId;
2059 if( !i_rHelpId.isEmpty() )
2061 aHelpId.realloc( 1 );
2062 *aHelpId.getArray() = i_rHelpId;
2064 css::beans::PropertyValue aVal;
2065 aVal.Name = i_rProperty;
2066 aVal.Value <<= i_nValue;
2067 css::uno::Sequence< OUString > aIds { i_rID };
2068 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Range", &aVal, aOpt);
2071 css::uno::Any PrinterOptionsHelper::setEditControlOpt(const OUString& i_rID,
2072 const OUString& i_rTitle,
2073 const OUString& i_rHelpId,
2074 const OUString& i_rProperty,
2075 const OUString& i_rValue,
2076 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2078 css::uno::Sequence< OUString > aHelpId;
2079 if( !i_rHelpId.isEmpty() )
2081 aHelpId.realloc( 1 );
2082 *aHelpId.getArray() = i_rHelpId;
2084 css::beans::PropertyValue aVal;
2085 aVal.Name = i_rProperty;
2086 aVal.Value <<= i_rValue;
2087 css::uno::Sequence< OUString > aIds { i_rID };
2088 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Edit", &aVal, i_rControlOptions);
2091 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */