Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / print3.cxx
blob7ad7ce34f8be4e549c5eb82485743de34e398d81
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/layout.hxx>
21 #include <vcl/print.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/metaact.hxx>
24 #include <vcl/configsettings.hxx>
25 #include <vcl/unohelp.hxx>
26 #include <tools/urlobj.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <sal/types.h>
31 #include "printdlg.hxx"
32 #include "svdata.hxx"
33 #include "salinst.hxx"
34 #include "salprn.hxx"
35 #include "svids.hrc"
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
39 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
40 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
41 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
42 #include <com/sun/star/view/DuplexMode.hpp>
43 #include <com/sun/star/lang/IllegalArgumentException.hpp>
44 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 #include <com/sun/star/awt/Size.hpp>
47 #include <unordered_map>
48 #include <unordered_set>
50 using namespace vcl;
52 class ImplPageCache
54 struct CacheEntry
56 GDIMetaFile aPage;
57 PrinterController::PageSize aSize;
60 std::vector< CacheEntry > maPages;
61 std::vector< sal_Int32 > maPageNumbers;
62 std::vector< sal_Int32 > maCacheRanking;
64 static const sal_Int32 nCacheSize = 6;
66 void updateRanking( sal_Int32 nLastHit )
68 if( maCacheRanking[0] != nLastHit )
70 for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
71 maCacheRanking[i] = maCacheRanking[i-1];
72 maCacheRanking[0] = nLastHit;
76 public:
77 ImplPageCache()
78 : maPages( nCacheSize )
79 , maPageNumbers( nCacheSize, -1 )
80 , maCacheRanking( nCacheSize )
82 for( sal_Int32 i = 0; i < nCacheSize; i++ )
83 maCacheRanking[i] = nCacheSize - i - 1;
86 // caution: does not ensure uniqueness
87 void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
89 sal_Int32 nReplacePage = maCacheRanking.back();
90 maPages[ nReplacePage ].aPage = i_rPage;
91 maPages[ nReplacePage ].aSize = i_rSize;
92 maPageNumbers[ nReplacePage ] = i_nPageNo;
93 // cache insertion means in our case, the page was just queried
94 // so update the ranking
95 updateRanking( nReplacePage );
98 // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
99 // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
100 // whole pages can be rather memory intensive
101 bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
103 for( sal_Int32 i = 0; i < nCacheSize; ++i )
105 if( maPageNumbers[i] == i_nPageNo )
107 updateRanking( i );
108 o_rPageFile = maPages[i].aPage;
109 o_rSize = maPages[i].aSize;
110 return true;
113 return false;
116 void invalidate()
118 for( sal_Int32 i = 0; i < nCacheSize; ++i )
120 maPageNumbers[i] = -1;
121 maPages[i].aPage.Clear();
122 maCacheRanking[i] = nCacheSize - i - 1;
127 class vcl::ImplPrinterControllerData
129 public:
130 struct ControlDependency
132 OUString maDependsOnName;
133 sal_Int32 mnDependsOnEntry;
135 ControlDependency() : mnDependsOnEntry( -1 ) {}
138 typedef std::unordered_map< OUString, size_t, OUStringHash > PropertyToIndexMap;
139 typedef std::unordered_map< OUString, ControlDependency, OUStringHash > ControlDependencyMap;
140 typedef std::unordered_map< OUString, css::uno::Sequence< sal_Bool >, OUStringHash > ChoiceDisableMap;
142 VclPtr< Printer > mxPrinter;
143 css::uno::Sequence< css::beans::PropertyValue > maUIOptions;
144 std::vector< css::beans::PropertyValue > maUIProperties;
145 std::vector< bool > maUIPropertyEnabled;
146 PropertyToIndexMap maPropertyToIndex;
147 ControlDependencyMap maControlDependencies;
148 ChoiceDisableMap maChoiceDisableMap;
149 bool mbFirstPage;
150 bool mbLastPage;
151 bool mbReversePageOrder;
152 bool mbPapersizeFromSetup;
153 bool mbPrinterModified;
154 css::view::PrintableState meJobState;
156 vcl::PrinterController::MultiPageSetup maMultiPage;
158 VclPtr<vcl::PrintProgressDialog> mpProgress;
160 ImplPageCache maPageCache;
162 // set by user through printer properties subdialog of printer settings dialog
163 Size maDefaultPageSize;
164 // set by user through printer properties subdialog of printer settings dialog
165 sal_Int32 mnDefaultPaperBin;
166 // Set by user through printer properties subdialog of print dialog.
167 // Overrides application-set tray for a page.
168 sal_Int32 mnFixedPaperBin;
170 // N.B. Apparently we have three levels of paper tray settings
171 // (latter overrides former):
172 // 1. default tray
173 // 2. tray set for a concrete page by an application, e.g., writer
174 // allows setting a printer tray (for the default printer) for a
175 // page style. This setting can be overridden by user by selecting
176 // "Use only paper tray from printer preferences" on the Options
177 // page in the print dialog, in which case the default tray is
178 // used for all pages.
179 // 3. tray set in printer properties the printer dialog
180 // I'm not quite sure why 1. and 3. are distinct, but the commit
181 // history suggests this is intentional...
183 ImplPrinterControllerData() :
184 mbFirstPage( true ),
185 mbLastPage( false ),
186 mbReversePageOrder( false ),
187 mbPapersizeFromSetup( false ),
188 mbPrinterModified( false ),
189 meJobState( css::view::PrintableState_JOB_STARTED ),
190 mpProgress( nullptr ),
191 mnDefaultPaperBin( -1 ),
192 mnFixedPaperBin( -1 )
194 ~ImplPrinterControllerData() { mpProgress.disposeAndClear(); }
196 const Size& getRealPaperSize( const Size& i_rPageSize, bool bNoNUP ) const
198 if( mbPapersizeFromSetup )
199 return maDefaultPageSize;
200 if( maMultiPage.nRows * maMultiPage.nColumns > 1 && ! bNoNUP )
201 return maMultiPage.aPaperSize;
202 return i_rPageSize;
204 bool isFixedPageSize() const
205 { return mbPapersizeFromSetup; }
206 PrinterController::PageSize modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps );
207 void resetPaperToLastConfigured();
210 PrinterController::PrinterController( const VclPtr<Printer>& i_xPrinter )
211 : mpImplData( new ImplPrinterControllerData )
213 mpImplData->mxPrinter = i_xPrinter;
216 static OUString queryFile( Printer* pPrinter )
218 OUString aResult;
220 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
221 css::uno::Reference< css::ui::dialogs::XFilePicker3 > xFilePicker = css::ui::dialogs::FilePicker::createWithMode(xContext, css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION);
225 #ifdef UNX
226 // add PostScript and PDF
227 bool bPS = true, bPDF = true;
228 if( pPrinter )
230 if( pPrinter->GetCapabilities( PrinterCapType::PDF ) )
231 bPS = false;
232 else
233 bPDF = false;
235 if( bPS )
236 xFilePicker->appendFilter( "PostScript", "*.ps" );
237 if( bPDF )
238 xFilePicker->appendFilter( "Portable Document Format", "*.pdf" );
239 #elif defined WNT
240 (void)pPrinter;
241 xFilePicker->appendFilter( "*.PRN", "*.prn" );
242 #endif
243 // add arbitrary files
244 xFilePicker->appendFilter(VclResId(SV_STDTEXT_ALLFILETYPES), "*.*");
246 catch (const css::lang::IllegalArgumentException&)
248 SAL_WARN( "vcl.gdi", "caught IllegalArgumentException when registering filter" );
251 if( xFilePicker->execute() == css::ui::dialogs::ExecutableDialogResults::OK )
253 css::uno::Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
254 INetURLObject aObj( aPathSeq[0] );
255 aResult = aObj.PathToFileName();
257 return aResult;
260 struct PrintJobAsync
262 std::shared_ptr<PrinterController> mxController;
263 JobSetup maInitSetup;
265 PrintJobAsync(const std::shared_ptr<PrinterController>& i_xController,
266 const JobSetup& i_rInitSetup)
267 : mxController( i_xController ), maInitSetup( i_rInitSetup )
270 DECL_LINK( ExecJob, void*, void );
273 IMPL_LINK_NOARG(PrintJobAsync, ExecJob, void*, void)
275 Printer::ImplPrintJob(mxController, maInitSetup);
277 // clean up, do not access members after this
278 delete this;
281 void Printer::PrintJob(const std::shared_ptr<PrinterController>& i_xController,
282 const JobSetup& i_rInitSetup)
284 bool bSynchronous = false;
285 css::beans::PropertyValue* pVal = i_xController->getValue( OUString( "Wait" ) );
286 if( pVal )
287 pVal->Value >>= bSynchronous;
289 if( bSynchronous )
290 ImplPrintJob(i_xController, i_rInitSetup);
291 else
293 PrintJobAsync* pAsync = new PrintJobAsync(i_xController, i_rInitSetup);
294 Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) );
298 bool Printer::PreparePrintJob(std::shared_ptr<PrinterController> xController,
299 const JobSetup& i_rInitSetup)
301 // check if there is a default printer; if not, show an error box (if appropriate)
302 if( GetDefaultPrinterName().isEmpty() )
304 if (xController->isShowDialogs())
306 ScopedVclPtrInstance<MessageDialog> aBox(
307 nullptr, "ErrorNoPrinterDialog",
308 "vcl/ui/errornoprinterdialog.ui");
309 aBox->Execute();
311 xController->setValue( "IsDirect",
312 css::uno::makeAny( false ) );
315 // setup printer
317 // #i114306# changed behavior back from persistence
318 // if no specific printer is already set, create the default printer
319 if (!xController->getPrinter())
321 OUString aPrinterName( i_rInitSetup.GetPrinterName() );
322 VclPtrInstance<Printer> xPrinter( aPrinterName );
323 xPrinter->SetJobSetup(i_rInitSetup);
324 xController->setPrinter(xPrinter);
327 // reset last page property
328 xController->setLastPage(false);
330 // update "PageRange" property inferring from other properties:
331 // case 1: "Pages" set from UNO API ->
332 // setup "Print Selection" and insert "PageRange" attribute
333 // case 2: "All pages" is selected
334 // update "Page range" attribute to have a sensible default,
335 // but leave "All" as selected
337 // "Pages" attribute from API is now equivalent to "PageRange"
338 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
339 // Argh ! That sure needs cleaning up
340 css::beans::PropertyValue* pContentVal = xController->getValue(OUString("PrintRange"));
341 if( ! pContentVal )
342 pContentVal = xController->getValue(OUString("PrintContent"));
344 // case 1: UNO API has set "Pages"
345 css::beans::PropertyValue* pPagesVal = xController->getValue(OUString("Pages"));
346 if( pPagesVal )
348 OUString aPagesVal;
349 pPagesVal->Value >>= aPagesVal;
350 if( !aPagesVal.isEmpty() )
352 // "Pages" attribute from API is now equivalent to "PageRange"
353 // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
354 // Argh ! That sure needs cleaning up
355 if( pContentVal )
357 pContentVal->Value <<= sal_Int32( 1 );
358 xController->setValue("PageRange", pPagesVal->Value);
362 // case 2: is "All" selected ?
363 else if( pContentVal )
365 sal_Int32 nContent = -1;
366 if( pContentVal->Value >>= nContent )
368 if( nContent == 0 )
370 // do not overwrite PageRange if it is already set
371 css::beans::PropertyValue* pRangeVal = xController->getValue(OUString("PageRange"));
372 OUString aRange;
373 if( pRangeVal )
374 pRangeVal->Value >>= aRange;
375 if( aRange.isEmpty() )
377 sal_Int32 nPages = xController->getPageCount();
378 if( nPages > 0 )
380 OUStringBuffer aBuf( 32 );
381 aBuf.append( "1" );
382 if( nPages > 1 )
384 aBuf.append( "-" );
385 aBuf.append( nPages );
387 xController->setValue("PageRange", css::uno::makeAny(aBuf.makeStringAndClear()));
394 css::beans::PropertyValue* pReverseVal = xController->getValue(OUString("PrintReverse"));
395 if( pReverseVal )
397 bool bReverse = false;
398 pReverseVal->Value >>= bReverse;
399 xController->setReversePrint( bReverse );
402 css::beans::PropertyValue* pPapersizeFromSetupVal = xController->getValue(OUString("PapersizeFromSetup"));
403 if( pPapersizeFromSetupVal )
405 bool bPapersizeFromSetup = false;
406 pPapersizeFromSetupVal->Value >>= bPapersizeFromSetup;
407 xController->setPapersizeFromSetup(bPapersizeFromSetup);
410 // setup NUp printing from properties
411 sal_Int32 nRows = xController->getIntProperty("NUpRows", 1);
412 sal_Int32 nCols = xController->getIntProperty("NUpColumns", 1);
413 if( nRows > 1 || nCols > 1 )
415 PrinterController::MultiPageSetup aMPS;
416 aMPS.nRows = nRows > 1 ? nRows : 1;
417 aMPS.nColumns = nCols > 1 ? nCols : 1;
418 sal_Int32 nValue = xController->getIntProperty("NUpPageMarginLeft", aMPS.nLeftMargin);
419 if( nValue >= 0 )
420 aMPS.nLeftMargin = nValue;
421 nValue = xController->getIntProperty("NUpPageMarginRight", aMPS.nRightMargin);
422 if( nValue >= 0 )
423 aMPS.nRightMargin = nValue;
424 nValue = xController->getIntProperty( "NUpPageMarginTop", aMPS.nTopMargin );
425 if( nValue >= 0 )
426 aMPS.nTopMargin = nValue;
427 nValue = xController->getIntProperty( "NUpPageMarginBottom", aMPS.nBottomMargin );
428 if( nValue >= 0 )
429 aMPS.nBottomMargin = nValue;
430 nValue = xController->getIntProperty( "NUpHorizontalSpacing", aMPS.nHorizontalSpacing );
431 if( nValue >= 0 )
432 aMPS.nHorizontalSpacing = nValue;
433 nValue = xController->getIntProperty( "NUpVerticalSpacing", aMPS.nVerticalSpacing );
434 if( nValue >= 0 )
435 aMPS.nVerticalSpacing = nValue;
436 aMPS.bDrawBorder = xController->getBoolProperty( "NUpDrawBorder", aMPS.bDrawBorder );
437 aMPS.nOrder = static_cast<NupOrderType>(xController->getIntProperty( "NUpSubPageOrder", (sal_Int32)aMPS.nOrder ));
438 aMPS.aPaperSize = xController->getPrinter()->PixelToLogic( xController->getPrinter()->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) );
439 css::beans::PropertyValue* pPgSizeVal = xController->getValue( OUString( "NUpPaperSize" ) );
440 css::awt::Size aSizeVal;
441 if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
443 aMPS.aPaperSize.Width() = aSizeVal.Width;
444 aMPS.aPaperSize.Height() = aSizeVal.Height;
447 xController->setMultipage( aMPS );
450 // in direct print case check whether there is anything to print.
451 // if not, show an errorbox (if appropriate)
452 if( xController->isShowDialogs() && xController->isDirectPrint() )
454 if( xController->getFilteredPageCount() == 0 )
456 ScopedVclPtrInstance<MessageDialog> aBox(
457 nullptr, "ErrorNoContentDialog",
458 "vcl/ui/errornocontentdialog.ui");
459 aBox->Execute();
460 return false;
464 // check if the printer brings up its own dialog
465 // in that case leave the work to that dialog
466 if( ! xController->getPrinter()->GetCapabilities( PrinterCapType::ExternalDialog ) &&
467 ! xController->isDirectPrint() &&
468 xController->isShowDialogs()
473 ScopedVclPtrInstance< PrintDialog > aDlg( nullptr, xController );
474 if( ! aDlg->Execute() )
476 xController->abortJob();
477 return false;
479 if( aDlg->isPrintToFile() )
481 OUString aFile = queryFile( xController->getPrinter().get() );
482 if( aFile.isEmpty() )
484 xController->abortJob();
485 return false;
487 xController->setValue( "LocalFileName",
488 css::uno::makeAny( aFile ) );
490 else if( aDlg->isSingleJobs() )
492 xController->setValue( "PrintCollateAsSingleJobs",
493 css::uno::makeAny( true ) );
496 catch (const std::bad_alloc&)
501 xController->pushPropertiesToPrinter();
502 return true;
505 bool Printer::ExecutePrintJob(std::shared_ptr<PrinterController> xController)
507 OUString aJobName;
508 css::beans::PropertyValue* pJobNameVal = xController->getValue( OUString( "JobName" ) );
509 if( pJobNameVal )
510 pJobNameVal->Value >>= aJobName;
512 return xController->getPrinter()->StartJob( aJobName, xController );
515 void Printer::FinishPrintJob(const std::shared_ptr<PrinterController>& xController)
517 xController->resetPaperToLastConfigured();
518 xController->jobFinished( xController->getJobState() );
521 void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& xController,
522 const JobSetup& i_rInitSetup)
524 if (PreparePrintJob(xController, i_rInitSetup))
526 ExecutePrintJob(xController);
528 FinishPrintJob(xController);
531 bool Printer::StartJob( const OUString& i_rJobName, std::shared_ptr<vcl::PrinterController>& i_xController)
533 mnError = PRINTER_OK;
535 if ( IsDisplayPrinter() )
536 return false;
538 if ( IsJobActive() || IsPrinting() )
539 return false;
541 sal_uInt32 nCopies = mnCopyCount;
542 bool bCollateCopy = mbCollateCopy;
543 bool bUserCopy = false;
545 if ( nCopies > 1 )
547 const sal_uInt32 nDevCopy = GetCapabilities( bCollateCopy
548 ? PrinterCapType::CollateCopies
549 : PrinterCapType::Copies );
551 // need to do copies by hand ?
552 if ( nCopies > nDevCopy )
554 bUserCopy = true;
555 nCopies = 1;
556 bCollateCopy = false;
559 else
560 bCollateCopy = false;
562 ImplSVData* pSVData = ImplGetSVData();
563 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
565 if (!mpPrinter)
566 return false;
568 bool bSinglePrintJobs = false;
569 css::beans::PropertyValue* pSingleValue = i_xController->getValue(OUString("PrintCollateAsSingleJobs"));
570 if( pSingleValue )
572 pSingleValue->Value >>= bSinglePrintJobs;
575 css::beans::PropertyValue* pFileValue = i_xController->getValue(OUString("LocalFileName"));
576 if( pFileValue )
578 OUString aFile;
579 pFileValue->Value >>= aFile;
580 if( !aFile.isEmpty() )
582 mbPrintFile = true;
583 maPrintFile = aFile;
584 bSinglePrintJobs = false;
588 OUString* pPrintFile = nullptr;
589 if ( mbPrintFile )
590 pPrintFile = &maPrintFile;
591 mpPrinterOptions->ReadFromConfig( mbPrintFile );
593 maJobName = i_rJobName;
594 mnCurPage = 1;
595 mnCurPrintPage = 1;
596 mbPrinting = true;
597 if( GetCapabilities( PrinterCapType::UsePullModel ) )
599 mbJobActive = true;
600 // SAL layer does all necessary page printing
601 // and also handles showing a dialog
602 // that also means it must call jobStarted when the dialog is finished
603 // it also must set the JobState of the Controller
604 if( mpPrinter->StartJob( pPrintFile,
605 i_rJobName,
606 Application::GetDisplayName(),
607 &maJobSetup.ImplGetData(),
608 *i_xController) )
610 EndJob();
612 else
614 mnError = ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode());
615 if ( !mnError )
616 mnError = PRINTER_GENERALERROR;
617 pSVData->mpDefInst->DestroyPrinter( mpPrinter );
618 mnCurPage = 0;
619 mnCurPrintPage = 0;
620 mbPrinting = false;
621 mpPrinter = nullptr;
622 mbJobActive = false;
624 GDIMetaFile aDummyFile;
625 i_xController->setLastPage(true);
626 i_xController->getFilteredPageFile(0, aDummyFile);
628 return false;
631 else
633 // possibly a dialog has been shown
634 // now the real job starts
635 i_xController->setJobState( css::view::PrintableState_JOB_STARTED );
636 i_xController->jobStarted();
638 int nJobs = 1;
639 int nOuterRepeatCount = 1;
640 int nInnerRepeatCount = 1;
641 if( bUserCopy )
643 if( mbCollateCopy )
644 nOuterRepeatCount = mnCopyCount;
645 else
646 nInnerRepeatCount = mnCopyCount;
648 if( bSinglePrintJobs )
650 nJobs = mnCopyCount;
651 nCopies = 1;
652 nOuterRepeatCount = nInnerRepeatCount = 1;
655 for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
657 bool bError = false;
658 if( mpPrinter->StartJob( pPrintFile,
659 i_rJobName,
660 Application::GetDisplayName(),
661 nCopies,
662 bCollateCopy,
663 i_xController->isDirectPrint(),
664 &maJobSetup.ImplGetData() ) )
666 bool bAborted = false;
667 mbJobActive = true;
668 i_xController->createProgressDialog();
669 const int nPages = i_xController->getFilteredPageCount();
670 // abort job, if no pages will be printed.
671 if ( nPages == 0 )
673 i_xController->abortJob();
674 bAborted = true;
676 for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ )
678 for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ )
680 for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ )
682 if( nPage == nPages-1 &&
683 nOuterIteration == nOuterRepeatCount-1 &&
684 nInnerIteration == nInnerRepeatCount-1 &&
685 nJobIteration == nJobs-1 )
687 i_xController->setLastPage(true);
689 i_xController->printFilteredPage(nPage);
690 if (i_xController->isProgressCanceled())
692 i_xController->abortJob();
694 if (i_xController->getJobState() ==
695 css::view::PrintableState_JOB_ABORTED)
697 bAborted = true;
701 // FIXME: duplex ?
703 EndJob();
705 if( nJobIteration < nJobs-1 )
707 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
709 if ( mpPrinter )
711 maJobName = i_rJobName;
712 mnCurPage = 1;
713 mnCurPrintPage = 1;
714 mbPrinting = true;
716 else
717 bError = true;
720 else
721 bError = true;
723 if( bError )
725 mnError = mpPrinter ? ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode()) : 0;
726 if ( !mnError )
727 mnError = PRINTER_GENERALERROR;
728 i_xController->setJobState( mnError == PRINTER_ABORT
729 ? css::view::PrintableState_JOB_ABORTED
730 : css::view::PrintableState_JOB_FAILED );
731 if( mpPrinter )
732 pSVData->mpDefInst->DestroyPrinter( mpPrinter );
733 mnCurPage = 0;
734 mnCurPrintPage = 0;
735 mbPrinting = false;
736 mpPrinter = nullptr;
738 return false;
742 if (i_xController->getJobState() == css::view::PrintableState_JOB_STARTED)
743 i_xController->setJobState(css::view::PrintableState_JOB_SPOOLED);
746 // make last used printer persistent for UI jobs
747 if (i_xController->isShowDialogs() && !i_xController->isDirectPrint())
749 SettingsConfigItem* pItem = SettingsConfigItem::get();
750 pItem->setValue( "PrintDialog",
751 "LastPrinterUsed",
752 GetName()
756 return true;
759 PrinterController::~PrinterController()
763 css::view::PrintableState PrinterController::getJobState() const
765 return mpImplData->meJobState;
768 void PrinterController::setJobState( css::view::PrintableState i_eState )
770 mpImplData->meJobState = i_eState;
773 const VclPtr<Printer>& PrinterController::getPrinter() const
775 return mpImplData->mxPrinter;
778 void PrinterController::setPrinter( const VclPtr<Printer>& i_rPrinter )
780 mpImplData->mxPrinter = i_rPrinter;
781 setValue( "Name",
782 css::uno::makeAny( OUString( i_rPrinter->GetName() ) ) );
783 mpImplData->mnDefaultPaperBin = mpImplData->mxPrinter->GetPaperBin();
784 mpImplData->mxPrinter->Push();
785 mpImplData->mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
786 mpImplData->maDefaultPageSize = mpImplData->mxPrinter->GetPaperSize();
787 mpImplData->mxPrinter->Pop();
788 mpImplData->mnFixedPaperBin = -1;
791 void PrinterController::resetPrinterOptions( bool i_bFileOutput )
793 PrinterOptions aOpt;
794 aOpt.ReadFromConfig( i_bFileOutput );
795 mpImplData->mxPrinter->SetPrinterOptions( aOpt );
798 bool PrinterController::setupPrinter( vcl::Window* i_pParent )
800 bool bRet = false;
802 // Important to hold printer alive while doing setup etc.
803 VclPtr< Printer > xPrinter = mpImplData->mxPrinter;
805 if( xPrinter.get() )
807 xPrinter->Push();
808 xPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
810 // get current data
811 Size aPaperSize(xPrinter->GetPaperSize());
812 sal_uInt16 nPaperBin = xPrinter->GetPaperBin();
814 // reset paper size back to last configured size, not
815 // whatever happens to be the current page
816 // (but only if the printer config has changed, otherwise
817 // don't override printer page auto-detection - tdf#91362)
818 if (getPrinterModified())
820 resetPaperToLastConfigured();
823 // call driver setup
824 bRet = xPrinter->Setup( i_pParent, getPapersizeFromSetup() );
825 SAL_WARN_IF(xPrinter != mpImplData->mxPrinter, "vcl.gdi",
826 "Printer changed underneath us during setup");
827 xPrinter = mpImplData->mxPrinter;
829 Size aNewPaperSize(xPrinter->GetPaperSize());
830 if (bRet)
832 bool bInvalidateCache = false;
834 // was papersize overridden ? if so we need to take action if we're
835 // configured to use the driver papersize
836 if (aNewPaperSize != mpImplData->maDefaultPageSize)
838 mpImplData->maDefaultPageSize = aNewPaperSize;
839 bInvalidateCache = getPapersizeFromSetup();
842 // was bin overridden ? if so we need to take action
843 sal_uInt16 nNewPaperBin = xPrinter->GetPaperBin();
844 if (nNewPaperBin != nPaperBin)
846 mpImplData->mnFixedPaperBin = nNewPaperBin;
847 bInvalidateCache = true;
850 if (bInvalidateCache)
852 mpImplData->maPageCache.invalidate();
855 else
857 //restore to whatever it was before we entered this method
858 if (aPaperSize != aNewPaperSize)
859 xPrinter->SetPaperSizeUser(aPaperSize, !mpImplData->isFixedPageSize());
861 xPrinter->Pop();
863 return bRet;
866 PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const css::uno::Sequence< css::beans::PropertyValue >& i_rProps )
868 PrinterController::PageSize aPageSize;
869 aPageSize.aSize = mxPrinter->GetPaperSize();
870 css::awt::Size aSetSize, aIsSize;
871 sal_Int32 nPaperBin = mnDefaultPaperBin;
872 for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty )
874 if ( i_rProps[ nProperty ].Name == "PreferredPageSize" )
876 i_rProps[ nProperty ].Value >>= aSetSize;
878 else if ( i_rProps[ nProperty ].Name == "PageSize" )
880 i_rProps[ nProperty ].Value >>= aIsSize;
882 else if ( i_rProps[ nProperty ].Name == "PageIncludesNonprintableArea" )
884 bool bVal = false;
885 i_rProps[ nProperty ].Value >>= bVal;
886 aPageSize.bFullPaper = bVal;
888 else if ( i_rProps[ nProperty ].Name == "PrinterPaperTray" )
890 sal_Int32 nBin = -1;
891 i_rProps[ nProperty ].Value >>= nBin;
892 if( nBin >= 0 && nBin < static_cast<sal_Int32>(mxPrinter->GetPaperBinCount()) )
893 nPaperBin = nBin;
897 Size aCurSize( mxPrinter->GetPaperSize() );
898 if( aSetSize.Width && aSetSize.Height )
900 Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
901 Size aRealPaperSize( getRealPaperSize( aSetPaperSize, true/*bNoNUP*/ ) );
902 if( aRealPaperSize != aCurSize )
903 aIsSize = aSetSize;
906 if( aIsSize.Width && aIsSize.Height )
908 aPageSize.aSize.Width() = aIsSize.Width;
909 aPageSize.aSize.Height() = aIsSize.Height;
911 Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, true/*bNoNUP*/ ) );
912 if( aRealPaperSize != aCurSize )
913 mxPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() );
916 // paper bin set from properties in print dialog overrides
917 // application default for a page
918 if ( mnFixedPaperBin != -1 )
919 nPaperBin = mnFixedPaperBin;
921 if( nPaperBin != -1 && nPaperBin != mxPrinter->GetPaperBin() )
922 mxPrinter->SetPaperBin( nPaperBin );
924 return aPageSize;
927 //fdo#61886
929 //when printing is finished, set the paper size of the printer to either what
930 //the user explicitly set as the desired paper size, or fallback to whatever
931 //the printer had before printing started. That way it doesn't contain the last
932 //paper size of a multiple paper size using document when we are in our normal
933 //auto accept document paper size mode and end up overwriting the original
934 //paper size setting for file->printer_settings just by pressing "ok" in the
935 //print dialog
936 void vcl::ImplPrinterControllerData::resetPaperToLastConfigured()
938 mxPrinter->Push();
939 mxPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
940 Size aCurSize(mxPrinter->GetPaperSize());
941 if (aCurSize != maDefaultPageSize)
942 mxPrinter->SetPaperSizeUser(maDefaultPageSize, !isFixedPageSize());
943 mxPrinter->Pop();
946 int PrinterController::getPageCountProtected() const
948 const MapMode aMapMode( MapUnit::Map100thMM );
950 mpImplData->mxPrinter->Push();
951 mpImplData->mxPrinter->SetMapMode( aMapMode );
952 int nPages = getPageCount();
953 mpImplData->mxPrinter->Pop();
954 return nPages;
957 css::uno::Sequence< css::beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
959 const MapMode aMapMode( MapUnit::Map100thMM );
961 mpImplData->mxPrinter->Push();
962 mpImplData->mxPrinter->SetMapMode( aMapMode );
963 css::uno::Sequence< css::beans::PropertyValue > aResult( getPageParameters( i_nPage ) );
964 mpImplData->mxPrinter->Pop();
965 return aResult;
968 PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
970 // update progress if necessary
971 if( mpImplData->mpProgress )
973 // do nothing if printing is canceled
974 if( mpImplData->mpProgress->isCanceled() )
975 return PrinterController::PageSize();
976 mpImplData->mpProgress->tick();
977 Application::Reschedule( true );
980 if( i_bMayUseCache )
982 PrinterController::PageSize aPageSize;
983 if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
985 return aPageSize;
988 else
989 mpImplData->maPageCache.invalidate();
991 o_rMtf.Clear();
993 // get page parameters
994 css::uno::Sequence< css::beans::PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
995 const MapMode aMapMode( MapUnit::Map100thMM );
997 mpImplData->mxPrinter->Push();
998 mpImplData->mxPrinter->SetMapMode( aMapMode );
1000 // modify job setup if necessary
1001 PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm );
1003 o_rMtf.SetPrefSize( aPageSize.aSize );
1004 o_rMtf.SetPrefMapMode( aMapMode );
1006 mpImplData->mxPrinter->EnableOutput( false );
1008 o_rMtf.Record( mpImplData->mxPrinter.get() );
1010 printPage( i_nUnfilteredPage );
1012 o_rMtf.Stop();
1013 o_rMtf.WindStart();
1014 mpImplData->mxPrinter->Pop();
1016 if( i_bMayUseCache )
1017 mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
1019 // reset "FirstPage" property to false now we've gotten at least our first one
1020 mpImplData->mbFirstPage = false;
1022 return aPageSize;
1025 static void appendSubPage( GDIMetaFile& o_rMtf, const tools::Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
1027 // intersect all clipregion actions with our clip rect
1028 io_rSubPage.WindStart();
1029 io_rSubPage.Clip( i_rClipRect );
1031 // save gstate
1032 o_rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1034 // clip to page rect
1035 o_rMtf.AddAction( new MetaClipRegionAction( vcl::Region( i_rClipRect ), true ) );
1037 // append the subpage
1038 io_rSubPage.WindStart();
1039 io_rSubPage.Play( o_rMtf );
1041 // restore gstate
1042 o_rMtf.AddAction( new MetaPopAction() );
1044 // draw a border
1045 if( i_bDrawBorder )
1047 // save gstate
1048 o_rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::CLIPREGION | PushFlags::MAPMODE ) );
1049 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1051 tools::Rectangle aBorderRect( i_rClipRect );
1052 o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), true ) );
1053 o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), false ) );
1054 o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
1056 // restore gstate
1057 o_rMtf.AddAction( new MetaPopAction() );
1061 PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
1063 const MultiPageSetup& rMPS( mpImplData->maMultiPage );
1064 int nSubPages = rMPS.nRows * rMPS.nColumns;
1065 if( nSubPages < 1 )
1066 nSubPages = 1;
1068 // reverse sheet order
1069 if( mpImplData->mbReversePageOrder )
1071 int nDocPages = getFilteredPageCount();
1072 i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
1075 // there is no filtering to be done (and possibly the page size of the
1076 // original page is to be set), when N-Up is "neutral" that is there is
1077 // only one subpage and the margins are 0
1078 if( nSubPages == 1 &&
1079 rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
1080 rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
1082 PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
1083 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1084 { // rhbz#657394: check that we are still printing...
1085 return PrinterController::PageSize();
1087 Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true );
1088 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1089 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1090 if( aPaperSize != aPageSize.aSize )
1092 // user overridden page size, center Metafile
1093 o_rMtf.WindStart();
1094 long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
1095 long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
1096 o_rMtf.Move( nDX, nDY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1097 o_rMtf.WindStart();
1098 o_rMtf.SetPrefSize( aPaperSize );
1099 aPageSize.aSize = aPaperSize;
1101 return aPageSize;
1104 // set last page property really only on the very last page to be rendered
1105 // that is on the last subpage of a NUp run
1106 bool bIsLastPage = mpImplData->mbLastPage;
1107 mpImplData->mbLastPage = false;
1109 Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) );
1111 // multi page area: page size minus margins + one time spacing right and down
1112 // the added spacing is so each subpage can be calculated including its spacing
1113 Size aMPArea( aPaperSize );
1114 aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin;
1115 aMPArea.Width() += rMPS.nHorizontalSpacing;
1116 aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin;
1117 aMPArea.Height() += rMPS.nVerticalSpacing;
1119 // determine offsets
1120 long nAdvX = aMPArea.Width() / rMPS.nColumns;
1121 long nAdvY = aMPArea.Height() / rMPS.nRows;
1123 // determine size of a "cell" subpage, leave a little space around pages
1124 Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
1126 o_rMtf.Clear();
1127 o_rMtf.SetPrefSize( aPaperSize );
1128 o_rMtf.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
1129 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MapUnit::Map100thMM ) ) );
1131 int nDocPages = getPageCountProtected();
1132 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1133 { // rhbz#657394: check that we are still printing...
1134 return PrinterController::PageSize();
1136 for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
1138 // map current sub page to real page
1139 int nPage = i_nFilteredPage * nSubPages + nSubPage;
1140 if( nSubPage == nSubPages-1 ||
1141 nPage == nDocPages-1 )
1143 mpImplData->mbLastPage = bIsLastPage;
1145 if( nPage >= 0 && nPage < nDocPages )
1147 GDIMetaFile aPageFile;
1148 PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
1149 if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
1151 long nCellX = 0, nCellY = 0;
1152 switch( rMPS.nOrder )
1154 case NupOrderType::LRTB:
1155 nCellX = (nSubPage % rMPS.nColumns);
1156 nCellY = (nSubPage / rMPS.nColumns);
1157 break;
1158 case NupOrderType::TBLR:
1159 nCellX = (nSubPage / rMPS.nRows);
1160 nCellY = (nSubPage % rMPS.nRows);
1161 break;
1162 case NupOrderType::RLTB:
1163 nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns);
1164 nCellY = (nSubPage / rMPS.nColumns);
1165 break;
1166 case NupOrderType::TBRL:
1167 nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows);
1168 nCellY = (nSubPage % rMPS.nRows);
1169 break;
1171 // scale the metafile down to a sub page size
1172 double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
1173 double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
1174 double fScale = std::min( fScaleX, fScaleY );
1175 aPageFile.Scale( fScale, fScale );
1176 aPageFile.WindStart();
1178 // move the subpage so it is centered in its "cell"
1179 long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
1180 long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
1181 long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
1182 long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
1183 aPageFile.Move( nX, nY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1184 aPageFile.WindStart();
1185 // calculate border rectangle
1186 tools::Rectangle aSubPageRect( Point( nX, nY ),
1187 Size( long(double(aPageSize.aSize.Width())*fScale),
1188 long(double(aPageSize.aSize.Height())*fScale) ) );
1190 // append subpage to page
1191 appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
1195 o_rMtf.WindStart();
1197 // subsequent getPageFile calls have changed the paper, reset it to current value
1198 mpImplData->mxPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) );
1199 mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1201 return PrinterController::PageSize( aPaperSize, true );
1204 int PrinterController::getFilteredPageCount()
1206 int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
1207 if( nDiv < 1 )
1208 nDiv = 1;
1209 return (getPageCountProtected() + (nDiv-1)) / nDiv;
1212 DrawModeFlags PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut )
1214 DrawModeFlags nRestoreDrawMode = mpImplData->mxPrinter->GetDrawMode();
1215 sal_Int32 nMaxBmpDPIX = mpImplData->mxPrinter->GetDPIX();
1216 sal_Int32 nMaxBmpDPIY = mpImplData->mxPrinter->GetDPIY();
1218 const PrinterOptions& rPrinterOptions = mpImplData->mxPrinter->GetPrinterOptions();
1220 static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
1221 static const sal_Int32 NORMAL_BMP_RESOLUTION = 200;
1223 if( rPrinterOptions.IsReduceBitmaps() )
1225 // calculate maximum resolution for bitmap graphics
1226 if( PrinterBitmapMode::Optimal == rPrinterOptions.GetReducedBitmapMode() )
1228 nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1229 nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1231 else if( PrinterBitmapMode::Normal == rPrinterOptions.GetReducedBitmapMode() )
1233 nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1234 nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1236 else
1238 nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
1239 nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
1243 // convert to greyscales
1244 if( rPrinterOptions.IsConvertToGreyscales() )
1246 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() |
1247 ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText |
1248 DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) );
1251 // disable transparency output
1252 if( rPrinterOptions.IsReduceTransparency() && ( PrinterTransparencyMode::NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
1254 mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() | DrawModeFlags::NoTransparency );
1257 Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
1258 if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
1260 // in N-Up printing we have no "page" background operation
1261 // we also have no way to determine the paper color
1262 // so let's go for white, which will kill 99.9% of the real cases
1263 aBg = Color( COL_WHITE );
1265 mpImplData->mxPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
1266 rPrinterOptions.IsReduceTransparency(),
1267 rPrinterOptions.GetReducedTransparencyMode() == PrinterTransparencyMode::Auto,
1268 rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
1271 return nRestoreDrawMode;
1274 void PrinterController::printFilteredPage( int i_nPage )
1276 if( mpImplData->meJobState != css::view::PrintableState_JOB_STARTED )
1277 return;
1279 GDIMetaFile aPageFile;
1280 PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
1282 if (mpImplData->meJobState != css::view::PrintableState_JOB_STARTED)
1283 { // rhbz#657394: check that we are still printing...
1284 return;
1287 if( mpImplData->mpProgress )
1289 // do nothing if printing is canceled
1290 if( mpImplData->mpProgress->isCanceled() )
1292 setJobState( css::view::PrintableState_JOB_ABORTED );
1293 return;
1297 // in N-Up printing set the correct page size
1298 mpImplData->mxPrinter->SetMapMode( MapUnit::Map100thMM );
1299 // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
1300 mpImplData->mxPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() );
1301 if( mpImplData->mnFixedPaperBin != -1 &&
1302 mpImplData->mxPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin )
1304 mpImplData->mxPrinter->SetPaperBin( mpImplData->mnFixedPaperBin );
1307 // if full paper is meant to be used, move the output to accommodate for pageoffset
1308 if( aPageSize.bFullPaper )
1310 Point aPageOffset( mpImplData->mxPrinter->GetPageOffset() );
1311 aPageFile.WindStart();
1312 aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1315 GDIMetaFile aCleanedFile;
1316 DrawModeFlags nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
1318 mpImplData->mxPrinter->EnableOutput();
1320 // actually print the page
1321 mpImplData->mxPrinter->ImplStartPage();
1323 mpImplData->mxPrinter->Push();
1324 aCleanedFile.WindStart();
1325 aCleanedFile.Play( mpImplData->mxPrinter.get() );
1326 mpImplData->mxPrinter->Pop();
1328 mpImplData->mxPrinter->ImplEndPage();
1330 mpImplData->mxPrinter->SetDrawMode( nRestoreDrawMode );
1333 void PrinterController::jobStarted()
1337 void PrinterController::jobFinished( css::view::PrintableState )
1341 void PrinterController::abortJob()
1343 setJobState( css::view::PrintableState_JOB_ABORTED );
1344 // applications (well, sw) depend on a page request with "IsLastPage" = true
1345 // to free resources, else they (well, sw) will crash eventually
1346 setLastPage( true );
1347 mpImplData->mpProgress.disposeAndClear();
1348 GDIMetaFile aMtf;
1349 getPageFile( 0, aMtf );
1352 void PrinterController::setLastPage( bool i_bLastPage )
1354 mpImplData->mbLastPage = i_bLastPage;
1357 void PrinterController::setReversePrint( bool i_bReverse )
1359 mpImplData->mbReversePageOrder = i_bReverse;
1362 bool PrinterController::getReversePrint() const
1364 return mpImplData->mbReversePageOrder;
1367 void PrinterController::setPapersizeFromSetup( bool i_bPapersizeFromSetup )
1369 mpImplData->mbPapersizeFromSetup = i_bPapersizeFromSetup;
1372 bool PrinterController::getPapersizeFromSetup() const
1374 return mpImplData->mbPapersizeFromSetup;
1377 void PrinterController::setPrinterModified( bool i_bPrinterModified )
1379 mpImplData->mbPrinterModified = i_bPrinterModified;
1382 bool PrinterController::getPrinterModified() const
1384 return mpImplData->mbPrinterModified;
1387 css::uno::Sequence< css::beans::PropertyValue > PrinterController::getJobProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rMergeList ) const
1389 std::unordered_set< OUString, OUStringHash > aMergeSet;
1390 size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
1391 for( int i = 0; i < i_rMergeList.getLength(); i++ )
1392 aMergeSet.insert( i_rMergeList[i].Name );
1394 css::uno::Sequence< css::beans::PropertyValue > aResult( nResultLen );
1395 for( int i = 0; i < i_rMergeList.getLength(); i++ )
1396 aResult[i] = i_rMergeList[i];
1397 int nCur = i_rMergeList.getLength();
1398 for(css::beans::PropertyValue & rPropVal : mpImplData->maUIProperties)
1400 if( aMergeSet.find( rPropVal.Name ) == aMergeSet.end() )
1401 aResult[nCur++] = rPropVal;
1403 // append IsFirstPage
1404 if( aMergeSet.find( OUString( "IsFirstPage" ) ) == aMergeSet.end() )
1406 css::beans::PropertyValue aVal;
1407 aVal.Name = "IsFirstPage";
1408 aVal.Value <<= mpImplData->mbFirstPage;
1409 aResult[nCur++] = aVal;
1411 // append IsLastPage
1412 if( aMergeSet.find( OUString( "IsLastPage" ) ) == aMergeSet.end() )
1414 css::beans::PropertyValue aVal;
1415 aVal.Name = "IsLastPage";
1416 aVal.Value <<= mpImplData->mbLastPage;
1417 aResult[nCur++] = aVal;
1419 // append IsPrinter
1420 if( aMergeSet.find( OUString( "IsPrinter" ) ) == aMergeSet.end() )
1422 css::beans::PropertyValue aVal;
1423 aVal.Name = "IsPrinter";
1424 aVal.Value <<= true;
1425 aResult[nCur++] = aVal;
1427 aResult.realloc( nCur );
1428 return aResult;
1431 const css::uno::Sequence< css::beans::PropertyValue >& PrinterController::getUIOptions() const
1433 return mpImplData->maUIOptions;
1436 css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty )
1438 std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1439 mpImplData->maPropertyToIndex.find( i_rProperty );
1440 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1443 const css::beans::PropertyValue* PrinterController::getValue( const OUString& i_rProperty ) const
1445 std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1446 mpImplData->maPropertyToIndex.find( i_rProperty );
1447 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : nullptr;
1450 void PrinterController::setValue( const OUString& i_rPropertyName, const css::uno::Any& i_rValue )
1452 css::beans::PropertyValue aVal;
1453 aVal.Name = i_rPropertyName;
1454 aVal.Value = i_rValue;
1456 setValue( aVal );
1459 void PrinterController::setValue( const css::beans::PropertyValue& i_rPropertyValue )
1461 std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1462 mpImplData->maPropertyToIndex.find( i_rPropertyValue.Name );
1463 if( it != mpImplData->maPropertyToIndex.end() )
1464 mpImplData->maUIProperties[ it->second ] = i_rPropertyValue;
1465 else
1467 // insert correct index into property map
1468 mpImplData->maPropertyToIndex[ i_rPropertyValue.Name ] = mpImplData->maUIProperties.size();
1469 mpImplData->maUIProperties.push_back( i_rPropertyValue );
1470 mpImplData->maUIPropertyEnabled.push_back( true );
1474 void PrinterController::setUIOptions( const css::uno::Sequence< css::beans::PropertyValue >& i_rOptions )
1476 SAL_WARN_IF( mpImplData->maUIOptions.getLength() != 0, "vcl.gdi", "setUIOptions called twice !" );
1478 mpImplData->maUIOptions = i_rOptions;
1480 for( int i = 0; i < i_rOptions.getLength(); i++ )
1482 css::uno::Sequence< css::beans::PropertyValue > aOptProp;
1483 i_rOptions[i].Value >>= aOptProp;
1484 bool bIsEnabled = true;
1485 bool bHaveProperty = false;
1486 OUString aPropName;
1487 vcl::ImplPrinterControllerData::ControlDependency aDep;
1488 css::uno::Sequence< sal_Bool > aChoicesDisabled;
1489 for( int n = 0; n < aOptProp.getLength(); n++ )
1491 const css::beans::PropertyValue& rEntry( aOptProp[ n ] );
1492 if ( rEntry.Name == "Property" )
1494 css::beans::PropertyValue aVal;
1495 rEntry.Value >>= aVal;
1496 DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )
1497 == mpImplData->maPropertyToIndex.end(), "duplicate property entry" );
1498 setValue( aVal );
1499 aPropName = aVal.Name;
1500 bHaveProperty = true;
1502 else if ( rEntry.Name == "Enabled" )
1504 bool bValue = true;
1505 rEntry.Value >>= bValue;
1506 bIsEnabled = bValue;
1508 else if ( rEntry.Name == "DependsOnName" )
1510 rEntry.Value >>= aDep.maDependsOnName;
1512 else if ( rEntry.Name == "DependsOnEntry" )
1514 rEntry.Value >>= aDep.mnDependsOnEntry;
1516 else if ( rEntry.Name == "ChoicesDisabled" )
1518 rEntry.Value >>= aChoicesDisabled;
1521 if( bHaveProperty )
1523 vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
1524 mpImplData->maPropertyToIndex.find( aPropName );
1525 // sanity check
1526 if( it != mpImplData->maPropertyToIndex.end() )
1528 mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
1530 if( !aDep.maDependsOnName.isEmpty() )
1531 mpImplData->maControlDependencies[ aPropName ] = aDep;
1532 if( aChoicesDisabled.getLength() > 0 )
1533 mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled;
1538 bool PrinterController::isUIOptionEnabled( const OUString& i_rProperty ) const
1540 bool bEnabled = false;
1541 std::unordered_map< OUString, size_t, OUStringHash >::const_iterator prop_it =
1542 mpImplData->maPropertyToIndex.find( i_rProperty );
1543 if( prop_it != mpImplData->maPropertyToIndex.end() )
1545 bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
1547 if( bEnabled )
1549 // check control dependencies
1550 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1551 mpImplData->maControlDependencies.find( i_rProperty );
1552 if( it != mpImplData->maControlDependencies.end() )
1554 // check if the dependency is enabled
1555 // if the dependency is disabled, we are too
1556 bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
1558 if( bEnabled )
1560 // does the dependency have the correct value ?
1561 const css::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
1562 OSL_ENSURE( pVal, "unknown property in dependency" );
1563 if( pVal )
1565 sal_Int32 nDepVal = 0;
1566 bool bDepVal = false;
1567 if( pVal->Value >>= nDepVal )
1569 bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
1571 else if( pVal->Value >>= bDepVal )
1573 // could be a dependency on a checked boolean
1574 // in this case the dependency is on a non zero for checked value
1575 bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) ||
1576 ( ! bDepVal && it->second.mnDependsOnEntry == 0);
1578 else
1580 // if the type does not match something is awry
1581 OSL_FAIL( "strange type in control dependency" );
1582 bEnabled = false;
1589 return bEnabled;
1592 bool PrinterController::isUIChoiceEnabled( const OUString& i_rProperty, sal_Int32 i_nValue ) const
1594 bool bEnabled = true;
1595 ImplPrinterControllerData::ChoiceDisableMap::const_iterator it =
1596 mpImplData->maChoiceDisableMap.find( i_rProperty );
1597 if(it != mpImplData->maChoiceDisableMap.end() )
1599 const css::uno::Sequence< sal_Bool >& rDisabled( it->second );
1600 if( i_nValue >= 0 && i_nValue < rDisabled.getLength() )
1601 bEnabled = ! rDisabled[i_nValue];
1603 return bEnabled;
1606 OUString PrinterController::getDependency( const OUString& i_rProperty ) const
1608 OUString aDependency;
1610 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1611 mpImplData->maControlDependencies.find( i_rProperty );
1612 if( it != mpImplData->maControlDependencies.end() )
1613 aDependency = it->second.maDependsOnName;
1615 return aDependency;
1618 OUString PrinterController::makeEnabled( const OUString& i_rProperty )
1620 OUString aDependency;
1622 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1623 mpImplData->maControlDependencies.find( i_rProperty );
1624 if( it != mpImplData->maControlDependencies.end() )
1626 if( isUIOptionEnabled( it->second.maDependsOnName ) )
1628 aDependency = it->second.maDependsOnName;
1629 const css::beans::PropertyValue* pVal = getValue( aDependency );
1630 OSL_ENSURE( pVal, "unknown property in dependency" );
1631 if( pVal )
1633 sal_Int32 nDepVal = 0;
1634 bool bDepVal = false;
1635 if( pVal->Value >>= nDepVal )
1637 if( it->second.mnDependsOnEntry != -1 )
1639 setValue( aDependency, css::uno::makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
1642 else if( pVal->Value >>= bDepVal )
1644 setValue( aDependency, css::uno::makeAny( it->second.mnDependsOnEntry != 0 ) );
1646 else
1648 // if the type does not match something is awry
1649 OSL_FAIL( "strange type in control dependency" );
1655 return aDependency;
1658 void PrinterController::createProgressDialog()
1660 if( ! mpImplData->mpProgress )
1662 bool bShow = true;
1663 css::beans::PropertyValue* pMonitor = getValue( OUString( "MonitorVisible" ) );
1664 if( pMonitor )
1665 pMonitor->Value >>= bShow;
1666 else
1668 const css::beans::PropertyValue* pVal = getValue( OUString( "IsApi" ) );
1669 if( pVal )
1671 bool bApi = false;
1672 pVal->Value >>= bApi;
1673 bShow = ! bApi;
1677 if( bShow && ! Application::IsHeadlessModeEnabled() )
1679 mpImplData->mpProgress = VclPtr<PrintProgressDialog>::Create( nullptr, getPageCountProtected() );
1680 mpImplData->mpProgress->Show();
1683 else
1684 mpImplData->mpProgress->reset();
1687 bool PrinterController::isProgressCanceled() const
1689 return mpImplData->mpProgress && mpImplData->mpProgress->isCanceled();
1692 void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
1694 mpImplData->maMultiPage = i_rMPS;
1697 const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
1699 return mpImplData->maMultiPage;
1702 void PrinterController::resetPaperToLastConfigured()
1704 mpImplData->resetPaperToLastConfigured();
1707 void PrinterController::pushPropertiesToPrinter()
1709 sal_Int32 nCopyCount = 1;
1710 // set copycount and collate
1711 const css::beans::PropertyValue* pVal = getValue( OUString( "CopyCount" ) );
1712 if( pVal )
1713 pVal->Value >>= nCopyCount;
1714 bool bCollate = false;
1715 pVal = getValue( OUString( "Collate" ) );
1716 if( pVal )
1717 pVal->Value >>= bCollate;
1718 mpImplData->mxPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate );
1720 // duplex mode
1721 pVal = getValue( OUString( "DuplexMode" ) );
1722 if( pVal )
1724 sal_Int16 nDuplex = css::view::DuplexMode::UNKNOWN;
1725 pVal->Value >>= nDuplex;
1726 switch( nDuplex )
1728 case css::view::DuplexMode::OFF: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::Off ); break;
1729 case css::view::DuplexMode::LONGEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::LongEdge ); break;
1730 case css::view::DuplexMode::SHORTEDGE: mpImplData->mxPrinter->SetDuplexMode( DuplexMode::ShortEdge ); break;
1735 bool PrinterController::isShowDialogs() const
1737 bool bApi = getBoolProperty( "IsApi", false );
1738 return ! bApi && ! Application::IsHeadlessModeEnabled();
1741 bool PrinterController::isDirectPrint() const
1743 bool bDirect = getBoolProperty( "IsDirect", false );
1744 return bDirect;
1747 bool PrinterController::getBoolProperty( const OUString& i_rProperty, bool i_bFallback ) const
1749 bool bRet = i_bFallback;
1750 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1751 if( pVal )
1752 pVal->Value >>= bRet;
1753 return bRet;
1756 sal_Int32 PrinterController::getIntProperty( const OUString& i_rProperty, sal_Int32 i_nFallback ) const
1758 sal_Int32 nRet = i_nFallback;
1759 const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1760 if( pVal )
1761 pVal->Value >>= nRet;
1762 return nRet;
1766 * PrinterOptionsHelper
1768 css::uno::Any PrinterOptionsHelper::getValue( const OUString& i_rPropertyName ) const
1770 css::uno::Any aRet;
1771 std::unordered_map< OUString, css::uno::Any, OUStringHash >::const_iterator it =
1772 m_aPropertyMap.find( i_rPropertyName );
1773 if( it != m_aPropertyMap.end() )
1774 aRet = it->second;
1775 return aRet;
1778 bool PrinterOptionsHelper::getBoolValue( const OUString& i_rPropertyName, bool i_bDefault ) const
1780 bool bRet = false;
1781 css::uno::Any aVal( getValue( i_rPropertyName ) );
1782 return (aVal >>= bRet) ? bRet : i_bDefault;
1785 sal_Int64 PrinterOptionsHelper::getIntValue( const OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
1787 sal_Int64 nRet = 0;
1788 css::uno::Any aVal( getValue( i_rPropertyName ) );
1789 return (aVal >>= nRet) ? nRet : i_nDefault;
1792 OUString PrinterOptionsHelper::getStringValue( const OUString& i_rPropertyName ) const
1794 OUString aRet;
1795 css::uno::Any aVal( getValue( i_rPropertyName ) );
1796 return (aVal >>= aRet) ? aRet : OUString();
1799 bool PrinterOptionsHelper::processProperties( const css::uno::Sequence< css::beans::PropertyValue >& i_rNewProp )
1801 bool bChanged = false;
1803 sal_Int32 nElements = i_rNewProp.getLength();
1804 const css::beans::PropertyValue* pVals = i_rNewProp.getConstArray();
1805 for( sal_Int32 i = 0; i < nElements; i++ )
1807 bool bElementChanged = false;
1808 std::unordered_map< OUString, css::uno::Any, OUStringHash >::iterator it =
1809 m_aPropertyMap.find( pVals[ i ].Name );
1810 if( it != m_aPropertyMap.end() )
1812 if( it->second != pVals[ i ].Value )
1813 bElementChanged = true;
1815 else
1816 bElementChanged = true;
1818 if( bElementChanged )
1820 m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value;
1821 bChanged = true;
1824 return bChanged;
1827 void PrinterOptionsHelper::appendPrintUIOptions( css::uno::Sequence< css::beans::PropertyValue >& io_rProps ) const
1829 if( !m_aUIProperties.empty() )
1831 sal_Int32 nIndex = io_rProps.getLength();
1832 io_rProps.realloc( nIndex+1 );
1833 css::beans::PropertyValue aVal;
1834 aVal.Name = "ExtraPrintUIOptions";
1835 aVal.Value <<= comphelper::containerToSequence(m_aUIProperties);
1836 io_rProps[ nIndex ] = aVal;
1840 css::uno::Any PrinterOptionsHelper::setUIControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1841 const OUString& i_rTitle,
1842 const css::uno::Sequence< OUString >& i_rHelpIds,
1843 const OUString& i_rType,
1844 const css::beans::PropertyValue* i_pVal,
1845 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1847 sal_Int32 nElements =
1848 2 // ControlType + ID
1849 + (i_rTitle.isEmpty() ? 0 : 1) // Text
1850 + (i_rHelpIds.getLength() ? 1 : 0) // HelpId
1851 + (i_pVal ? 1 : 0) // Property
1852 + i_rControlOptions.maAddProps.size() // additional props
1853 + (i_rControlOptions.maGroupHint.isEmpty() ? 0 : 1) // grouping
1854 + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint
1855 + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled
1857 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1859 nElements += 1;
1860 if( i_rControlOptions.mnDependsOnEntry != -1 )
1861 nElements += 1;
1862 if( i_rControlOptions.mbAttachToDependency )
1863 nElements += 1;
1866 css::uno::Sequence< css::beans::PropertyValue > aCtrl( nElements );
1867 sal_Int32 nUsed = 0;
1868 if( !i_rTitle.isEmpty() )
1870 aCtrl[nUsed ].Name = "Text";
1871 aCtrl[nUsed++].Value <<= i_rTitle;
1873 if( i_rHelpIds.getLength() )
1875 aCtrl[nUsed ].Name = "HelpId";
1876 aCtrl[nUsed++].Value <<= i_rHelpIds;
1878 aCtrl[nUsed ].Name = "ControlType";
1879 aCtrl[nUsed++].Value <<= i_rType;
1880 aCtrl[nUsed ].Name = "ID";
1881 aCtrl[nUsed++].Value <<= i_rIDs;
1882 if( i_pVal )
1884 aCtrl[nUsed ].Name = "Property";
1885 aCtrl[nUsed++].Value <<= *i_pVal;
1887 if( !i_rControlOptions.maDependsOnName.isEmpty() )
1889 aCtrl[nUsed ].Name = "DependsOnName";
1890 aCtrl[nUsed++].Value <<= i_rControlOptions.maDependsOnName;
1891 if( i_rControlOptions.mnDependsOnEntry != -1 )
1893 aCtrl[nUsed ].Name = "DependsOnEntry";
1894 aCtrl[nUsed++].Value <<= i_rControlOptions.mnDependsOnEntry;
1896 if( i_rControlOptions.mbAttachToDependency )
1898 aCtrl[nUsed ].Name = "AttachToDependency";
1899 aCtrl[nUsed++].Value <<= i_rControlOptions.mbAttachToDependency;
1902 if( !i_rControlOptions.maGroupHint.isEmpty() )
1904 aCtrl[nUsed ].Name = "GroupingHint";
1905 aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
1907 if( i_rControlOptions.mbInternalOnly )
1909 aCtrl[nUsed ].Name = "InternalUIOnly";
1910 aCtrl[nUsed++].Value <<= true;
1912 if( ! i_rControlOptions.mbEnabled )
1914 aCtrl[nUsed ].Name = "Enabled";
1915 aCtrl[nUsed++].Value <<= false;
1918 sal_Int32 nAddProps = i_rControlOptions.maAddProps.size();
1919 for( sal_Int32 i = 0; i < nAddProps; i++ )
1920 aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
1922 SAL_WARN_IF( nUsed != nElements, "vcl.gdi", "nUsed != nElements, probable heap corruption" );
1924 return css::uno::makeAny( aCtrl );
1927 css::uno::Any PrinterOptionsHelper::setGroupControlOpt(const OUString& i_rID,
1928 const OUString& i_rTitle,
1929 const OUString& i_rHelpId)
1931 css::uno::Sequence< OUString > aHelpId;
1932 if( !i_rHelpId.isEmpty() )
1934 aHelpId.realloc( 1 );
1935 *aHelpId.getArray() = i_rHelpId;
1937 css::uno::Sequence< OUString > aIds { i_rID };
1938 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Group");
1941 css::uno::Any PrinterOptionsHelper::setSubgroupControlOpt(const OUString& i_rID,
1942 const OUString& i_rTitle,
1943 const OUString& i_rHelpId,
1944 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1946 css::uno::Sequence< OUString > aHelpId;
1947 if( !i_rHelpId.isEmpty() )
1949 aHelpId.realloc( 1 );
1950 *aHelpId.getArray() = i_rHelpId;
1952 css::uno::Sequence< OUString > aIds { i_rID };
1953 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Subgroup", nullptr, i_rControlOptions);
1956 css::uno::Any PrinterOptionsHelper::setBoolControlOpt(const OUString& i_rID,
1957 const OUString& i_rTitle,
1958 const OUString& i_rHelpId,
1959 const OUString& i_rProperty,
1960 bool i_bValue,
1961 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1963 css::uno::Sequence< OUString > aHelpId;
1964 if( !i_rHelpId.isEmpty() )
1966 aHelpId.realloc( 1 );
1967 *aHelpId.getArray() = i_rHelpId;
1969 css::beans::PropertyValue aVal;
1970 aVal.Name = i_rProperty;
1971 aVal.Value <<= i_bValue;
1972 css::uno::Sequence< OUString > aIds { i_rID };
1973 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Bool", &aVal, i_rControlOptions);
1976 css::uno::Any PrinterOptionsHelper::setChoiceRadiosControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1977 const OUString& i_rTitle,
1978 const css::uno::Sequence< OUString >& i_rHelpId,
1979 const OUString& i_rProperty,
1980 const css::uno::Sequence< OUString >& i_rChoices,
1981 sal_Int32 i_nValue,
1982 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
1983 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1985 UIControlOptions aOpt( i_rControlOptions );
1986 sal_Int32 nUsed = aOpt.maAddProps.size();
1987 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) );
1988 aOpt.maAddProps[nUsed].Name = "Choices";
1989 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
1990 if( i_rDisabledChoices.getLength() )
1992 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
1993 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
1996 css::beans::PropertyValue aVal;
1997 aVal.Name = i_rProperty;
1998 aVal.Value <<= i_nValue;
1999 return setUIControlOpt(i_rIDs, i_rTitle, i_rHelpId, "Radio", &aVal, aOpt);
2002 css::uno::Any PrinterOptionsHelper::setChoiceListControlOpt(const OUString& i_rID,
2003 const OUString& i_rTitle,
2004 const css::uno::Sequence< OUString >& i_rHelpId,
2005 const OUString& i_rProperty,
2006 const css::uno::Sequence< OUString >& i_rChoices,
2007 sal_Int32 i_nValue,
2008 const css::uno::Sequence< sal_Bool >& i_rDisabledChoices,
2009 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2011 UIControlOptions aOpt( i_rControlOptions );
2012 sal_Int32 nUsed = aOpt.maAddProps.size();
2013 aOpt.maAddProps.resize( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) );
2014 aOpt.maAddProps[nUsed].Name = "Choices";
2015 aOpt.maAddProps[nUsed].Value <<= i_rChoices;
2016 if( i_rDisabledChoices.getLength() )
2018 aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2019 aOpt.maAddProps[nUsed+1].Value <<= i_rDisabledChoices;
2022 css::beans::PropertyValue aVal;
2023 aVal.Name = i_rProperty;
2024 aVal.Value <<= i_nValue;
2025 css::uno::Sequence< OUString > aIds { i_rID };
2026 return setUIControlOpt(aIds, i_rTitle, i_rHelpId, "List", &aVal, aOpt);
2029 css::uno::Any PrinterOptionsHelper::setRangeControlOpt(const OUString& i_rID,
2030 const OUString& i_rTitle,
2031 const OUString& i_rHelpId,
2032 const OUString& i_rProperty,
2033 sal_Int32 i_nValue,
2034 sal_Int32 i_nMinValue,
2035 sal_Int32 i_nMaxValue,
2036 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2038 UIControlOptions aOpt( i_rControlOptions );
2039 if( i_nMaxValue >= i_nMinValue )
2041 sal_Int32 nUsed = aOpt.maAddProps.size();
2042 aOpt.maAddProps.resize( nUsed + 2 );
2043 aOpt.maAddProps[nUsed ].Name = "MinValue";
2044 aOpt.maAddProps[nUsed++].Value <<= i_nMinValue;
2045 aOpt.maAddProps[nUsed ].Name = "MaxValue";
2046 aOpt.maAddProps[nUsed++].Value <<= i_nMaxValue;
2049 css::uno::Sequence< OUString > aHelpId;
2050 if( !i_rHelpId.isEmpty() )
2052 aHelpId.realloc( 1 );
2053 *aHelpId.getArray() = i_rHelpId;
2055 css::beans::PropertyValue aVal;
2056 aVal.Name = i_rProperty;
2057 aVal.Value <<= i_nValue;
2058 css::uno::Sequence< OUString > aIds { i_rID };
2059 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Range", &aVal, aOpt);
2062 css::uno::Any PrinterOptionsHelper::setEditControlOpt(const OUString& i_rID,
2063 const OUString& i_rTitle,
2064 const OUString& i_rHelpId,
2065 const OUString& i_rProperty,
2066 const OUString& i_rValue,
2067 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2069 css::uno::Sequence< OUString > aHelpId;
2070 if( !i_rHelpId.isEmpty() )
2072 aHelpId.realloc( 1 );
2073 *aHelpId.getArray() = i_rHelpId;
2075 css::beans::PropertyValue aVal;
2076 aVal.Name = i_rProperty;
2077 aVal.Value <<= i_rValue;
2078 css::uno::Sequence< OUString > aIds { i_rID };
2079 return setUIControlOpt(aIds, i_rTitle, aHelpId, "Edit", &aVal, i_rControlOptions);
2082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */