Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "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 :
27 : #include "printdlg.hxx"
28 : #include "svdata.hxx"
29 : #include "salinst.hxx"
30 : #include "salprn.hxx"
31 : #include "svids.hrc"
32 :
33 : #include "tools/urlobj.hxx"
34 :
35 : #include "com/sun/star/container/XNameAccess.hpp"
36 : #include "com/sun/star/ui/dialogs/FilePicker.hpp"
37 : #include "com/sun/star/ui/dialogs/XFilterManager.hpp"
38 : #include "com/sun/star/ui/dialogs/TemplateDescription.hpp"
39 : #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
40 : #include "com/sun/star/view/DuplexMode.hpp"
41 : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
42 : #include "com/sun/star/awt/Size.hpp"
43 : #include "comphelper/processfactory.hxx"
44 :
45 : #include <unordered_map>
46 : #include <unordered_set>
47 :
48 : using namespace com::sun::star;
49 : using namespace com::sun::star::uno;
50 : using namespace com::sun::star::beans;
51 : using namespace vcl;
52 :
53 0 : class ImplPageCache
54 : {
55 0 : struct CacheEntry
56 : {
57 : GDIMetaFile aPage;
58 : PrinterController::PageSize aSize;
59 : };
60 :
61 : std::vector< CacheEntry > maPages;
62 : std::vector< sal_Int32 > maPageNumbers;
63 : std::vector< sal_Int32 > maCacheRanking;
64 :
65 : static const sal_Int32 nCacheSize = 6;
66 :
67 0 : void updateRanking( sal_Int32 nLastHit )
68 : {
69 0 : if( maCacheRanking[0] != nLastHit )
70 : {
71 0 : for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
72 0 : maCacheRanking[i] = maCacheRanking[i-1];
73 0 : maCacheRanking[0] = nLastHit;
74 : }
75 0 : }
76 :
77 : public:
78 0 : ImplPageCache()
79 : : maPages( nCacheSize )
80 : , maPageNumbers( nCacheSize, -1 )
81 0 : , maCacheRanking( nCacheSize )
82 : {
83 0 : for( sal_Int32 i = 0; i < nCacheSize; i++ )
84 0 : maCacheRanking[i] = nCacheSize - i - 1;
85 0 : }
86 :
87 : // caution: does not ensure uniqueness
88 0 : void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
89 : {
90 0 : sal_Int32 nReplacePage = maCacheRanking.back();
91 0 : maPages[ nReplacePage ].aPage = i_rPage;
92 0 : maPages[ nReplacePage ].aSize = i_rSize;
93 0 : maPageNumbers[ nReplacePage ] = i_nPageNo;
94 : // cache insertion means in our case, the page was just queried
95 : // so update the ranking
96 0 : updateRanking( nReplacePage );
97 0 : }
98 :
99 : // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
100 : // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
101 : // whole pages can be rather memory intensive
102 0 : bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
103 : {
104 0 : for( sal_Int32 i = 0; i < nCacheSize; ++i )
105 : {
106 0 : if( maPageNumbers[i] == i_nPageNo )
107 : {
108 0 : updateRanking( i );
109 0 : o_rPageFile = maPages[i].aPage;
110 0 : o_rSize = maPages[i].aSize;
111 0 : return true;
112 : }
113 : }
114 0 : return false;
115 : }
116 :
117 0 : void invalidate()
118 : {
119 0 : for( sal_Int32 i = 0; i < nCacheSize; ++i )
120 : {
121 0 : maPageNumbers[i] = -1;
122 0 : maPages[i].aPage.Clear();
123 0 : maCacheRanking[i] = nCacheSize - i - 1;
124 : }
125 0 : }
126 : };
127 :
128 : class vcl::ImplPrinterControllerData
129 : {
130 : public:
131 0 : struct ControlDependency
132 : {
133 : OUString maDependsOnName;
134 : sal_Int32 mnDependsOnEntry;
135 :
136 0 : ControlDependency() : mnDependsOnEntry( -1 ) {}
137 : };
138 :
139 : typedef std::unordered_map< OUString, size_t, OUStringHash > PropertyToIndexMap;
140 : typedef std::unordered_map< OUString, ControlDependency, OUStringHash > ControlDependencyMap;
141 : typedef std::unordered_map< OUString, Sequence< sal_Bool >, OUStringHash > ChoiceDisableMap;
142 :
143 : VclPtr< Printer > mxPrinter;
144 : Sequence< PropertyValue > maUIOptions;
145 : std::vector< PropertyValue > maUIProperties;
146 : std::vector< bool > maUIPropertyEnabled;
147 : PropertyToIndexMap maPropertyToIndex;
148 : Link<> maOptionChangeHdl;
149 : ControlDependencyMap maControlDependencies;
150 : ChoiceDisableMap maChoiceDisableMap;
151 : bool mbFirstPage;
152 : bool mbLastPage;
153 : bool mbReversePageOrder;
154 : bool mbPapersizeFromSetup;
155 : view::PrintableState meJobState;
156 :
157 : vcl::PrinterController::MultiPageSetup maMultiPage;
158 :
159 : VclPtr<vcl::PrintProgressDialog> mpProgress;
160 :
161 : ImplPageCache maPageCache;
162 :
163 : // set by user through printer properties subdialog of printer settings dialog
164 : Size maDefaultPageSize;
165 : // set by user through printer properties subdialog of printer settings dialog
166 : sal_Int32 mnDefaultPaperBin;
167 : // Set by user through printer properties subdialog of print dialog.
168 : // Overrides application-set tray for a page.
169 : sal_Int32 mnFixedPaperBin;
170 :
171 : // N.B. Apparently we have three levels of paper tray settings
172 : // (latter overrides former):
173 : // 1. default tray
174 : // 2. tray set for a concrete page by an application, e.g., writer
175 : // allows setting a printer tray (for the default printer) for a
176 : // page style. This setting can be overridden by user by selecting
177 : // "Use only paper tray from printer preferences" on the Options
178 : // page in the print dialog, in which case the default tray is
179 : // used for all pages.
180 : // 3. tray set in printer properties the printer dialog
181 : // I'm not quite sure why 1. and 3. are distinct, but the commit
182 : // history suggests this is intentional...
183 :
184 0 : ImplPrinterControllerData() :
185 : mbFirstPage( true ),
186 : mbLastPage( false ),
187 : mbReversePageOrder( false ),
188 : mbPapersizeFromSetup( false ),
189 : meJobState( view::PrintableState_JOB_STARTED ),
190 : mpProgress( NULL ),
191 : mnDefaultPaperBin( -1 ),
192 0 : mnFixedPaperBin( -1 )
193 0 : {}
194 0 : ~ImplPrinterControllerData() { mpProgress.disposeAndClear(); }
195 :
196 0 : Size getRealPaperSize( const Size& i_rPageSize, bool bNoNUP ) const
197 : {
198 0 : if( mbPapersizeFromSetup )
199 0 : return maDefaultPageSize;
200 0 : if( maMultiPage.nRows * maMultiPage.nColumns > 1 && ! bNoNUP )
201 0 : return maMultiPage.aPaperSize;
202 0 : return i_rPageSize;
203 : }
204 0 : bool isFixedPageSize() const
205 0 : { return mbPapersizeFromSetup; }
206 : PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP );
207 : void resetPaperToLastConfigured();
208 : };
209 :
210 0 : PrinterController::PrinterController( const VclPtr<Printer>& i_xPrinter )
211 0 : : mpImplData( new ImplPrinterControllerData )
212 : {
213 0 : mpImplData->mxPrinter = i_xPrinter;
214 0 : }
215 :
216 0 : static OUString queryFile( Printer* pPrinter )
217 : {
218 0 : OUString aResult;
219 :
220 0 : uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
221 0 : uno::Reference< ui::dialogs::XFilePicker3 > xFilePicker = ui::dialogs::FilePicker::createWithMode(xContext, ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION);
222 :
223 : try
224 : {
225 : #ifdef UNX
226 : // add PostScript and PDF
227 0 : bool bPS = true, bPDF = true;
228 0 : if( pPrinter )
229 : {
230 0 : if( pPrinter->GetCapabilities( PrinterCapType::PDF ) )
231 0 : bPS = false;
232 : else
233 0 : bPDF = false;
234 : }
235 0 : if( bPS )
236 0 : xFilePicker->appendFilter( OUString( "PostScript" ), OUString( "*.ps" ) );
237 0 : if( bPDF )
238 0 : xFilePicker->appendFilter( OUString( "Portable Document Format" ), OUString( "*.pdf" ) );
239 : #elif defined WNT
240 : (void)pPrinter;
241 : xFilePicker->appendFilter( OUString( "*.PRN" ), OUString( "*.prn" ) );
242 : #endif
243 : // add arbitrary files
244 0 : xFilePicker->appendFilter(VclResId(SV_STDTEXT_ALLFILETYPES), "*.*");
245 : }
246 0 : catch (const lang::IllegalArgumentException&)
247 : {
248 : SAL_WARN( "vcl.gdi", "caught IllegalArgumentException when registering filter" );
249 : }
250 :
251 0 : if( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK )
252 : {
253 0 : uno::Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
254 0 : INetURLObject aObj( aPathSeq[0] );
255 0 : aResult = aObj.PathToFileName();
256 : }
257 0 : return aResult;
258 : }
259 :
260 0 : struct PrintJobAsync
261 : {
262 : std::shared_ptr<PrinterController> mxController;
263 : JobSetup maInitSetup;
264 :
265 0 : PrintJobAsync(const std::shared_ptr<PrinterController>& i_xController,
266 : const JobSetup& i_rInitSetup)
267 0 : : mxController( i_xController ), maInitSetup( i_rInitSetup )
268 0 : {}
269 :
270 : DECL_LINK( ExecJob, void* );
271 : };
272 :
273 0 : IMPL_LINK_NOARG(PrintJobAsync, ExecJob)
274 : {
275 0 : Printer::ImplPrintJob(mxController, maInitSetup);
276 :
277 : // clean up, do not access members after this
278 0 : delete this;
279 :
280 0 : return 0;
281 : }
282 :
283 0 : void Printer::PrintJob(const std::shared_ptr<PrinterController>& i_xController,
284 : const JobSetup& i_rInitSetup)
285 : {
286 0 : bool bSynchronous = false;
287 0 : PropertyValue* pVal = i_xController->getValue( OUString( "Wait" ) );
288 0 : if( pVal )
289 0 : pVal->Value >>= bSynchronous;
290 :
291 0 : if( bSynchronous )
292 0 : ImplPrintJob(i_xController, i_rInitSetup);
293 : else
294 : {
295 0 : PrintJobAsync* pAsync = new PrintJobAsync(i_xController, i_rInitSetup);
296 0 : Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) );
297 : }
298 0 : }
299 :
300 0 : bool Printer::PreparePrintJob(std::shared_ptr<PrinterController> xController,
301 : const JobSetup& i_rInitSetup)
302 : {
303 : // check if there is a default printer; if not, show an error box (if appropriate)
304 0 : if( GetDefaultPrinterName().isEmpty() )
305 : {
306 0 : if (xController->isShowDialogs())
307 : {
308 : ScopedVclPtrInstance<MessageDialog> aBox(
309 : nullptr, "ErrorNoPrinterDialog",
310 0 : "vcl/ui/errornoprinterdialog.ui");
311 0 : aBox->Execute();
312 : }
313 : xController->setValue( OUString( "IsDirect" ),
314 0 : makeAny( false ) );
315 : }
316 :
317 : // setup printer
318 :
319 : // #i114306# changed behavior back from persistence
320 : // if no specific printer is already set, create the default printer
321 0 : if (!xController->getPrinter())
322 : {
323 0 : OUString aPrinterName( i_rInitSetup.GetPrinterName() );
324 0 : VclPtrInstance<Printer> xPrinter( aPrinterName );
325 0 : xPrinter->SetJobSetup(i_rInitSetup);
326 0 : xController->setPrinter(xPrinter);
327 : }
328 :
329 : // reset last page property
330 0 : xController->setLastPage(false);
331 :
332 : // update "PageRange" property inferring from other properties:
333 : // case 1: "Pages" set from UNO API ->
334 : // setup "Print Selection" and insert "PageRange" attribute
335 : // case 2: "All pages" is selected
336 : // update "Page range" attribute to have a sensible default,
337 : // but leave "All" as selected
338 :
339 : // "Pages" attribute from API is now equivalent to "PageRange"
340 : // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
341 : // Argh ! That sure needs cleaning up
342 0 : PropertyValue* pContentVal = xController->getValue(OUString("PrintRange"));
343 0 : if( ! pContentVal )
344 0 : pContentVal = xController->getValue(OUString("PrintContent"));
345 :
346 : // case 1: UNO API has set "Pages"
347 0 : PropertyValue* pPagesVal = xController->getValue(OUString("Pages"));
348 0 : if( pPagesVal )
349 : {
350 0 : OUString aPagesVal;
351 0 : pPagesVal->Value >>= aPagesVal;
352 0 : if( !aPagesVal.isEmpty() )
353 : {
354 : // "Pages" attribute from API is now equivalent to "PageRange"
355 : // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
356 : // Argh ! That sure needs cleaning up
357 0 : if( pContentVal )
358 : {
359 0 : pContentVal->Value = makeAny( sal_Int32( 1 ) );
360 0 : xController->setValue(OUString("PageRange"), pPagesVal->Value);
361 : }
362 0 : }
363 : }
364 : // case 2: is "All" selected ?
365 0 : else if( pContentVal )
366 : {
367 0 : sal_Int32 nContent = -1;
368 0 : if( pContentVal->Value >>= nContent )
369 : {
370 0 : if( nContent == 0 )
371 : {
372 : // do not overwrite PageRange if it is already set
373 0 : PropertyValue* pRangeVal = xController->getValue(OUString("PageRange"));
374 0 : OUString aRange;
375 0 : if( pRangeVal )
376 0 : pRangeVal->Value >>= aRange;
377 0 : if( aRange.isEmpty() )
378 : {
379 0 : sal_Int32 nPages = xController->getPageCount();
380 0 : if( nPages > 0 )
381 : {
382 0 : OUStringBuffer aBuf( 32 );
383 0 : aBuf.appendAscii( "1" );
384 0 : if( nPages > 1 )
385 : {
386 0 : aBuf.appendAscii( "-" );
387 0 : aBuf.append( nPages );
388 : }
389 0 : xController->setValue(OUString("PageRange"), makeAny(aBuf.makeStringAndClear()));
390 : }
391 0 : }
392 : }
393 : }
394 : }
395 :
396 0 : PropertyValue* pReverseVal = xController->getValue(OUString("PrintReverse"));
397 0 : if( pReverseVal )
398 : {
399 0 : bool bReverse = false;
400 0 : pReverseVal->Value >>= bReverse;
401 0 : xController->setReversePrint( bReverse );
402 : }
403 :
404 0 : PropertyValue* pPapersizeFromSetupVal = xController->getValue(OUString("PapersizeFromSetup"));
405 0 : if( pPapersizeFromSetupVal )
406 : {
407 0 : bool bPapersizeFromSetup = false;
408 0 : pPapersizeFromSetupVal->Value >>= bPapersizeFromSetup;
409 0 : xController->setPapersizeFromSetup(bPapersizeFromSetup);
410 : }
411 :
412 : // setup NUp printing from properties
413 0 : sal_Int32 nRows = xController->getIntProperty(OUString("NUpRows"), 1);
414 0 : sal_Int32 nCols = xController->getIntProperty(OUString("NUpColumns"), 1);
415 0 : if( nRows > 1 || nCols > 1 )
416 : {
417 0 : PrinterController::MultiPageSetup aMPS;
418 0 : aMPS.nRows = nRows > 1 ? nRows : 1;
419 0 : aMPS.nColumns = nCols > 1 ? nCols : 1;
420 0 : sal_Int32 nValue = xController->getIntProperty(OUString("NUpPageMarginLeft"), aMPS.nLeftMargin);
421 0 : if( nValue >= 0 )
422 0 : aMPS.nLeftMargin = nValue;
423 0 : nValue = xController->getIntProperty(OUString("NUpPageMarginRight"), aMPS.nRightMargin);
424 0 : if( nValue >= 0 )
425 0 : aMPS.nRightMargin = nValue;
426 0 : nValue = xController->getIntProperty( OUString( "NUpPageMarginTop" ), aMPS.nTopMargin );
427 0 : if( nValue >= 0 )
428 0 : aMPS.nTopMargin = nValue;
429 0 : nValue = xController->getIntProperty( OUString( "NUpPageMarginBottom" ), aMPS.nBottomMargin );
430 0 : if( nValue >= 0 )
431 0 : aMPS.nBottomMargin = nValue;
432 0 : nValue = xController->getIntProperty( OUString( "NUpHorizontalSpacing" ), aMPS.nHorizontalSpacing );
433 0 : if( nValue >= 0 )
434 0 : aMPS.nHorizontalSpacing = nValue;
435 0 : nValue = xController->getIntProperty( OUString( "NUpVerticalSpacing" ), aMPS.nVerticalSpacing );
436 0 : if( nValue >= 0 )
437 0 : aMPS.nVerticalSpacing = nValue;
438 0 : aMPS.bDrawBorder = xController->getBoolProperty( OUString( "NUpDrawBorder" ), aMPS.bDrawBorder );
439 0 : aMPS.nOrder = static_cast<PrinterController::NupOrderType>(xController->getIntProperty( OUString( "NUpSubPageOrder" ), aMPS.nOrder ));
440 0 : aMPS.aPaperSize = xController->getPrinter()->PixelToLogic( xController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
441 0 : PropertyValue* pPgSizeVal = xController->getValue( OUString( "NUpPaperSize" ) );
442 0 : awt::Size aSizeVal;
443 0 : if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
444 : {
445 0 : aMPS.aPaperSize.Width() = aSizeVal.Width;
446 0 : aMPS.aPaperSize.Height() = aSizeVal.Height;
447 : }
448 :
449 0 : xController->setMultipage( aMPS );
450 : }
451 :
452 : // in direct print case check whether there is anything to print.
453 : // if not, show an errorbox (if appropriate)
454 0 : if( xController->isShowDialogs() && xController->isDirectPrint() )
455 : {
456 0 : if( xController->getFilteredPageCount() == 0 )
457 : {
458 : ScopedVclPtrInstance<MessageDialog> aBox(
459 : nullptr, "ErrorNoContentDialog",
460 0 : "vcl/ui/errornocontentdialog.ui");
461 0 : aBox->Execute();
462 0 : return false;
463 : }
464 : }
465 :
466 : // check if the printer brings up its own dialog
467 : // in that case leave the work to that dialog
468 0 : if( ! xController->getPrinter()->GetCapabilities( PrinterCapType::ExternalDialog ) &&
469 0 : ! xController->isDirectPrint() &&
470 0 : xController->isShowDialogs()
471 : )
472 : {
473 : try
474 : {
475 0 : ScopedVclPtrInstance< PrintDialog > aDlg( nullptr, xController );
476 0 : if( ! aDlg->Execute() )
477 : {
478 0 : xController->abortJob();
479 0 : return false;
480 : }
481 0 : if( aDlg->isPrintToFile() )
482 : {
483 0 : OUString aFile = queryFile( xController->getPrinter().get() );
484 0 : if( aFile.isEmpty() )
485 : {
486 0 : xController->abortJob();
487 0 : return false;
488 : }
489 : xController->setValue( OUString( "LocalFileName" ),
490 0 : makeAny( aFile ) );
491 : }
492 0 : else if( aDlg->isSingleJobs() )
493 : {
494 : xController->setValue( OUString( "PrintCollateAsSingleJobs" ),
495 0 : makeAny( true ) );
496 0 : }
497 : }
498 0 : catch (const std::bad_alloc&)
499 : {
500 : }
501 : }
502 :
503 0 : xController->pushPropertiesToPrinter();
504 0 : return true;
505 : }
506 :
507 0 : bool Printer::ExecutePrintJob(std::shared_ptr<PrinterController> xController)
508 : {
509 0 : OUString aJobName;
510 0 : PropertyValue* pJobNameVal = xController->getValue( OUString( "JobName" ) );
511 0 : if( pJobNameVal )
512 0 : pJobNameVal->Value >>= aJobName;
513 :
514 0 : return xController->getPrinter()->StartJob( aJobName, xController );
515 : }
516 :
517 0 : void Printer::FinishPrintJob(std::shared_ptr<PrinterController> xController)
518 : {
519 0 : xController->resetPaperToLastConfigured();
520 0 : xController->jobFinished( xController->getJobState() );
521 0 : }
522 :
523 0 : void Printer::ImplPrintJob(std::shared_ptr<PrinterController> xController,
524 : const JobSetup& i_rInitSetup)
525 : {
526 0 : if (PreparePrintJob(xController, i_rInitSetup))
527 : {
528 0 : ExecutePrintJob(xController);
529 : }
530 0 : FinishPrintJob(xController);
531 0 : }
532 :
533 0 : bool Printer::StartJob( const OUString& i_rJobName, std::shared_ptr<vcl::PrinterController>& i_xController)
534 : {
535 0 : mnError = PRINTER_OK;
536 :
537 0 : if ( IsDisplayPrinter() )
538 0 : return false;
539 :
540 0 : if ( IsJobActive() || IsPrinting() )
541 0 : return false;
542 :
543 0 : sal_uLong nCopies = mnCopyCount;
544 0 : bool bCollateCopy = mbCollateCopy;
545 0 : bool bUserCopy = false;
546 :
547 0 : if ( nCopies > 1 )
548 : {
549 : sal_uLong nDevCopy;
550 :
551 0 : if ( bCollateCopy )
552 0 : nDevCopy = GetCapabilities( PrinterCapType::CollateCopies );
553 : else
554 0 : nDevCopy = GetCapabilities( PrinterCapType::Copies );
555 :
556 : // need to do copies by hand ?
557 0 : if ( nCopies > nDevCopy )
558 : {
559 0 : bUserCopy = true;
560 0 : nCopies = 1;
561 0 : bCollateCopy = false;
562 : }
563 : }
564 : else
565 0 : bCollateCopy = false;
566 :
567 0 : ImplSVData* pSVData = ImplGetSVData();
568 0 : mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
569 :
570 0 : if (!mpPrinter)
571 0 : return false;
572 :
573 0 : bool bSinglePrintJobs = false;
574 0 : PropertyValue* pSingleValue = i_xController->getValue(OUString("PrintCollateAsSingleJobs"));
575 0 : if( pSingleValue )
576 : {
577 0 : pSingleValue->Value >>= bSinglePrintJobs;
578 : }
579 :
580 0 : PropertyValue* pFileValue = i_xController->getValue(OUString("LocalFileName"));
581 0 : if( pFileValue )
582 : {
583 0 : OUString aFile;
584 0 : pFileValue->Value >>= aFile;
585 0 : if( !aFile.isEmpty() )
586 : {
587 0 : mbPrintFile = true;
588 0 : maPrintFile = aFile;
589 0 : bSinglePrintJobs = false;
590 0 : }
591 : }
592 :
593 0 : OUString* pPrintFile = NULL;
594 0 : if ( mbPrintFile )
595 0 : pPrintFile = &maPrintFile;
596 0 : mpPrinterOptions->ReadFromConfig( mbPrintFile );
597 :
598 0 : maJobName = i_rJobName;
599 0 : mnCurPage = 1;
600 0 : mnCurPrintPage = 1;
601 0 : mbPrinting = true;
602 0 : if( GetCapabilities( PrinterCapType::UsePullModel ) )
603 : {
604 0 : mbJobActive = true;
605 : // sallayer does all necessary page printing
606 : // and also handles showing a dialog
607 : // that also means it must call jobStarted when the dialog is finished
608 : // it also must set the JobState of the Controller
609 0 : if( mpPrinter->StartJob( pPrintFile,
610 : i_rJobName,
611 : Application::GetDisplayName(),
612 : maJobSetup.ImplGetConstData(),
613 0 : *i_xController) )
614 : {
615 0 : EndJob();
616 : }
617 : else
618 : {
619 0 : mnError = ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode());
620 0 : if ( !mnError )
621 0 : mnError = PRINTER_GENERALERROR;
622 0 : pSVData->mpDefInst->DestroyPrinter( mpPrinter );
623 0 : mnCurPage = 0;
624 0 : mnCurPrintPage = 0;
625 0 : mbPrinting = false;
626 0 : mpPrinter = NULL;
627 0 : mbJobActive = false;
628 :
629 0 : GDIMetaFile aDummyFile;
630 0 : i_xController->setLastPage(true);
631 0 : i_xController->getFilteredPageFile(0, aDummyFile);
632 :
633 0 : return false;
634 : }
635 : }
636 : else
637 : {
638 : // possibly a dialog has been shown
639 : // now the real job starts
640 0 : i_xController->setJobState( view::PrintableState_JOB_STARTED );
641 0 : i_xController->jobStarted();
642 :
643 0 : int nJobs = 1;
644 0 : int nOuterRepeatCount = 1;
645 0 : int nInnerRepeatCount = 1;
646 0 : if( bUserCopy )
647 : {
648 0 : if( mbCollateCopy )
649 0 : nOuterRepeatCount = mnCopyCount;
650 : else
651 0 : nInnerRepeatCount = mnCopyCount;
652 : }
653 0 : if( bSinglePrintJobs )
654 : {
655 0 : nJobs = mnCopyCount;
656 0 : nCopies = 1;
657 0 : nOuterRepeatCount = nInnerRepeatCount = 1;
658 : }
659 :
660 0 : for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
661 : {
662 0 : bool bError = false;
663 0 : if( mpPrinter->StartJob( pPrintFile,
664 : i_rJobName,
665 : Application::GetDisplayName(),
666 : nCopies,
667 : bCollateCopy,
668 0 : i_xController->isDirectPrint(),
669 0 : maJobSetup.ImplGetConstData() ) )
670 : {
671 0 : bool bAborted = false;
672 0 : mbJobActive = true;
673 0 : i_xController->createProgressDialog();
674 0 : const int nPages = i_xController->getFilteredPageCount();
675 : // abort job, if no pages will be printed.
676 0 : if ( nPages == 0 )
677 : {
678 0 : i_xController->abortJob();
679 0 : bAborted = true;
680 : }
681 0 : for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ )
682 : {
683 0 : for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ )
684 : {
685 0 : for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ )
686 : {
687 0 : if( nPage == nPages-1 &&
688 0 : nOuterIteration == nOuterRepeatCount-1 &&
689 0 : nInnerIteration == nInnerRepeatCount-1 &&
690 0 : nJobIteration == nJobs-1 )
691 : {
692 0 : i_xController->setLastPage(true);
693 : }
694 0 : i_xController->printFilteredPage(nPage);
695 0 : if (i_xController->isProgressCanceled())
696 : {
697 0 : i_xController->abortJob();
698 : }
699 0 : if (i_xController->getJobState() ==
700 : view::PrintableState_JOB_ABORTED)
701 : {
702 0 : bAborted = true;
703 : }
704 : }
705 : }
706 : // FIXME: duplex ?
707 : }
708 0 : EndJob();
709 :
710 0 : if( nJobIteration < nJobs-1 )
711 : {
712 0 : mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
713 :
714 0 : if ( mpPrinter )
715 : {
716 0 : maJobName = i_rJobName;
717 0 : mnCurPage = 1;
718 0 : mnCurPrintPage = 1;
719 0 : mbPrinting = true;
720 : }
721 : else
722 0 : bError = true;
723 : }
724 : }
725 : else
726 0 : bError = true;
727 :
728 0 : if( bError )
729 : {
730 0 : mnError = mpPrinter ? ImplSalPrinterErrorCodeToVCL(mpPrinter->GetErrorCode()) : 0;
731 0 : if ( !mnError )
732 0 : mnError = PRINTER_GENERALERROR;
733 0 : i_xController->setJobState( mnError == PRINTER_ABORT
734 : ? view::PrintableState_JOB_ABORTED
735 0 : : view::PrintableState_JOB_FAILED );
736 0 : if( mpPrinter )
737 0 : pSVData->mpDefInst->DestroyPrinter( mpPrinter );
738 0 : mnCurPage = 0;
739 0 : mnCurPrintPage = 0;
740 0 : mbPrinting = false;
741 0 : mpPrinter = NULL;
742 :
743 0 : return false;
744 : }
745 : }
746 :
747 0 : if (i_xController->getJobState() == view::PrintableState_JOB_STARTED)
748 0 : i_xController->setJobState(view::PrintableState_JOB_SPOOLED);
749 : }
750 :
751 : // make last used printer persistent for UI jobs
752 0 : if (i_xController->isShowDialogs() && !i_xController->isDirectPrint())
753 : {
754 0 : SettingsConfigItem* pItem = SettingsConfigItem::get();
755 : pItem->setValue( OUString( "PrintDialog" ),
756 : OUString( "LastPrinterUsed" ),
757 0 : GetName()
758 0 : );
759 : }
760 :
761 0 : return true;
762 : }
763 :
764 0 : PrinterController::~PrinterController()
765 : {
766 0 : delete mpImplData;
767 0 : }
768 :
769 0 : view::PrintableState PrinterController::getJobState() const
770 : {
771 0 : return mpImplData->meJobState;
772 : }
773 :
774 0 : void PrinterController::setJobState( view::PrintableState i_eState )
775 : {
776 0 : mpImplData->meJobState = i_eState;
777 0 : }
778 :
779 0 : const VclPtr<Printer>& PrinterController::getPrinter() const
780 : {
781 0 : return mpImplData->mxPrinter;
782 : }
783 :
784 0 : void PrinterController::setPrinter( const VclPtr<Printer>& i_rPrinter )
785 : {
786 0 : mpImplData->mxPrinter = i_rPrinter;
787 : setValue( OUString( "Name" ),
788 0 : makeAny( OUString( i_rPrinter->GetName() ) ) );
789 0 : mpImplData->mnDefaultPaperBin = mpImplData->mxPrinter->GetPaperBin();
790 0 : mpImplData->mxPrinter->Push();
791 0 : mpImplData->mxPrinter->SetMapMode(MapMode(MAP_100TH_MM));
792 0 : mpImplData->maDefaultPageSize = mpImplData->mxPrinter->GetPaperSize();
793 0 : mpImplData->mxPrinter->Pop();
794 0 : mpImplData->mnFixedPaperBin = -1;
795 0 : }
796 :
797 0 : void PrinterController::resetPrinterOptions( bool i_bFileOutput )
798 : {
799 0 : PrinterOptions aOpt;
800 0 : aOpt.ReadFromConfig( i_bFileOutput );
801 0 : mpImplData->mxPrinter->SetPrinterOptions( aOpt );
802 0 : }
803 :
804 0 : bool PrinterController::setupPrinter( vcl::Window* i_pParent )
805 : {
806 0 : bool bRet = false;
807 0 : if( mpImplData->mxPrinter.get() )
808 : {
809 0 : mpImplData->mxPrinter->Push();
810 0 : mpImplData->mxPrinter->SetMapMode(MapMode(MAP_100TH_MM));
811 :
812 : // get current data
813 0 : Size aPaperSize(mpImplData->mxPrinter->GetPaperSize());
814 0 : sal_uInt16 nPaperBin = mpImplData->mxPrinter->GetPaperBin();
815 :
816 : // reset paper size back to last configured size, not
817 : // whatever happens to be the current page
818 0 : resetPaperToLastConfigured();
819 :
820 : // call driver setup
821 0 : bRet = mpImplData->mxPrinter->Setup( i_pParent );
822 0 : Size aNewPaperSize(mpImplData->mxPrinter->GetPaperSize());
823 0 : if (bRet)
824 : {
825 0 : bool bInvalidateCache = false;
826 :
827 : // was papersize overridden ? if so we need to take action if we're
828 : // configured to use the driver papersize
829 0 : if (aNewPaperSize != mpImplData->maDefaultPageSize)
830 : {
831 0 : mpImplData->maDefaultPageSize = aNewPaperSize;
832 0 : bInvalidateCache = getPapersizeFromSetup();
833 : }
834 :
835 : // was bin overridden ? if so we need to take action
836 0 : sal_uInt16 nNewPaperBin = mpImplData->mxPrinter->GetPaperBin();
837 0 : if (nNewPaperBin != nPaperBin)
838 : {
839 0 : mpImplData->mnFixedPaperBin = nNewPaperBin;
840 0 : bInvalidateCache = true;
841 : }
842 :
843 0 : if (bInvalidateCache)
844 : {
845 0 : mpImplData->maPageCache.invalidate();
846 : }
847 : }
848 : else
849 : {
850 : //restore to whatever it was before we entered this method
851 0 : if (aPaperSize != aNewPaperSize)
852 0 : mpImplData->mxPrinter->SetPaperSizeUser(aPaperSize, !mpImplData->isFixedPageSize());
853 : }
854 0 : mpImplData->mxPrinter->Pop();
855 : }
856 0 : return bRet;
857 : }
858 :
859 0 : PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP )
860 : {
861 0 : PrinterController::PageSize aPageSize;
862 0 : aPageSize.aSize = mxPrinter->GetPaperSize();
863 0 : awt::Size aSetSize, aIsSize;
864 0 : sal_Int32 nPaperBin = mnDefaultPaperBin;
865 0 : for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty )
866 : {
867 0 : if ( i_rProps[ nProperty ].Name == "PreferredPageSize" )
868 : {
869 0 : i_rProps[ nProperty ].Value >>= aSetSize;
870 : }
871 0 : else if ( i_rProps[ nProperty ].Name == "PageSize" )
872 : {
873 0 : i_rProps[ nProperty ].Value >>= aIsSize;
874 : }
875 0 : else if ( i_rProps[ nProperty ].Name == "PageIncludesNonprintableArea" )
876 : {
877 0 : bool bVal = false;
878 0 : i_rProps[ nProperty ].Value >>= bVal;
879 0 : aPageSize.bFullPaper = bVal;
880 : }
881 0 : else if ( i_rProps[ nProperty ].Name == "PrinterPaperTray" )
882 : {
883 0 : sal_Int32 nBin = -1;
884 0 : i_rProps[ nProperty ].Value >>= nBin;
885 0 : if( nBin >= 0 && nBin < mxPrinter->GetPaperBinCount() )
886 0 : nPaperBin = nBin;
887 : }
888 : }
889 :
890 0 : Size aCurSize( mxPrinter->GetPaperSize() );
891 0 : if( aSetSize.Width && aSetSize.Height )
892 : {
893 0 : Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
894 0 : Size aRealPaperSize( getRealPaperSize( aSetPaperSize, bNoNUP ) );
895 0 : if( aRealPaperSize != aCurSize )
896 0 : aIsSize = aSetSize;
897 : }
898 :
899 0 : if( aIsSize.Width && aIsSize.Height )
900 : {
901 0 : aPageSize.aSize.Width() = aIsSize.Width;
902 0 : aPageSize.aSize.Height() = aIsSize.Height;
903 :
904 0 : Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, bNoNUP ) );
905 0 : if( aRealPaperSize != aCurSize )
906 0 : mxPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() );
907 : }
908 :
909 : // paper bin set from properties in print dialog overrides
910 : // application default for a page
911 0 : if ( mnFixedPaperBin != -1 )
912 0 : nPaperBin = mnFixedPaperBin;
913 :
914 0 : if( nPaperBin != -1 && nPaperBin != mxPrinter->GetPaperBin() )
915 0 : mxPrinter->SetPaperBin( nPaperBin );
916 :
917 0 : return aPageSize;
918 : }
919 :
920 : //fdo#61886
921 :
922 : //when printing is finished, set the paper size of the printer to either what
923 : //the user explicitly set as the desired paper size, or fallback to whatever
924 : //the printer had before printing started. That way it doesn't contain the last
925 : //paper size of a multiple paper size using document when we are in our normal
926 : //auto accept document paper size mode and end up overwriting the original
927 : //paper size setting for file->printer_settings just by pressing "ok" in the
928 : //print dialog
929 0 : void vcl::ImplPrinterControllerData::resetPaperToLastConfigured()
930 : {
931 0 : mxPrinter->Push();
932 0 : mxPrinter->SetMapMode(MapMode(MAP_100TH_MM));
933 0 : Size aCurSize(mxPrinter->GetPaperSize());
934 0 : if (aCurSize != maDefaultPageSize)
935 0 : mxPrinter->SetPaperSizeUser(maDefaultPageSize, !isFixedPageSize());
936 0 : mxPrinter->Pop();
937 0 : }
938 :
939 0 : int PrinterController::getPageCountProtected() const
940 : {
941 0 : const MapMode aMapMode( MAP_100TH_MM );
942 :
943 0 : mpImplData->mxPrinter->Push();
944 0 : mpImplData->mxPrinter->SetMapMode( aMapMode );
945 0 : int nPages = getPageCount();
946 0 : mpImplData->mxPrinter->Pop();
947 0 : return nPages;
948 : }
949 :
950 0 : Sequence< PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
951 : {
952 0 : const MapMode aMapMode( MAP_100TH_MM );
953 :
954 0 : mpImplData->mxPrinter->Push();
955 0 : mpImplData->mxPrinter->SetMapMode( aMapMode );
956 0 : Sequence< PropertyValue > aResult( getPageParameters( i_nPage ) );
957 0 : mpImplData->mxPrinter->Pop();
958 0 : return aResult;
959 : }
960 :
961 0 : PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
962 : {
963 : // update progress if necessary
964 0 : if( mpImplData->mpProgress )
965 : {
966 : // do nothing if printing is canceled
967 0 : if( mpImplData->mpProgress->isCanceled() )
968 0 : return PrinterController::PageSize();
969 0 : mpImplData->mpProgress->tick();
970 0 : Application::Reschedule( true );
971 : }
972 :
973 0 : if( i_bMayUseCache )
974 : {
975 0 : PrinterController::PageSize aPageSize;
976 0 : if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
977 : {
978 0 : return aPageSize;
979 : }
980 : }
981 : else
982 0 : mpImplData->maPageCache.invalidate();
983 :
984 0 : o_rMtf.Clear();
985 :
986 : // get page parameters
987 0 : Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
988 0 : const MapMode aMapMode( MAP_100TH_MM );
989 :
990 0 : mpImplData->mxPrinter->Push();
991 0 : mpImplData->mxPrinter->SetMapMode( aMapMode );
992 :
993 : // modify job setup if necessary
994 0 : PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm, true );
995 :
996 0 : o_rMtf.SetPrefSize( aPageSize.aSize );
997 0 : o_rMtf.SetPrefMapMode( aMapMode );
998 :
999 0 : mpImplData->mxPrinter->EnableOutput( false );
1000 :
1001 0 : o_rMtf.Record( mpImplData->mxPrinter.get() );
1002 :
1003 0 : printPage( i_nUnfilteredPage );
1004 :
1005 0 : o_rMtf.Stop();
1006 0 : o_rMtf.WindStart();
1007 0 : mpImplData->mxPrinter->Pop();
1008 :
1009 0 : if( i_bMayUseCache )
1010 0 : mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
1011 :
1012 : // reset "FirstPage" property to false now we've gotten at least our first one
1013 0 : mpImplData->mbFirstPage = false;
1014 :
1015 0 : return aPageSize;
1016 : }
1017 :
1018 0 : static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
1019 : {
1020 : // intersect all clipregion actions with our clip rect
1021 0 : io_rSubPage.WindStart();
1022 0 : io_rSubPage.Clip( i_rClipRect );
1023 :
1024 : // save gstate
1025 0 : o_rMtf.AddAction( new MetaPushAction( PushFlags::ALL ) );
1026 :
1027 : // clip to page rect
1028 0 : o_rMtf.AddAction( new MetaClipRegionAction( vcl::Region( i_rClipRect ), true ) );
1029 :
1030 : // append the subpage
1031 0 : io_rSubPage.WindStart();
1032 0 : io_rSubPage.Play( o_rMtf );
1033 :
1034 : // restore gstate
1035 0 : o_rMtf.AddAction( new MetaPopAction() );
1036 :
1037 : // draw a border
1038 0 : if( i_bDrawBorder )
1039 : {
1040 : // save gstate
1041 0 : o_rMtf.AddAction( new MetaPushAction( PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::CLIPREGION | PushFlags::MAPMODE ) );
1042 0 : o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
1043 :
1044 0 : Rectangle aBorderRect( i_rClipRect );
1045 0 : o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), true ) );
1046 0 : o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), false ) );
1047 0 : o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
1048 :
1049 : // restore gstate
1050 0 : o_rMtf.AddAction( new MetaPopAction() );
1051 : }
1052 0 : }
1053 :
1054 0 : PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
1055 : {
1056 0 : const MultiPageSetup& rMPS( mpImplData->maMultiPage );
1057 0 : int nSubPages = rMPS.nRows * rMPS.nColumns;
1058 0 : if( nSubPages < 1 )
1059 0 : nSubPages = 1;
1060 :
1061 : // reverse sheet order
1062 0 : if( mpImplData->mbReversePageOrder )
1063 : {
1064 0 : int nDocPages = getFilteredPageCount();
1065 0 : i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
1066 : }
1067 :
1068 : // there is no filtering to be done (and possibly the page size of the
1069 : // original page is to be set), when N-Up is "neutral" that is there is
1070 : // only one subpage and the margins are 0
1071 0 : if( nSubPages == 1 &&
1072 0 : rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
1073 0 : rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
1074 : {
1075 0 : PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
1076 0 : if (mpImplData->meJobState != view::PrintableState_JOB_STARTED)
1077 : { // rhbz#657394: check that we are still printing...
1078 0 : return PrinterController::PageSize();
1079 : }
1080 0 : Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true );
1081 0 : mpImplData->mxPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1082 0 : mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1083 0 : if( aPaperSize != aPageSize.aSize )
1084 : {
1085 : // user overridden page size, center Metafile
1086 0 : o_rMtf.WindStart();
1087 0 : long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
1088 0 : long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
1089 0 : o_rMtf.Move( nDX, nDY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1090 0 : o_rMtf.WindStart();
1091 0 : o_rMtf.SetPrefSize( aPaperSize );
1092 0 : aPageSize.aSize = aPaperSize;
1093 : }
1094 0 : return aPageSize;
1095 : }
1096 :
1097 : // set last page property really only on the very last page to be rendered
1098 : // that is on the last subpage of a NUp run
1099 0 : bool bIsLastPage = mpImplData->mbLastPage;
1100 0 : mpImplData->mbLastPage = false;
1101 :
1102 0 : Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) );
1103 :
1104 : // multi page area: page size minus margins + one time spacing right and down
1105 : // the added spacing is so each subpage can be calculated including its spacing
1106 0 : Size aMPArea( aPaperSize );
1107 0 : aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin;
1108 0 : aMPArea.Width() += rMPS.nHorizontalSpacing;
1109 0 : aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin;
1110 0 : aMPArea.Height() += rMPS.nVerticalSpacing;
1111 :
1112 : // determine offsets
1113 0 : long nAdvX = aMPArea.Width() / rMPS.nColumns;
1114 0 : long nAdvY = aMPArea.Height() / rMPS.nRows;
1115 :
1116 : // determine size of a "cell" subpage, leave a little space around pages
1117 0 : Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
1118 :
1119 0 : o_rMtf.Clear();
1120 0 : o_rMtf.SetPrefSize( aPaperSize );
1121 0 : o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
1122 0 : o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
1123 :
1124 0 : int nDocPages = getPageCountProtected();
1125 0 : if (mpImplData->meJobState != view::PrintableState_JOB_STARTED)
1126 : { // rhbz#657394: check that we are still printing...
1127 0 : return PrinterController::PageSize();
1128 : }
1129 0 : for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
1130 : {
1131 : // map current sub page to real page
1132 0 : int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat;
1133 0 : if( nSubPage == nSubPages-1 ||
1134 0 : nPage == nDocPages-1 )
1135 : {
1136 0 : mpImplData->mbLastPage = bIsLastPage;
1137 : }
1138 0 : if( nPage >= 0 && nPage < nDocPages )
1139 : {
1140 0 : GDIMetaFile aPageFile;
1141 0 : PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
1142 0 : if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
1143 : {
1144 0 : long nCellX = 0, nCellY = 0;
1145 0 : switch( rMPS.nOrder )
1146 : {
1147 : case PrinterController::LRTB:
1148 0 : nCellX = (nSubPage % rMPS.nColumns);
1149 0 : nCellY = (nSubPage / rMPS.nColumns);
1150 0 : break;
1151 : case PrinterController::TBLR:
1152 0 : nCellX = (nSubPage / rMPS.nRows);
1153 0 : nCellY = (nSubPage % rMPS.nRows);
1154 0 : break;
1155 : case PrinterController::RLTB:
1156 0 : nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns);
1157 0 : nCellY = (nSubPage / rMPS.nColumns);
1158 0 : break;
1159 : case PrinterController::TBRL:
1160 0 : nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows);
1161 0 : nCellY = (nSubPage % rMPS.nRows);
1162 0 : break;
1163 : }
1164 : // scale the metafile down to a sub page size
1165 0 : double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
1166 0 : double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
1167 0 : double fScale = std::min( fScaleX, fScaleY );
1168 0 : aPageFile.Scale( fScale, fScale );
1169 0 : aPageFile.WindStart();
1170 :
1171 : // move the subpage so it is centered in its "cell"
1172 0 : long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
1173 0 : long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
1174 0 : long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
1175 0 : long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
1176 0 : aPageFile.Move( nX, nY, mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1177 0 : aPageFile.WindStart();
1178 : // calculate border rectangle
1179 : Rectangle aSubPageRect( Point( nX, nY ),
1180 0 : Size( long(double(aPageSize.aSize.Width())*fScale),
1181 0 : long(double(aPageSize.aSize.Height())*fScale) ) );
1182 :
1183 : // append subpage to page
1184 0 : appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
1185 0 : }
1186 : }
1187 : }
1188 0 : o_rMtf.WindStart();
1189 :
1190 : // subsequent getPageFile calls have changed the paper, reset it to current value
1191 0 : mpImplData->mxPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1192 0 : mpImplData->mxPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1193 :
1194 0 : return PrinterController::PageSize( aPaperSize, true );
1195 : }
1196 :
1197 0 : int PrinterController::getFilteredPageCount()
1198 : {
1199 0 : int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
1200 0 : if( nDiv < 1 )
1201 0 : nDiv = 1;
1202 0 : return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv;
1203 : }
1204 :
1205 0 : DrawModeFlags PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut )
1206 : {
1207 0 : DrawModeFlags nRestoreDrawMode = mpImplData->mxPrinter->GetDrawMode();
1208 0 : sal_Int32 nMaxBmpDPIX = mpImplData->mxPrinter->GetDPIX();
1209 0 : sal_Int32 nMaxBmpDPIY = mpImplData->mxPrinter->GetDPIY();
1210 :
1211 0 : const PrinterOptions& rPrinterOptions = mpImplData->mxPrinter->GetPrinterOptions();
1212 :
1213 : static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
1214 : static const sal_Int32 NORMAL_BMP_RESOLUTION = 200;
1215 :
1216 0 : if( rPrinterOptions.IsReduceBitmaps() )
1217 : {
1218 : // calculate maximum resolution for bitmap graphics
1219 0 : if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() )
1220 : {
1221 0 : nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1222 0 : nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1223 : }
1224 0 : else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() )
1225 : {
1226 0 : nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1227 0 : nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1228 : }
1229 : else
1230 : {
1231 0 : nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
1232 0 : nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
1233 : }
1234 : }
1235 :
1236 : // convert to greysacles
1237 0 : if( rPrinterOptions.IsConvertToGreyscales() )
1238 : {
1239 0 : mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() |
1240 : ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText |
1241 0 : DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) );
1242 : }
1243 :
1244 : // disable transparency output
1245 0 : if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
1246 : {
1247 0 : mpImplData->mxPrinter->SetDrawMode( mpImplData->mxPrinter->GetDrawMode() | DrawModeFlags::NoTransparency );
1248 : }
1249 :
1250 0 : Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
1251 0 : if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
1252 : {
1253 : // in N-Up printing we have no "page" background operation
1254 : // we also have no way to determine the paper color
1255 : // so let's go for white, which will kill 99.9% of the real cases
1256 0 : aBg = Color( COL_WHITE );
1257 : }
1258 0 : mpImplData->mxPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
1259 0 : rPrinterOptions.IsReduceTransparency(),
1260 0 : rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO,
1261 0 : rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
1262 : aBg
1263 0 : );
1264 0 : return nRestoreDrawMode;
1265 : }
1266 :
1267 0 : void PrinterController::printFilteredPage( int i_nPage )
1268 : {
1269 0 : if( mpImplData->meJobState != view::PrintableState_JOB_STARTED )
1270 0 : return;
1271 :
1272 0 : GDIMetaFile aPageFile;
1273 0 : PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
1274 :
1275 0 : if (mpImplData->meJobState != view::PrintableState_JOB_STARTED)
1276 : { // rhbz#657394: check that we are still printing...
1277 0 : return;
1278 : }
1279 :
1280 0 : if( mpImplData->mpProgress )
1281 : {
1282 : // do nothing if printing is canceled
1283 0 : if( mpImplData->mpProgress->isCanceled() )
1284 : {
1285 0 : setJobState( view::PrintableState_JOB_ABORTED );
1286 0 : return;
1287 : }
1288 : }
1289 :
1290 : // in N-Up printing set the correct page size
1291 0 : mpImplData->mxPrinter->SetMapMode( MAP_100TH_MM );
1292 : // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
1293 0 : mpImplData->mxPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() );
1294 0 : if( mpImplData->mnFixedPaperBin != -1 &&
1295 0 : mpImplData->mxPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin )
1296 : {
1297 0 : mpImplData->mxPrinter->SetPaperBin( mpImplData->mnFixedPaperBin );
1298 : }
1299 :
1300 : // if full paper is meant to be used, move the output to accommodate for pageoffset
1301 0 : if( aPageSize.bFullPaper )
1302 : {
1303 0 : Point aPageOffset( mpImplData->mxPrinter->GetPageOffset() );
1304 0 : aPageFile.WindStart();
1305 0 : aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mxPrinter->GetDPIX(), mpImplData->mxPrinter->GetDPIY() );
1306 : }
1307 :
1308 0 : GDIMetaFile aCleanedFile;
1309 0 : DrawModeFlags nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
1310 :
1311 0 : mpImplData->mxPrinter->EnableOutput( true );
1312 :
1313 : // actually print the page
1314 0 : mpImplData->mxPrinter->ImplStartPage();
1315 :
1316 0 : mpImplData->mxPrinter->Push();
1317 0 : aCleanedFile.WindStart();
1318 0 : aCleanedFile.Play( mpImplData->mxPrinter.get() );
1319 0 : mpImplData->mxPrinter->Pop();
1320 :
1321 0 : mpImplData->mxPrinter->ImplEndPage();
1322 :
1323 0 : mpImplData->mxPrinter->SetDrawMode( nRestoreDrawMode );
1324 : }
1325 :
1326 0 : void PrinterController::jobStarted()
1327 : {
1328 0 : }
1329 :
1330 0 : void PrinterController::jobFinished( view::PrintableState )
1331 : {
1332 0 : }
1333 :
1334 0 : void PrinterController::abortJob()
1335 : {
1336 0 : setJobState( view::PrintableState_JOB_ABORTED );
1337 : // applications (well, sw) depend on a page request with "IsLastPage" = true
1338 : // to free resources, else they (well, sw) will crash eventually
1339 0 : setLastPage( true );
1340 0 : mpImplData->mpProgress.disposeAndClear();
1341 0 : GDIMetaFile aMtf;
1342 0 : getPageFile( 0, aMtf, false );
1343 0 : }
1344 :
1345 0 : void PrinterController::setLastPage( bool i_bLastPage )
1346 : {
1347 0 : mpImplData->mbLastPage = i_bLastPage;
1348 0 : }
1349 :
1350 0 : void PrinterController::setReversePrint( bool i_bReverse )
1351 : {
1352 0 : mpImplData->mbReversePageOrder = i_bReverse;
1353 0 : }
1354 :
1355 0 : bool PrinterController::getReversePrint() const
1356 : {
1357 0 : return mpImplData->mbReversePageOrder;
1358 : }
1359 :
1360 0 : void PrinterController::setPapersizeFromSetup( bool i_bPapersizeFromSetup )
1361 : {
1362 0 : mpImplData->mbPapersizeFromSetup = i_bPapersizeFromSetup;
1363 0 : }
1364 :
1365 0 : bool PrinterController::getPapersizeFromSetup() const
1366 : {
1367 0 : return mpImplData->mbPapersizeFromSetup;
1368 : }
1369 :
1370 0 : Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const
1371 : {
1372 0 : std::unordered_set< OUString, OUStringHash > aMergeSet;
1373 0 : size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
1374 0 : for( int i = 0; i < i_rMergeList.getLength(); i++ )
1375 0 : aMergeSet.insert( i_rMergeList[i].Name );
1376 :
1377 0 : Sequence< PropertyValue > aResult( nResultLen );
1378 0 : for( int i = 0; i < i_rMergeList.getLength(); i++ )
1379 0 : aResult[i] = i_rMergeList[i];
1380 0 : int nCur = i_rMergeList.getLength();
1381 0 : for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ )
1382 : {
1383 0 : if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() )
1384 0 : aResult[nCur++] = mpImplData->maUIProperties[i];
1385 : }
1386 : // append IsFirstPage
1387 0 : if( aMergeSet.find( OUString( "IsFirstPage" ) ) == aMergeSet.end() )
1388 : {
1389 0 : PropertyValue aVal;
1390 0 : aVal.Name = "IsFirstPage";
1391 0 : aVal.Value <<= mpImplData->mbFirstPage;
1392 0 : aResult[nCur++] = aVal;
1393 : }
1394 : // append IsLastPage
1395 0 : if( aMergeSet.find( OUString( "IsLastPage" ) ) == aMergeSet.end() )
1396 : {
1397 0 : PropertyValue aVal;
1398 0 : aVal.Name = "IsLastPage";
1399 0 : aVal.Value <<= mpImplData->mbLastPage;
1400 0 : aResult[nCur++] = aVal;
1401 : }
1402 : // append IsPrinter
1403 0 : if( aMergeSet.find( OUString( "IsPrinter" ) ) == aMergeSet.end() )
1404 : {
1405 0 : PropertyValue aVal;
1406 0 : aVal.Name = "IsPrinter";
1407 0 : aVal.Value <<= sal_True;
1408 0 : aResult[nCur++] = aVal;
1409 : }
1410 0 : aResult.realloc( nCur );
1411 0 : return aResult;
1412 : }
1413 :
1414 0 : const Sequence< PropertyValue >& PrinterController::getUIOptions() const
1415 : {
1416 0 : return mpImplData->maUIOptions;
1417 : }
1418 :
1419 0 : PropertyValue* PrinterController::getValue( const OUString& i_rProperty )
1420 : {
1421 : std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1422 0 : mpImplData->maPropertyToIndex.find( i_rProperty );
1423 0 : return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
1424 : }
1425 :
1426 0 : const PropertyValue* PrinterController::getValue( const OUString& i_rProperty ) const
1427 : {
1428 : std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1429 0 : mpImplData->maPropertyToIndex.find( i_rProperty );
1430 0 : return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
1431 : }
1432 :
1433 0 : void PrinterController::setValue( const OUString& i_rName, const Any& i_rValue )
1434 : {
1435 0 : PropertyValue aVal;
1436 0 : aVal.Name = i_rName;
1437 0 : aVal.Value = i_rValue;
1438 :
1439 0 : setValue( aVal );
1440 0 : }
1441 :
1442 0 : void PrinterController::setValue( const PropertyValue& i_rValue )
1443 : {
1444 : std::unordered_map< OUString, size_t, OUStringHash >::const_iterator it =
1445 0 : mpImplData->maPropertyToIndex.find( i_rValue.Name );
1446 0 : if( it != mpImplData->maPropertyToIndex.end() )
1447 0 : mpImplData->maUIProperties[ it->second ] = i_rValue;
1448 : else
1449 : {
1450 : // insert correct index into property map
1451 0 : mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size();
1452 0 : mpImplData->maUIProperties.push_back( i_rValue );
1453 0 : mpImplData->maUIPropertyEnabled.push_back( true );
1454 : }
1455 0 : }
1456 :
1457 0 : void PrinterController::setUIOptions( const Sequence< PropertyValue >& i_rOptions )
1458 : {
1459 : DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" );
1460 :
1461 0 : mpImplData->maUIOptions = i_rOptions;
1462 :
1463 0 : for( int i = 0; i < i_rOptions.getLength(); i++ )
1464 : {
1465 0 : Sequence< PropertyValue > aOptProp;
1466 0 : i_rOptions[i].Value >>= aOptProp;
1467 0 : bool bIsEnabled = true;
1468 0 : bool bHaveProperty = false;
1469 0 : OUString aPropName;
1470 0 : vcl::ImplPrinterControllerData::ControlDependency aDep;
1471 0 : Sequence< sal_Bool > aChoicesDisabled;
1472 0 : for( int n = 0; n < aOptProp.getLength(); n++ )
1473 : {
1474 0 : const PropertyValue& rEntry( aOptProp[ n ] );
1475 0 : if ( rEntry.Name == "Property" )
1476 : {
1477 0 : PropertyValue aVal;
1478 0 : rEntry.Value >>= aVal;
1479 : DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )
1480 : == mpImplData->maPropertyToIndex.end(), "duplicate property entry" );
1481 0 : setValue( aVal );
1482 0 : aPropName = aVal.Name;
1483 0 : bHaveProperty = true;
1484 : }
1485 0 : else if ( rEntry.Name == "Enabled" )
1486 : {
1487 0 : bool bValue = true;
1488 0 : rEntry.Value >>= bValue;
1489 0 : bIsEnabled = bValue;
1490 : }
1491 0 : else if ( rEntry.Name == "DependsOnName" )
1492 : {
1493 0 : rEntry.Value >>= aDep.maDependsOnName;
1494 : }
1495 0 : else if ( rEntry.Name == "DependsOnEntry" )
1496 : {
1497 0 : rEntry.Value >>= aDep.mnDependsOnEntry;
1498 : }
1499 0 : else if ( rEntry.Name == "ChoicesDisabled" )
1500 : {
1501 0 : rEntry.Value >>= aChoicesDisabled;
1502 : }
1503 : }
1504 0 : if( bHaveProperty )
1505 : {
1506 : vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
1507 0 : mpImplData->maPropertyToIndex.find( aPropName );
1508 : // sanity check
1509 0 : if( it != mpImplData->maPropertyToIndex.end() )
1510 : {
1511 0 : mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
1512 : }
1513 0 : if( !aDep.maDependsOnName.isEmpty() )
1514 0 : mpImplData->maControlDependencies[ aPropName ] = aDep;
1515 0 : if( aChoicesDisabled.getLength() > 0 )
1516 0 : mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled;
1517 : }
1518 0 : }
1519 0 : }
1520 :
1521 0 : bool PrinterController::isUIOptionEnabled( const OUString& i_rProperty ) const
1522 : {
1523 0 : bool bEnabled = false;
1524 : std::unordered_map< OUString, size_t, OUStringHash >::const_iterator prop_it =
1525 0 : mpImplData->maPropertyToIndex.find( i_rProperty );
1526 0 : if( prop_it != mpImplData->maPropertyToIndex.end() )
1527 : {
1528 0 : bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
1529 :
1530 0 : if( bEnabled )
1531 : {
1532 : // check control dependencies
1533 : vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1534 0 : mpImplData->maControlDependencies.find( i_rProperty );
1535 0 : if( it != mpImplData->maControlDependencies.end() )
1536 : {
1537 : // check if the dependency is enabled
1538 : // if the dependency is disabled, we are too
1539 0 : bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
1540 :
1541 0 : if( bEnabled )
1542 : {
1543 : // does the dependency have the correct value ?
1544 0 : const css::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
1545 : OSL_ENSURE( pVal, "unknown property in dependency" );
1546 0 : if( pVal )
1547 : {
1548 0 : sal_Int32 nDepVal = 0;
1549 0 : bool bDepVal = false;
1550 0 : if( pVal->Value >>= nDepVal )
1551 : {
1552 0 : bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
1553 : }
1554 0 : else if( pVal->Value >>= bDepVal )
1555 : {
1556 : // could be a dependency on a checked boolean
1557 : // in this case the dependency is on a non zero for checked value
1558 0 : bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) ||
1559 0 : ( ! bDepVal && it->second.mnDependsOnEntry == 0);
1560 : }
1561 : else
1562 : {
1563 : // if the type does not match something is awry
1564 : OSL_FAIL( "strange type in control dependency" );
1565 0 : bEnabled = false;
1566 : }
1567 : }
1568 : }
1569 : }
1570 : }
1571 : }
1572 0 : return bEnabled;
1573 : }
1574 :
1575 0 : bool PrinterController::isUIChoiceEnabled( const OUString& i_rProperty, sal_Int32 i_nValue ) const
1576 : {
1577 0 : bool bEnabled = true;
1578 : ImplPrinterControllerData::ChoiceDisableMap::const_iterator it =
1579 0 : mpImplData->maChoiceDisableMap.find( i_rProperty );
1580 0 : if(it != mpImplData->maChoiceDisableMap.end() )
1581 : {
1582 0 : const Sequence< sal_Bool >& rDisabled( it->second );
1583 0 : if( i_nValue >= 0 && i_nValue < rDisabled.getLength() )
1584 0 : bEnabled = ! rDisabled[i_nValue];
1585 : }
1586 0 : return bEnabled;
1587 : }
1588 :
1589 0 : OUString PrinterController::getDependency( const OUString& i_rProperty ) const
1590 : {
1591 0 : OUString aDependency;
1592 :
1593 : vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1594 0 : mpImplData->maControlDependencies.find( i_rProperty );
1595 0 : if( it != mpImplData->maControlDependencies.end() )
1596 0 : aDependency = it->second.maDependsOnName;
1597 :
1598 0 : return aDependency;
1599 : }
1600 :
1601 0 : OUString PrinterController::makeEnabled( const OUString& i_rProperty )
1602 : {
1603 0 : OUString aDependency;
1604 :
1605 : vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1606 0 : mpImplData->maControlDependencies.find( i_rProperty );
1607 0 : if( it != mpImplData->maControlDependencies.end() )
1608 : {
1609 0 : if( isUIOptionEnabled( it->second.maDependsOnName ) )
1610 : {
1611 0 : aDependency = it->second.maDependsOnName;
1612 0 : const css::beans::PropertyValue* pVal = getValue( aDependency );
1613 : OSL_ENSURE( pVal, "unknown property in dependency" );
1614 0 : if( pVal )
1615 : {
1616 0 : sal_Int32 nDepVal = 0;
1617 0 : bool bDepVal = false;
1618 0 : if( pVal->Value >>= nDepVal )
1619 : {
1620 0 : if( it->second.mnDependsOnEntry != -1 )
1621 : {
1622 0 : setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
1623 : }
1624 : }
1625 0 : else if( pVal->Value >>= bDepVal )
1626 : {
1627 0 : setValue( aDependency, makeAny( it->second.mnDependsOnEntry != 0 ) );
1628 : }
1629 : else
1630 : {
1631 : // if the type does not match something is awry
1632 : OSL_FAIL( "strange type in control dependency" );
1633 : }
1634 : }
1635 : }
1636 : }
1637 :
1638 0 : return aDependency;
1639 : }
1640 :
1641 0 : void PrinterController::setOptionChangeHdl( const Link<>& i_rHdl )
1642 : {
1643 0 : mpImplData->maOptionChangeHdl = i_rHdl;
1644 0 : }
1645 :
1646 0 : void PrinterController::createProgressDialog()
1647 : {
1648 0 : if( ! mpImplData->mpProgress )
1649 : {
1650 0 : bool bShow = true;
1651 0 : PropertyValue* pMonitor = getValue( OUString( "MonitorVisible" ) );
1652 0 : if( pMonitor )
1653 0 : pMonitor->Value >>= bShow;
1654 : else
1655 : {
1656 0 : const css::beans::PropertyValue* pVal = getValue( OUString( "IsApi" ) );
1657 0 : if( pVal )
1658 : {
1659 0 : bool bApi = false;
1660 0 : pVal->Value >>= bApi;
1661 0 : bShow = ! bApi;
1662 : }
1663 : }
1664 :
1665 0 : if( bShow && ! Application::IsHeadlessModeEnabled() )
1666 : {
1667 0 : mpImplData->mpProgress = VclPtr<PrintProgressDialog>::Create( nullptr, getPageCountProtected() );
1668 0 : mpImplData->mpProgress->Show();
1669 : }
1670 : }
1671 : else
1672 0 : mpImplData->mpProgress->reset();
1673 0 : }
1674 :
1675 0 : bool PrinterController::isProgressCanceled() const
1676 : {
1677 0 : return mpImplData->mpProgress && mpImplData->mpProgress->isCanceled();
1678 : }
1679 :
1680 0 : void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
1681 : {
1682 0 : mpImplData->maMultiPage = i_rMPS;
1683 0 : }
1684 :
1685 0 : const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
1686 : {
1687 0 : return mpImplData->maMultiPage;
1688 : }
1689 :
1690 0 : void PrinterController::resetPaperToLastConfigured()
1691 : {
1692 0 : mpImplData->resetPaperToLastConfigured();
1693 0 : }
1694 :
1695 0 : void PrinterController::pushPropertiesToPrinter()
1696 : {
1697 0 : sal_Int32 nCopyCount = 1;
1698 : // set copycount and collate
1699 0 : const css::beans::PropertyValue* pVal = getValue( OUString( "CopyCount" ) );
1700 0 : if( pVal )
1701 0 : pVal->Value >>= nCopyCount;
1702 0 : bool bCollate = false;
1703 0 : pVal = getValue( OUString( "Collate" ) );
1704 0 : if( pVal )
1705 0 : pVal->Value >>= bCollate;
1706 0 : mpImplData->mxPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate );
1707 :
1708 : // duplex mode
1709 0 : pVal = getValue( OUString( "DuplexMode" ) );
1710 0 : if( pVal )
1711 : {
1712 0 : sal_Int16 nDuplex = view::DuplexMode::UNKNOWN;
1713 0 : pVal->Value >>= nDuplex;
1714 0 : switch( nDuplex )
1715 : {
1716 0 : case view::DuplexMode::OFF: mpImplData->mxPrinter->SetDuplexMode( DUPLEX_OFF ); break;
1717 0 : case view::DuplexMode::LONGEDGE: mpImplData->mxPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break;
1718 0 : case view::DuplexMode::SHORTEDGE: mpImplData->mxPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break;
1719 : }
1720 : }
1721 0 : }
1722 :
1723 0 : bool PrinterController::isShowDialogs() const
1724 : {
1725 0 : bool bApi = getBoolProperty( OUString( "IsApi" ), false );
1726 0 : return ! bApi && ! Application::IsHeadlessModeEnabled();
1727 : }
1728 :
1729 0 : bool PrinterController::isDirectPrint() const
1730 : {
1731 0 : bool bDirect = getBoolProperty( OUString( "IsDirect" ), false );
1732 0 : return bDirect;
1733 : }
1734 :
1735 0 : bool PrinterController::getBoolProperty( const OUString& i_rProperty, bool i_bFallback ) const
1736 : {
1737 0 : bool bRet = i_bFallback;
1738 0 : const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1739 0 : if( pVal )
1740 0 : pVal->Value >>= bRet;
1741 0 : return bRet;
1742 : }
1743 :
1744 0 : sal_Int32 PrinterController::getIntProperty( const OUString& i_rProperty, sal_Int32 i_nFallback ) const
1745 : {
1746 0 : sal_Int32 nRet = i_nFallback;
1747 0 : const css::beans::PropertyValue* pVal = getValue( i_rProperty );
1748 0 : if( pVal )
1749 0 : pVal->Value >>= nRet;
1750 0 : return nRet;
1751 : }
1752 :
1753 : /*
1754 : * PrinterOptionsHelper
1755 : **/
1756 54 : Any PrinterOptionsHelper::getValue( const OUString& i_rPropertyName ) const
1757 : {
1758 54 : Any aRet;
1759 : std::unordered_map< OUString, Any, OUStringHash >::const_iterator it =
1760 54 : m_aPropertyMap.find( i_rPropertyName );
1761 54 : if( it != m_aPropertyMap.end() )
1762 2 : aRet = it->second;
1763 54 : return aRet;
1764 : }
1765 :
1766 39 : bool PrinterOptionsHelper::getBoolValue( const OUString& i_rPropertyName, bool i_bDefault ) const
1767 : {
1768 39 : bool bRet = false;
1769 39 : Any aVal( getValue( i_rPropertyName ) );
1770 39 : return (aVal >>= bRet) ? bRet : i_bDefault;
1771 : }
1772 :
1773 12 : sal_Int64 PrinterOptionsHelper::getIntValue( const OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
1774 : {
1775 12 : sal_Int64 nRet = 0;
1776 12 : Any aVal( getValue( i_rPropertyName ) );
1777 12 : return (aVal >>= nRet) ? nRet : i_nDefault;
1778 : }
1779 :
1780 1 : OUString PrinterOptionsHelper::getStringValue( const OUString& i_rPropertyName, const OUString& i_rDefault ) const
1781 : {
1782 1 : OUString aRet;
1783 2 : Any aVal( getValue( i_rPropertyName ) );
1784 2 : return (aVal >>= aRet) ? aRet : i_rDefault;
1785 : }
1786 :
1787 3 : bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp,
1788 : std::set< OUString >* o_pChangeProp )
1789 : {
1790 3 : bool bChanged = false;
1791 :
1792 : // clear the changed set
1793 3 : if( o_pChangeProp )
1794 0 : o_pChangeProp->clear();
1795 :
1796 3 : sal_Int32 nElements = i_rNewProp.getLength();
1797 3 : const PropertyValue* pVals = i_rNewProp.getConstArray();
1798 12 : for( sal_Int32 i = 0; i < nElements; i++ )
1799 : {
1800 9 : bool bElementChanged = false;
1801 : std::unordered_map< OUString, Any, OUStringHash >::iterator it =
1802 9 : m_aPropertyMap.find( pVals[ i ].Name );
1803 9 : if( it != m_aPropertyMap.end() )
1804 : {
1805 6 : if( it->second != pVals[ i ].Value )
1806 1 : bElementChanged = true;
1807 : }
1808 : else
1809 3 : bElementChanged = true;
1810 :
1811 9 : if( bElementChanged )
1812 : {
1813 4 : if( o_pChangeProp )
1814 0 : o_pChangeProp->insert( pVals[ i ].Name );
1815 4 : m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value;
1816 4 : bChanged = true;
1817 : }
1818 : }
1819 3 : return bChanged;
1820 : }
1821 :
1822 1 : void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< PropertyValue >& io_rProps ) const
1823 : {
1824 1 : if( m_aUIProperties.getLength() > 0 )
1825 : {
1826 1 : sal_Int32 nIndex = io_rProps.getLength();
1827 1 : io_rProps.realloc( nIndex+1 );
1828 1 : PropertyValue aVal;
1829 1 : aVal.Name = "ExtraPrintUIOptions";
1830 1 : aVal.Value = makeAny( m_aUIProperties );
1831 1 : io_rProps[ nIndex ] = aVal;
1832 : }
1833 1 : }
1834 :
1835 21 : Any PrinterOptionsHelper::setUIControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1836 : const OUString& i_rTitle,
1837 : const Sequence< OUString >& i_rHelpIds,
1838 : const OUString& i_rType,
1839 : const PropertyValue* i_pVal,
1840 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1841 : {
1842 : sal_Int32 nElements =
1843 : 2 // ControlType + ID
1844 21 : + (i_rTitle.isEmpty() ? 0 : 1) // Text
1845 21 : + (i_rHelpIds.getLength() ? 1 : 0) // HelpId
1846 21 : + (i_pVal ? 1 : 0) // Property
1847 21 : + i_rControlOptions.maAddProps.getLength() // additional props
1848 21 : + (i_rControlOptions.maGroupHint.isEmpty() ? 0 : 1) // grouping
1849 21 : + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint
1850 21 : + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled
1851 : ;
1852 21 : if( !i_rControlOptions.maDependsOnName.isEmpty() )
1853 : {
1854 3 : nElements += 1;
1855 3 : if( i_rControlOptions.mnDependsOnEntry != -1 )
1856 2 : nElements += 1;
1857 3 : if( i_rControlOptions.mbAttachToDependency )
1858 2 : nElements += 1;
1859 : }
1860 :
1861 21 : Sequence< PropertyValue > aCtrl( nElements );
1862 21 : sal_Int32 nUsed = 0;
1863 21 : if( !i_rTitle.isEmpty() )
1864 : {
1865 18 : aCtrl[nUsed ].Name = "Text";
1866 18 : aCtrl[nUsed++].Value = makeAny( i_rTitle );
1867 : }
1868 21 : if( i_rHelpIds.getLength() )
1869 : {
1870 15 : aCtrl[nUsed ].Name = "HelpId";
1871 15 : aCtrl[nUsed++].Value = makeAny( i_rHelpIds );
1872 : }
1873 21 : aCtrl[nUsed ].Name = "ControlType";
1874 21 : aCtrl[nUsed++].Value = makeAny( i_rType );
1875 21 : aCtrl[nUsed ].Name = "ID";
1876 21 : aCtrl[nUsed++].Value = makeAny( i_rIDs );
1877 21 : if( i_pVal )
1878 : {
1879 14 : aCtrl[nUsed ].Name = "Property";
1880 14 : aCtrl[nUsed++].Value = makeAny( *i_pVal );
1881 : }
1882 21 : if( !i_rControlOptions.maDependsOnName.isEmpty() )
1883 : {
1884 3 : aCtrl[nUsed ].Name = "DependsOnName";
1885 3 : aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName );
1886 3 : if( i_rControlOptions.mnDependsOnEntry != -1 )
1887 : {
1888 2 : aCtrl[nUsed ].Name = "DependsOnEntry";
1889 2 : aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry );
1890 : }
1891 3 : if( i_rControlOptions.mbAttachToDependency )
1892 : {
1893 2 : aCtrl[nUsed ].Name = "AttachToDependency";
1894 2 : aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency );
1895 : }
1896 : }
1897 21 : if( !i_rControlOptions.maGroupHint.isEmpty() )
1898 : {
1899 6 : aCtrl[nUsed ].Name = "GroupingHint";
1900 6 : aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
1901 : }
1902 21 : if( i_rControlOptions.mbInternalOnly )
1903 : {
1904 1 : aCtrl[nUsed ].Name = "InternalUIOnly";
1905 1 : aCtrl[nUsed++].Value <<= sal_True;
1906 : }
1907 21 : if( ! i_rControlOptions.mbEnabled )
1908 : {
1909 1 : aCtrl[nUsed ].Name = "Enabled";
1910 1 : aCtrl[nUsed++].Value <<= sal_False;
1911 : }
1912 :
1913 21 : sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength();
1914 26 : for( sal_Int32 i = 0; i < nAddProps; i++ )
1915 5 : aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
1916 :
1917 : DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" );
1918 :
1919 21 : return makeAny( aCtrl );
1920 : }
1921 :
1922 1 : Any PrinterOptionsHelper::setGroupControlOpt(const OUString& i_rID,
1923 : const OUString& i_rTitle,
1924 : const OUString& i_rHelpId)
1925 : {
1926 1 : Sequence< OUString > aHelpId;
1927 1 : if( !i_rHelpId.isEmpty() )
1928 : {
1929 1 : aHelpId.realloc( 1 );
1930 1 : *aHelpId.getArray() = i_rHelpId;
1931 : }
1932 2 : Sequence< OUString > aIds(1);
1933 1 : aIds[0] = i_rID;
1934 2 : return setUIControlOpt(aIds, i_rTitle, aHelpId, "Group");
1935 : }
1936 :
1937 6 : Any PrinterOptionsHelper::setSubgroupControlOpt(const OUString& i_rID,
1938 : const OUString& i_rTitle,
1939 : const OUString& i_rHelpId,
1940 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1941 : {
1942 6 : Sequence< OUString > aHelpId;
1943 6 : if( !i_rHelpId.isEmpty() )
1944 : {
1945 0 : aHelpId.realloc( 1 );
1946 0 : *aHelpId.getArray() = i_rHelpId;
1947 : }
1948 12 : Sequence< OUString > aIds(1);
1949 6 : aIds[0] = i_rID;
1950 12 : return setUIControlOpt(aIds, i_rTitle, aHelpId, "Subgroup", NULL, i_rControlOptions);
1951 : }
1952 :
1953 9 : Any PrinterOptionsHelper::setBoolControlOpt(const OUString& i_rID,
1954 : const OUString& i_rTitle,
1955 : const OUString& i_rHelpId,
1956 : const OUString& i_rProperty,
1957 : bool i_bValue,
1958 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1959 : {
1960 9 : Sequence< OUString > aHelpId;
1961 9 : if( !i_rHelpId.isEmpty() )
1962 : {
1963 9 : aHelpId.realloc( 1 );
1964 9 : *aHelpId.getArray() = i_rHelpId;
1965 : }
1966 18 : PropertyValue aVal;
1967 9 : aVal.Name = i_rProperty;
1968 9 : aVal.Value = makeAny( i_bValue );
1969 18 : Sequence< OUString > aIds(1);
1970 9 : aIds[0] = i_rID;
1971 18 : return setUIControlOpt(aIds, i_rTitle, aHelpId, "Bool", &aVal, i_rControlOptions);
1972 : }
1973 :
1974 1 : Any PrinterOptionsHelper::setChoiceRadiosControlOpt(const css::uno::Sequence< OUString >& i_rIDs,
1975 : const OUString& i_rTitle,
1976 : const Sequence< OUString >& i_rHelpId,
1977 : const OUString& i_rProperty,
1978 : const Sequence< OUString >& i_rChoices,
1979 : sal_Int32 i_nValue,
1980 : const Sequence< sal_Bool >& i_rDisabledChoices,
1981 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
1982 : {
1983 1 : UIControlOptions aOpt( i_rControlOptions );
1984 1 : sal_Int32 nUsed = aOpt.maAddProps.getLength();
1985 1 : aOpt.maAddProps.realloc( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) );
1986 1 : aOpt.maAddProps[nUsed].Name = "Choices";
1987 1 : aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices );
1988 1 : if( i_rDisabledChoices.getLength() )
1989 : {
1990 1 : aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
1991 1 : aOpt.maAddProps[nUsed+1].Value = makeAny( i_rDisabledChoices );
1992 : }
1993 :
1994 2 : PropertyValue aVal;
1995 1 : aVal.Name = i_rProperty;
1996 1 : aVal.Value = makeAny( i_nValue );
1997 2 : return setUIControlOpt(i_rIDs, i_rTitle, i_rHelpId, "Radio", &aVal, aOpt);
1998 : }
1999 :
2000 3 : Any PrinterOptionsHelper::setChoiceListControlOpt(const OUString& i_rID,
2001 : const OUString& i_rTitle,
2002 : const Sequence< OUString >& i_rHelpId,
2003 : const OUString& i_rProperty,
2004 : const Sequence< OUString >& i_rChoices,
2005 : sal_Int32 i_nValue,
2006 : const Sequence< sal_Bool >& i_rDisabledChoices,
2007 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2008 : {
2009 3 : UIControlOptions aOpt( i_rControlOptions );
2010 3 : sal_Int32 nUsed = aOpt.maAddProps.getLength();
2011 3 : aOpt.maAddProps.realloc( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) );
2012 3 : aOpt.maAddProps[nUsed].Name = "Choices";
2013 3 : aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices );
2014 3 : if( i_rDisabledChoices.getLength() )
2015 : {
2016 0 : aOpt.maAddProps[nUsed+1].Name = "ChoicesDisabled";
2017 0 : aOpt.maAddProps[nUsed+1].Value = makeAny( i_rDisabledChoices );
2018 : }
2019 :
2020 6 : PropertyValue aVal;
2021 3 : aVal.Name = i_rProperty;
2022 3 : aVal.Value = makeAny( i_nValue );
2023 6 : Sequence< OUString > aIds(1);
2024 3 : aIds[0] = i_rID;
2025 6 : return setUIControlOpt(aIds, i_rTitle, i_rHelpId, "List", &aVal, aOpt);
2026 : }
2027 :
2028 0 : Any PrinterOptionsHelper::setRangeControlOpt(const OUString& i_rID,
2029 : const OUString& i_rTitle,
2030 : const OUString& i_rHelpId,
2031 : const OUString& i_rProperty,
2032 : sal_Int32 i_nValue,
2033 : sal_Int32 i_nMinValue,
2034 : sal_Int32 i_nMaxValue,
2035 : const PrinterOptionsHelper::UIControlOptions& i_rControlOptions)
2036 : {
2037 0 : UIControlOptions aOpt( i_rControlOptions );
2038 0 : if( i_nMaxValue >= i_nMinValue )
2039 : {
2040 0 : sal_Int32 nUsed = aOpt.maAddProps.getLength();
2041 0 : aOpt.maAddProps.realloc( nUsed + 2 );
2042 0 : aOpt.maAddProps[nUsed ].Name = "MinValue";
2043 0 : aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue );
2044 0 : aOpt.maAddProps[nUsed ].Name = "MaxValue";
2045 0 : aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue );
2046 : }
2047 :
2048 0 : Sequence< OUString > aHelpId;
2049 0 : if( !i_rHelpId.isEmpty() )
2050 : {
2051 0 : aHelpId.realloc( 1 );
2052 0 : *aHelpId.getArray() = i_rHelpId;
2053 : }
2054 0 : PropertyValue aVal;
2055 0 : aVal.Name = i_rProperty;
2056 0 : aVal.Value = makeAny( i_nValue );
2057 0 : Sequence< OUString > aIds(1);
2058 0 : aIds[0] = i_rID;
2059 0 : return setUIControlOpt(aIds, i_rTitle, aHelpId, "Range", &aVal, aOpt);
2060 : }
2061 :
2062 1 : 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)
2068 : {
2069 1 : Sequence< OUString > aHelpId;
2070 1 : if( !i_rHelpId.isEmpty() )
2071 : {
2072 1 : aHelpId.realloc( 1 );
2073 1 : *aHelpId.getArray() = i_rHelpId;
2074 : }
2075 2 : PropertyValue aVal;
2076 1 : aVal.Name = i_rProperty;
2077 1 : aVal.Value = makeAny( i_rValue );
2078 2 : Sequence< OUString > aIds(1);
2079 1 : aIds[0] = i_rID;
2080 2 : return setUIControlOpt(aIds, i_rTitle, aHelpId, "Edit", &aVal, i_rControlOptions);
2081 801 : }
2082 :
2083 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|