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