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