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 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: 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 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 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 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 145 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 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 {} 186 ~ImplPrinterControllerData() { delete mpProgress; } 187 188 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 } 196 bool isFixedPageSize() const 197 { return maFixedPageSize.Width() != 0 && maFixedPageSize.Height() != 0; } 198 PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP ); 199 }; 200 201 PrinterController::PrinterController() 202 : mpImplData( new ImplPrinterControllerData ) 203 { 204 } 205 206 PrinterController::PrinterController( const boost::shared_ptr<Printer>& i_pPrinter ) 207 : mpImplData( new ImplPrinterControllerData ) 208 { 209 mpImplData->mpPrinter = i_pPrinter; 210 } 211 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 274 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 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 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 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 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 int nPages = i_pController->getFilteredPageCount(); 660 for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ ) 661 { 662 for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ ) 663 { 664 for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ ) 665 { 666 if( nPage == nPages-1 && 667 nOuterIteration == nOuterRepeatCount-1 && 668 nInnerIteration == nInnerRepeatCount-1 && 669 nJobIteration == nJobs-1 ) 670 { 671 i_pController->setLastPage( sal_True ); 672 } 673 i_pController->printFilteredPage( nPage ); 674 if( i_pController->isProgressCanceled() ) 675 { 676 i_pController->abortJob(); 677 bAborted = true; 678 } 679 } 680 } 681 // FIXME: duplex ? 682 } 683 EndJob(); 684 685 if( nJobIteration < nJobs-1 ) 686 { 687 mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); 688 689 if ( mpPrinter ) 690 { 691 maJobName = i_rJobName; 692 mnCurPage = 1; 693 mnCurPrintPage = 1; 694 mbPrinting = sal_True; 695 } 696 else 697 bError = true; 698 } 699 } 700 else 701 bError = true; 702 703 if( bError ) 704 { 705 mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); 706 if ( !mnError ) 707 mnError = PRINTER_GENERALERROR; 708 i_pController->setJobState( mnError == PRINTER_ABORT 709 ? view::PrintableState_JOB_ABORTED 710 : view::PrintableState_JOB_FAILED ); 711 if( mpPrinter ) 712 pSVData->mpDefInst->DestroyPrinter( mpPrinter ); 713 mnCurPage = 0; 714 mnCurPrintPage = 0; 715 mbPrinting = sal_False; 716 mpPrinter = NULL; 717 718 return false; 719 } 720 } 721 722 if( i_pController->getJobState() == view::PrintableState_JOB_STARTED ) 723 i_pController->setJobState( view::PrintableState_JOB_SPOOLED ); 724 } 725 726 // make last used printer persistent for UI jobs 727 if( i_pController->isShowDialogs() && ! i_pController->isDirectPrint() ) 728 { 729 SettingsConfigItem* pItem = SettingsConfigItem::get(); 730 pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), 731 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinterUsed" ) ), 732 GetName() 733 ); 734 } 735 736 return true; 737 } 738 739 PrinterController::~PrinterController() 740 { 741 delete mpImplData; 742 } 743 744 view::PrintableState PrinterController::getJobState() const 745 { 746 return mpImplData->meJobState; 747 } 748 749 void PrinterController::setJobState( view::PrintableState i_eState ) 750 { 751 mpImplData->meJobState = i_eState; 752 } 753 754 const boost::shared_ptr<Printer>& PrinterController::getPrinter() const 755 { 756 return mpImplData->mpPrinter; 757 } 758 759 void PrinterController::setPrinter( const boost::shared_ptr<Printer>& i_rPrinter ) 760 { 761 mpImplData->mpPrinter = i_rPrinter; 762 setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) ), 763 makeAny( rtl::OUString( i_rPrinter->GetName() ) ) ); 764 mpImplData->mnDefaultPaperBin = mpImplData->mpPrinter->GetPaperBin(); 765 mpImplData->mnFixedPaperBin = -1; 766 } 767 768 void PrinterController:: resetPrinterOptions( bool i_bFileOutput ) 769 { 770 PrinterOptions aOpt; 771 aOpt.ReadFromConfig( i_bFileOutput ); 772 mpImplData->mpPrinter->SetPrinterOptions( aOpt ); 773 } 774 775 bool PrinterController::setupPrinter( Window* i_pParent ) 776 { 777 bool bRet = false; 778 if( mpImplData->mpPrinter.get() ) 779 { 780 // get old data 781 Size aPaperSize( mpImplData->mpPrinter->PixelToLogic( 782 mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); 783 sal_uInt16 nPaperBin = mpImplData->mpPrinter->GetPaperBin(); 784 785 // call driver setup 786 bRet = mpImplData->mpPrinter->Setup( i_pParent ); 787 if( bRet ) 788 { 789 // was papersize or bin overridden ? if so we need to take action 790 Size aNewPaperSize( mpImplData->mpPrinter->PixelToLogic( 791 mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); 792 sal_uInt16 nNewPaperBin = mpImplData->mpPrinter->GetPaperBin(); 793 if( aNewPaperSize != aPaperSize || nNewPaperBin != nPaperBin ) 794 { 795 mpImplData->maFixedPageSize = aNewPaperSize; 796 mpImplData->maPageCache.invalidate(); 797 awt::Size aOverrideSize; 798 aOverrideSize.Width = aNewPaperSize.Width(); 799 aOverrideSize.Height = aNewPaperSize.Height(); 800 setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OverridePageSize" ) ), 801 makeAny( aOverrideSize ) ); 802 mpImplData->mnFixedPaperBin = nNewPaperBin; 803 } 804 } 805 } 806 return bRet; 807 } 808 809 PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP ) 810 { 811 PrinterController::PageSize aPageSize; 812 aPageSize.aSize = mpPrinter->GetPaperSize(); 813 awt::Size aSetSize, aIsSize; 814 sal_Int32 nPaperBin = mnDefaultPaperBin; 815 for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty ) 816 { 817 if( i_rProps[ nProperty ].Name.equalsAscii( "PreferredPageSize" ) ) 818 { 819 i_rProps[ nProperty ].Value >>= aSetSize; 820 } 821 else if( i_rProps[ nProperty ].Name.equalsAscii( "PageSize" ) ) 822 { 823 i_rProps[ nProperty ].Value >>= aIsSize; 824 } 825 else if( i_rProps[ nProperty ].Name.equalsAscii( "PageIncludesNonprintableArea" ) ) 826 { 827 sal_Bool bVal = sal_False; 828 i_rProps[ nProperty ].Value >>= bVal; 829 aPageSize.bFullPaper = static_cast<bool>(bVal); 830 } 831 else if( i_rProps[ nProperty ].Name.equalsAscii( "PrinterPaperTray" ) ) 832 { 833 sal_Int32 nBin = -1; 834 i_rProps[ nProperty ].Value >>= nBin; 835 if( nBin >= 0 && nBin < mpPrinter->GetPaperBinCount() ) 836 nPaperBin = nBin; 837 } 838 } 839 840 Size aCurSize( mpPrinter->GetPaperSize() ); 841 if( aSetSize.Width && aSetSize.Height ) 842 { 843 Size aSetPaperSize( aSetSize.Width, aSetSize.Height ); 844 Size aRealPaperSize( getRealPaperSize( aSetPaperSize, bNoNUP ) ); 845 if( aRealPaperSize != aCurSize ) 846 aIsSize = aSetSize; 847 } 848 849 if( aIsSize.Width && aIsSize.Height ) 850 { 851 aPageSize.aSize.Width() = aIsSize.Width; 852 aPageSize.aSize.Height() = aIsSize.Height; 853 854 Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, bNoNUP ) ); 855 if( aRealPaperSize != aCurSize ) 856 mpPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() ); 857 } 858 859 if( nPaperBin != -1 && nPaperBin != mpPrinter->GetPaperBin() ) 860 mpPrinter->SetPaperBin( nPaperBin ); 861 862 return aPageSize; 863 } 864 865 int PrinterController::getPageCountProtected() const 866 { 867 const MapMode aMapMode( MAP_100TH_MM ); 868 869 mpImplData->mpPrinter->Push(); 870 mpImplData->mpPrinter->SetMapMode( aMapMode ); 871 int nPages = getPageCount(); 872 mpImplData->mpPrinter->Pop(); 873 return nPages; 874 } 875 876 Sequence< beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const 877 { 878 const MapMode aMapMode( MAP_100TH_MM ); 879 880 mpImplData->mpPrinter->Push(); 881 mpImplData->mpPrinter->SetMapMode( aMapMode ); 882 Sequence< beans::PropertyValue > aResult( getPageParameters( i_nPage ) ); 883 mpImplData->mpPrinter->Pop(); 884 return aResult; 885 } 886 887 PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) 888 { 889 // update progress if necessary 890 if( mpImplData->mpProgress ) 891 { 892 // do nothing if printing is canceled 893 if( mpImplData->mpProgress->isCanceled() ) 894 return PrinterController::PageSize(); 895 mpImplData->mpProgress->tick(); 896 Application::Reschedule( true ); 897 } 898 899 if( i_bMayUseCache ) 900 { 901 PrinterController::PageSize aPageSize; 902 if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) ) 903 { 904 return aPageSize; 905 } 906 } 907 else 908 mpImplData->maPageCache.invalidate(); 909 910 o_rMtf.Clear(); 911 912 // get page parameters 913 Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) ); 914 const MapMode aMapMode( MAP_100TH_MM ); 915 916 mpImplData->mpPrinter->Push(); 917 mpImplData->mpPrinter->SetMapMode( aMapMode ); 918 919 // modify job setup if necessary 920 PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm, true ); 921 922 o_rMtf.SetPrefSize( aPageSize.aSize ); 923 o_rMtf.SetPrefMapMode( aMapMode ); 924 925 mpImplData->mpPrinter->EnableOutput( sal_False ); 926 927 o_rMtf.Record( mpImplData->mpPrinter.get() ); 928 929 printPage( i_nUnfilteredPage ); 930 931 o_rMtf.Stop(); 932 o_rMtf.WindStart(); 933 mpImplData->mpPrinter->Pop(); 934 935 if( i_bMayUseCache ) 936 mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize ); 937 938 // reset "FirstPage" property to false now we've gotten at least our first one 939 mpImplData->mbFirstPage = sal_False; 940 941 return aPageSize; 942 } 943 944 static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder ) 945 { 946 // intersect all clipregion actions with our clip rect 947 io_rSubPage.WindStart(); 948 io_rSubPage.Clip( i_rClipRect ); 949 950 // save gstate 951 o_rMtf.AddAction( new MetaPushAction( PUSH_ALL ) ); 952 953 // clip to page rect 954 o_rMtf.AddAction( new MetaClipRegionAction( Region( i_rClipRect ), sal_True ) ); 955 956 // append the subpage 957 io_rSubPage.WindStart(); 958 io_rSubPage.Play( o_rMtf ); 959 960 // restore gstate 961 o_rMtf.AddAction( new MetaPopAction() ); 962 963 // draw a border 964 if( i_bDrawBorder ) 965 { 966 // save gstate 967 o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_CLIPREGION | PUSH_MAPMODE ) ); 968 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); 969 970 Rectangle aBorderRect( i_rClipRect ); 971 o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), sal_True ) ); 972 o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), sal_False ) ); 973 o_rMtf.AddAction( new MetaRectAction( aBorderRect ) ); 974 975 // restore gstate 976 o_rMtf.AddAction( new MetaPopAction() ); 977 } 978 } 979 980 PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) 981 { 982 const MultiPageSetup& rMPS( mpImplData->maMultiPage ); 983 int nSubPages = rMPS.nRows * rMPS.nColumns; 984 if( nSubPages < 1 ) 985 nSubPages = 1; 986 987 // reverse sheet order 988 if( mpImplData->mbReversePageOrder ) 989 { 990 int nDocPages = getFilteredPageCount(); 991 i_nFilteredPage = nDocPages - 1 - i_nFilteredPage; 992 } 993 994 // there is no filtering to be done (and possibly the page size of the 995 // original page is to be set), when N-Up is "neutral" that is there is 996 // only one subpage and the margins are 0 997 if( nSubPages == 1 && 998 rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 && 999 rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 ) 1000 { 1001 PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache ); 1002 Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true ); 1003 mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); 1004 mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); 1005 if( aPaperSize != aPageSize.aSize ) 1006 { 1007 // user overridden page size, center Metafile 1008 o_rMtf.WindStart(); 1009 long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2; 1010 long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2; 1011 o_rMtf.Move( nDX, nDY, mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() ); 1012 o_rMtf.WindStart(); 1013 o_rMtf.SetPrefSize( aPaperSize ); 1014 aPageSize.aSize = aPaperSize; 1015 } 1016 return aPageSize; 1017 } 1018 1019 // set last page property really only on the very last page to be rendered 1020 // that is on the last subpage of a NUp run 1021 sal_Bool bIsLastPage = mpImplData->mbLastPage; 1022 mpImplData->mbLastPage = sal_False; 1023 1024 Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) ); 1025 1026 // multi page area: page size minus margins + one time spacing right and down 1027 // the added spacing is so each subpage can be calculated including its spacing 1028 Size aMPArea( aPaperSize ); 1029 aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin; 1030 aMPArea.Width() += rMPS.nHorizontalSpacing; 1031 aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin; 1032 aMPArea.Height() += rMPS.nVerticalSpacing; 1033 1034 // determine offsets 1035 long nAdvX = aMPArea.Width() / rMPS.nColumns; 1036 long nAdvY = aMPArea.Height() / rMPS.nRows; 1037 1038 // determine size of a "cell" subpage, leave a little space around pages 1039 Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing ); 1040 1041 o_rMtf.Clear(); 1042 o_rMtf.SetPrefSize( aPaperSize ); 1043 o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); 1044 o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); 1045 1046 int nDocPages = getPageCountProtected(); 1047 for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ ) 1048 { 1049 // map current sub page to real page 1050 int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat; 1051 if( nSubPage == nSubPages-1 || 1052 nPage == nDocPages-1 ) 1053 { 1054 mpImplData->mbLastPage = bIsLastPage; 1055 } 1056 if( nPage >= 0 && nPage < nDocPages ) 1057 { 1058 GDIMetaFile aPageFile; 1059 PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache ); 1060 if( aPageSize.aSize.Width() && aPageSize.aSize.Height() ) 1061 { 1062 long nCellX = 0, nCellY = 0; 1063 switch( rMPS.nOrder ) 1064 { 1065 case PrinterController::LRTB: 1066 nCellX = (nSubPage % rMPS.nColumns); 1067 nCellY = (nSubPage / rMPS.nColumns); 1068 break; 1069 case PrinterController::TBLR: 1070 nCellX = (nSubPage / rMPS.nRows); 1071 nCellY = (nSubPage % rMPS.nRows); 1072 break; 1073 case PrinterController::RLTB: 1074 nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns); 1075 nCellY = (nSubPage / rMPS.nColumns); 1076 break; 1077 case PrinterController::TBRL: 1078 nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows); 1079 nCellY = (nSubPage % rMPS.nRows); 1080 break; 1081 } 1082 // scale the metafile down to a sub page size 1083 double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width()); 1084 double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height()); 1085 double fScale = std::min( fScaleX, fScaleY ); 1086 aPageFile.Scale( fScale, fScale ); 1087 aPageFile.WindStart(); 1088 1089 // move the subpage so it is centered in its "cell" 1090 long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2; 1091 long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2; 1092 long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX; 1093 long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY; 1094 aPageFile.Move( nX, nY, mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() ); 1095 aPageFile.WindStart(); 1096 // calculate border rectangle 1097 Rectangle aSubPageRect( Point( nX, nY ), 1098 Size( long(double(aPageSize.aSize.Width())*fScale), 1099 long(double(aPageSize.aSize.Height())*fScale) ) ); 1100 1101 // append subpage to page 1102 appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder ); 1103 } 1104 } 1105 } 1106 o_rMtf.WindStart(); 1107 1108 // subsequent getPageFile calls have changed the paper, reset it to current value 1109 mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); 1110 mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); 1111 1112 return PrinterController::PageSize( aPaperSize, true ); 1113 } 1114 1115 int PrinterController::getFilteredPageCount() 1116 { 1117 int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns; 1118 if( nDiv < 1 ) 1119 nDiv = 1; 1120 return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv; 1121 } 1122 1123 sal_uLong PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut ) 1124 { 1125 sal_uLong nRestoreDrawMode = mpImplData->mpPrinter->GetDrawMode(); 1126 sal_Int32 nMaxBmpDPIX = mpImplData->mpPrinter->ImplGetDPIX(); 1127 sal_Int32 nMaxBmpDPIY = mpImplData->mpPrinter->ImplGetDPIY(); 1128 1129 const PrinterOptions& rPrinterOptions = mpImplData->mpPrinter->GetPrinterOptions(); 1130 1131 static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300; 1132 static const sal_Int32 NORMAL_BMP_RESOLUTION = 200; 1133 1134 1135 if( rPrinterOptions.IsReduceBitmaps() ) 1136 { 1137 // calculate maximum resolution for bitmap graphics 1138 if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() ) 1139 { 1140 nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX ); 1141 nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY ); 1142 } 1143 else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() ) 1144 { 1145 nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX ); 1146 nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY ); 1147 } 1148 else 1149 { 1150 nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX ); 1151 nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY ); 1152 } 1153 } 1154 1155 // convert to greysacles 1156 if( rPrinterOptions.IsConvertToGreyscales() ) 1157 { 1158 mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | 1159 ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | 1160 DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); 1161 } 1162 1163 // disable transparency output 1164 if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) ) 1165 { 1166 mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | DRAWMODE_NOTRANSPARENCY ); 1167 } 1168 1169 Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic 1170 if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 ) 1171 { 1172 // in N-Up printing we have no "page" background operation 1173 // we also have no way to determine the paper color 1174 // so let's go for white, which will kill 99.9% of the real cases 1175 aBg = Color( COL_WHITE ); 1176 } 1177 mpImplData->mpPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY, 1178 rPrinterOptions.IsReduceTransparency(), 1179 rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO, 1180 rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(), 1181 aBg 1182 ); 1183 return nRestoreDrawMode; 1184 } 1185 1186 void PrinterController::printFilteredPage( int i_nPage ) 1187 { 1188 if( mpImplData->meJobState != view::PrintableState_JOB_STARTED ) 1189 return; 1190 1191 GDIMetaFile aPageFile; 1192 PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile ); 1193 1194 if( mpImplData->mpProgress ) 1195 { 1196 // do nothing if printing is canceled 1197 if( mpImplData->mpProgress->isCanceled() ) 1198 { 1199 setJobState( view::PrintableState_JOB_ABORTED ); 1200 return; 1201 } 1202 } 1203 1204 // in N-Up printing set the correct page size 1205 mpImplData->mpPrinter->SetMapMode( MAP_100TH_MM ); 1206 // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile() 1207 mpImplData->mpPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() ); 1208 if( mpImplData->mnFixedPaperBin != -1 && 1209 mpImplData->mpPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin ) 1210 { 1211 mpImplData->mpPrinter->SetPaperBin( mpImplData->mnFixedPaperBin ); 1212 } 1213 1214 // if full paper is meant to be used, move the output to accomodate for pageoffset 1215 if( aPageSize.bFullPaper ) 1216 { 1217 Point aPageOffset( mpImplData->mpPrinter->GetPageOffset() ); 1218 aPageFile.WindStart(); 1219 aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() ); 1220 } 1221 1222 GDIMetaFile aCleanedFile; 1223 sal_uLong nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile ); 1224 1225 mpImplData->mpPrinter->EnableOutput( sal_True ); 1226 1227 // actually print the page 1228 mpImplData->mpPrinter->ImplStartPage(); 1229 1230 mpImplData->mpPrinter->Push(); 1231 aCleanedFile.WindStart(); 1232 aCleanedFile.Play( mpImplData->mpPrinter.get() ); 1233 mpImplData->mpPrinter->Pop(); 1234 1235 mpImplData->mpPrinter->ImplEndPage(); 1236 1237 mpImplData->mpPrinter->SetDrawMode( nRestoreDrawMode ); 1238 } 1239 1240 void PrinterController::jobStarted() 1241 { 1242 } 1243 1244 void PrinterController::jobFinished( view::PrintableState ) 1245 { 1246 } 1247 1248 void PrinterController::triggerAppToFreeResources() 1249 { 1250 // applications (well, sw) depend on a page request with "IsLastPage" = true 1251 // to free resources, else they (well, sw) will crash eventually 1252 setLastPage( sal_True ); 1253 delete mpImplData->mpProgress; 1254 mpImplData->mpProgress = NULL; 1255 GDIMetaFile aMtf; 1256 getPageFile( 0, aMtf, false ); 1257 setLastPage( sal_False ); 1258 } 1259 1260 void PrinterController::abortJob() 1261 { 1262 setJobState( view::PrintableState_JOB_ABORTED ); 1263 1264 triggerAppToFreeResources(); 1265 } 1266 1267 void PrinterController::setLastPage( sal_Bool i_bLastPage ) 1268 { 1269 mpImplData->mbLastPage = i_bLastPage; 1270 } 1271 1272 void PrinterController::setReversePrint( sal_Bool i_bReverse ) 1273 { 1274 mpImplData->mbReversePageOrder = i_bReverse; 1275 } 1276 1277 bool PrinterController::getReversePrint() const 1278 { 1279 return mpImplData->mbReversePageOrder; 1280 } 1281 1282 Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const 1283 { 1284 std::hash_set< rtl::OUString, rtl::OUStringHash > aMergeSet; 1285 size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3; 1286 for( int i = 0; i < i_rMergeList.getLength(); i++ ) 1287 aMergeSet.insert( i_rMergeList[i].Name ); 1288 1289 Sequence< PropertyValue > aResult( nResultLen ); 1290 for( int i = 0; i < i_rMergeList.getLength(); i++ ) 1291 aResult[i] = i_rMergeList[i]; 1292 int nCur = i_rMergeList.getLength(); 1293 for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ ) 1294 { 1295 if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() ) 1296 aResult[nCur++] = mpImplData->maUIProperties[i]; 1297 } 1298 // append IsFirstPage 1299 if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) ) == aMergeSet.end() ) 1300 { 1301 PropertyValue aVal; 1302 aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ); 1303 aVal.Value <<= mpImplData->mbFirstPage; 1304 aResult[nCur++] = aVal; 1305 } 1306 // append IsLastPage 1307 if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) ) == aMergeSet.end() ) 1308 { 1309 PropertyValue aVal; 1310 aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ); 1311 aVal.Value <<= mpImplData->mbLastPage; 1312 aResult[nCur++] = aVal; 1313 } 1314 // append IsPrinter 1315 if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ) ) == aMergeSet.end() ) 1316 { 1317 PropertyValue aVal; 1318 aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ); 1319 aVal.Value <<= sal_True; 1320 aResult[nCur++] = aVal; 1321 } 1322 aResult.realloc( nCur ); 1323 return aResult; 1324 } 1325 1326 const Sequence< beans::PropertyValue >& PrinterController::getUIOptions() const 1327 { 1328 return mpImplData->maUIOptions; 1329 } 1330 1331 beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) 1332 { 1333 std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = 1334 mpImplData->maPropertyToIndex.find( i_rProperty ); 1335 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; 1336 } 1337 1338 const beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) const 1339 { 1340 std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = 1341 mpImplData->maPropertyToIndex.find( i_rProperty ); 1342 return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; 1343 } 1344 1345 Sequence< beans::PropertyValue > PrinterController::getValues( const Sequence< rtl::OUString >& i_rNames ) const 1346 { 1347 Sequence< beans::PropertyValue > aRet( i_rNames.getLength() ); 1348 sal_Int32 nFound = 0; 1349 for( sal_Int32 i = 0; i < i_rNames.getLength(); i++ ) 1350 { 1351 const beans::PropertyValue* pVal = getValue( i_rNames[i] ); 1352 if( pVal ) 1353 aRet[ nFound++ ] = *pVal; 1354 } 1355 aRet.realloc( nFound ); 1356 return aRet; 1357 } 1358 1359 void PrinterController::setValue( const rtl::OUString& i_rName, const Any& i_rValue ) 1360 { 1361 beans::PropertyValue aVal; 1362 aVal.Name = i_rName; 1363 aVal.Value = i_rValue; 1364 1365 setValue( aVal ); 1366 } 1367 1368 void PrinterController::setValue( const beans::PropertyValue& i_rValue ) 1369 { 1370 std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = 1371 mpImplData->maPropertyToIndex.find( i_rValue.Name ); 1372 if( it != mpImplData->maPropertyToIndex.end() ) 1373 mpImplData->maUIProperties[ it->second ] = i_rValue; 1374 else 1375 { 1376 // insert correct index into property map 1377 mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size(); 1378 mpImplData->maUIProperties.push_back( i_rValue ); 1379 mpImplData->maUIPropertyEnabled.push_back( true ); 1380 } 1381 } 1382 1383 void PrinterController::setUIOptions( const Sequence< beans::PropertyValue >& i_rOptions ) 1384 { 1385 DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" ); 1386 1387 mpImplData->maUIOptions = i_rOptions; 1388 1389 for( int i = 0; i < i_rOptions.getLength(); i++ ) 1390 { 1391 Sequence< beans::PropertyValue > aOptProp; 1392 i_rOptions[i].Value >>= aOptProp; 1393 bool bIsEnabled = true; 1394 bool bHaveProperty = false; 1395 rtl::OUString aPropName; 1396 vcl::ImplPrinterControllerData::ControlDependency aDep; 1397 Sequence< sal_Bool > aChoicesDisabled; 1398 for( int n = 0; n < aOptProp.getLength(); n++ ) 1399 { 1400 const beans::PropertyValue& rEntry( aOptProp[ n ] ); 1401 if( rEntry.Name.equalsAscii( "Property" ) ) 1402 { 1403 PropertyValue aVal; 1404 rEntry.Value >>= aVal; 1405 DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name ) 1406 == mpImplData->maPropertyToIndex.end(), "duplicate property entry" ); 1407 setValue( aVal ); 1408 aPropName = aVal.Name; 1409 bHaveProperty = true; 1410 } 1411 else if( rEntry.Name.equalsAscii( "Enabled" ) ) 1412 { 1413 sal_Bool bValue = sal_True; 1414 rEntry.Value >>= bValue; 1415 bIsEnabled = bValue; 1416 } 1417 else if( rEntry.Name.equalsAscii( "DependsOnName" ) ) 1418 { 1419 rEntry.Value >>= aDep.maDependsOnName; 1420 } 1421 else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) ) 1422 { 1423 rEntry.Value >>= aDep.mnDependsOnEntry; 1424 } 1425 else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) ) 1426 { 1427 rEntry.Value >>= aChoicesDisabled; 1428 } 1429 } 1430 if( bHaveProperty ) 1431 { 1432 vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it = 1433 mpImplData->maPropertyToIndex.find( aPropName ); 1434 // sanity check 1435 if( it != mpImplData->maPropertyToIndex.end() ) 1436 { 1437 mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled; 1438 } 1439 if( aDep.maDependsOnName.getLength() > 0 ) 1440 mpImplData->maControlDependencies[ aPropName ] = aDep; 1441 if( aChoicesDisabled.getLength() > 0 ) 1442 mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled; 1443 } 1444 } 1445 } 1446 1447 void PrinterController::enableUIOption( const rtl::OUString& i_rProperty, bool i_bEnable ) 1448 { 1449 std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = 1450 mpImplData->maPropertyToIndex.find( i_rProperty ); 1451 if( it != mpImplData->maPropertyToIndex.end() ) 1452 { 1453 // call handler only for actual changes 1454 if( ( mpImplData->maUIPropertyEnabled[ it->second ] && ! i_bEnable ) || 1455 ( ! mpImplData->maUIPropertyEnabled[ it->second ] && i_bEnable ) ) 1456 { 1457 mpImplData->maUIPropertyEnabled[ it->second ] = i_bEnable; 1458 rtl::OUString aPropName( i_rProperty ); 1459 mpImplData->maOptionChangeHdl.Call( &aPropName ); 1460 } 1461 } 1462 } 1463 1464 bool PrinterController::isUIOptionEnabled( const rtl::OUString& i_rProperty ) const 1465 { 1466 bool bEnabled = false; 1467 std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator prop_it = 1468 mpImplData->maPropertyToIndex.find( i_rProperty ); 1469 if( prop_it != mpImplData->maPropertyToIndex.end() ) 1470 { 1471 bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second]; 1472 1473 if( bEnabled ) 1474 { 1475 // check control dependencies 1476 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = 1477 mpImplData->maControlDependencies.find( i_rProperty ); 1478 if( it != mpImplData->maControlDependencies.end() ) 1479 { 1480 // check if the dependency is enabled 1481 // if the dependency is disabled, we are too 1482 bEnabled = isUIOptionEnabled( it->second.maDependsOnName ); 1483 1484 if( bEnabled ) 1485 { 1486 // does the dependency have the correct value ? 1487 const com::sun::star::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName ); 1488 OSL_ENSURE( pVal, "unknown property in dependency" ); 1489 if( pVal ) 1490 { 1491 sal_Int32 nDepVal = 0; 1492 sal_Bool bDepVal = sal_False; 1493 if( pVal->Value >>= nDepVal ) 1494 { 1495 bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1); 1496 } 1497 else if( pVal->Value >>= bDepVal ) 1498 { 1499 // could be a dependency on a checked boolean 1500 // in this case the dependency is on a non zero for checked value 1501 bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) || 1502 ( ! bDepVal && it->second.mnDependsOnEntry == 0); 1503 } 1504 else 1505 { 1506 // if the type does not match something is awry 1507 OSL_ENSURE( 0, "strange type in control dependency" ); 1508 bEnabled = false; 1509 } 1510 } 1511 } 1512 } 1513 } 1514 } 1515 return bEnabled; 1516 } 1517 1518 bool PrinterController::isUIChoiceEnabled( const rtl::OUString& i_rProperty, sal_Int32 i_nValue ) const 1519 { 1520 bool bEnabled = true; 1521 ImplPrinterControllerData::ChoiceDisableMap::const_iterator it = 1522 mpImplData->maChoiceDisableMap.find( i_rProperty ); 1523 if(it != mpImplData->maChoiceDisableMap.end() ) 1524 { 1525 const Sequence< sal_Bool >& rDisabled( it->second ); 1526 if( i_nValue >= 0 && i_nValue < rDisabled.getLength() ) 1527 bEnabled = ! rDisabled[i_nValue]; 1528 } 1529 return bEnabled; 1530 } 1531 1532 rtl::OUString PrinterController::getDependency( const rtl::OUString& i_rProperty ) const 1533 { 1534 rtl::OUString aDependency; 1535 1536 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = 1537 mpImplData->maControlDependencies.find( i_rProperty ); 1538 if( it != mpImplData->maControlDependencies.end() ) 1539 aDependency = it->second.maDependsOnName; 1540 1541 return aDependency; 1542 } 1543 1544 rtl::OUString PrinterController::makeEnabled( const rtl::OUString& i_rProperty ) 1545 { 1546 rtl::OUString aDependency; 1547 1548 vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = 1549 mpImplData->maControlDependencies.find( i_rProperty ); 1550 if( it != mpImplData->maControlDependencies.end() ) 1551 { 1552 if( isUIOptionEnabled( it->second.maDependsOnName ) ) 1553 { 1554 aDependency = it->second.maDependsOnName; 1555 const com::sun::star::beans::PropertyValue* pVal = getValue( aDependency ); 1556 OSL_ENSURE( pVal, "unknown property in dependency" ); 1557 if( pVal ) 1558 { 1559 sal_Int32 nDepVal = 0; 1560 sal_Bool bDepVal = sal_False; 1561 if( pVal->Value >>= nDepVal ) 1562 { 1563 if( it->second.mnDependsOnEntry != -1 ) 1564 { 1565 setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) ); 1566 } 1567 } 1568 else if( pVal->Value >>= bDepVal ) 1569 { 1570 setValue( aDependency, makeAny( sal_Bool( it->second.mnDependsOnEntry != 0 ) ) ); 1571 } 1572 else 1573 { 1574 // if the type does not match something is awry 1575 OSL_ENSURE( 0, "strange type in control dependency" ); 1576 } 1577 } 1578 } 1579 } 1580 1581 return aDependency; 1582 } 1583 1584 void PrinterController::setOptionChangeHdl( const Link& i_rHdl ) 1585 { 1586 mpImplData->maOptionChangeHdl = i_rHdl; 1587 } 1588 1589 void PrinterController::createProgressDialog() 1590 { 1591 if( ! mpImplData->mpProgress ) 1592 { 1593 sal_Bool bShow = sal_True; 1594 beans::PropertyValue* pMonitor = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) ); 1595 if( pMonitor ) 1596 pMonitor->Value >>= bShow; 1597 else 1598 { 1599 const com::sun::star::beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ) ); 1600 if( pVal ) 1601 { 1602 sal_Bool bApi = sal_False; 1603 pVal->Value >>= bApi; 1604 bShow = ! bApi; 1605 } 1606 } 1607 1608 if( bShow && ! Application::IsHeadlessModeEnabled() ) 1609 { 1610 mpImplData->mpProgress = new PrintProgressDialog( NULL, getPageCountProtected() ); 1611 mpImplData->mpProgress->Show(); 1612 } 1613 } 1614 else 1615 mpImplData->mpProgress->reset(); 1616 } 1617 1618 bool PrinterController::isProgressCanceled() const 1619 { 1620 return mpImplData->mpProgress && mpImplData->mpProgress->isCanceled(); 1621 } 1622 1623 void PrinterController::setMultipage( const MultiPageSetup& i_rMPS ) 1624 { 1625 mpImplData->maMultiPage = i_rMPS; 1626 } 1627 1628 const PrinterController::MultiPageSetup& PrinterController::getMultipage() const 1629 { 1630 return mpImplData->maMultiPage; 1631 } 1632 1633 void PrinterController::pushPropertiesToPrinter() 1634 { 1635 sal_Int32 nCopyCount = 1; 1636 // set copycount and collate 1637 const beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) ); 1638 if( pVal ) 1639 pVal->Value >>= nCopyCount; 1640 sal_Bool bCollate = sal_False; 1641 pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); 1642 if( pVal ) 1643 pVal->Value >>= bCollate; 1644 mpImplData->mpPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate ); 1645 1646 // duplex mode 1647 pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexMode" ) ) ); 1648 if( pVal ) 1649 { 1650 sal_Int16 nDuplex = view::DuplexMode::UNKNOWN; 1651 pVal->Value >>= nDuplex; 1652 switch( nDuplex ) 1653 { 1654 case view::DuplexMode::OFF: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_OFF ); break; 1655 case view::DuplexMode::LONGEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break; 1656 case view::DuplexMode::SHORTEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break; 1657 } 1658 } 1659 } 1660 1661 bool PrinterController::isShowDialogs() const 1662 { 1663 sal_Bool bApi = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ), sal_False ); 1664 return ! bApi && ! Application::IsHeadlessModeEnabled(); 1665 } 1666 1667 bool PrinterController::isDirectPrint() const 1668 { 1669 sal_Bool bDirect = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), sal_False ); 1670 return bDirect == sal_True; 1671 } 1672 1673 sal_Bool PrinterController::getBoolProperty( const rtl::OUString& i_rProperty, sal_Bool i_bFallback ) const 1674 { 1675 sal_Bool bRet = i_bFallback; 1676 const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty ); 1677 if( pVal ) 1678 pVal->Value >>= bRet; 1679 return bRet; 1680 } 1681 1682 sal_Int32 PrinterController::getIntProperty( const rtl::OUString& i_rProperty, sal_Int32 i_nFallback ) const 1683 { 1684 sal_Int32 nRet = i_nFallback; 1685 const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty ); 1686 if( pVal ) 1687 pVal->Value >>= nRet; 1688 return nRet; 1689 } 1690 1691 /* 1692 * PrinterOptionsHelper 1693 **/ 1694 Any PrinterOptionsHelper::getValue( const rtl::OUString& i_rPropertyName ) const 1695 { 1696 Any aRet; 1697 std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = 1698 m_aPropertyMap.find( i_rPropertyName ); 1699 if( it != m_aPropertyMap.end() ) 1700 aRet = it->second; 1701 return aRet; 1702 } 1703 1704 void PrinterOptionsHelper::setValue( const rtl::OUString& i_rPropertyName, const Any& i_rValue ) 1705 { 1706 m_aPropertyMap[ i_rPropertyName ] = i_rValue; 1707 } 1708 1709 bool PrinterOptionsHelper::hasProperty( const rtl::OUString& i_rPropertyName ) const 1710 { 1711 Any aRet; 1712 std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = 1713 m_aPropertyMap.find( i_rPropertyName ); 1714 return it != m_aPropertyMap.end(); 1715 } 1716 1717 sal_Bool PrinterOptionsHelper::getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault ) const 1718 { 1719 sal_Bool bRet = sal_False; 1720 Any aVal( getValue( i_rPropertyName ) ); 1721 return (aVal >>= bRet) ? bRet : i_bDefault; 1722 } 1723 1724 sal_Int64 PrinterOptionsHelper::getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault ) const 1725 { 1726 sal_Int64 nRet = 0; 1727 Any aVal( getValue( i_rPropertyName ) ); 1728 return (aVal >>= nRet) ? nRet : i_nDefault; 1729 } 1730 1731 rtl::OUString PrinterOptionsHelper::getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault ) const 1732 { 1733 rtl::OUString aRet; 1734 Any aVal( getValue( i_rPropertyName ) ); 1735 return (aVal >>= aRet) ? aRet : i_rDefault; 1736 } 1737 1738 bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp, 1739 std::set< rtl::OUString >* o_pChangeProp ) 1740 { 1741 bool bChanged = false; 1742 1743 // clear the changed set 1744 if( o_pChangeProp ) 1745 o_pChangeProp->clear(); 1746 1747 sal_Int32 nElements = i_rNewProp.getLength(); 1748 const PropertyValue* pVals = i_rNewProp.getConstArray(); 1749 for( sal_Int32 i = 0; i < nElements; i++ ) 1750 { 1751 bool bElementChanged = false; 1752 std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::iterator it = 1753 m_aPropertyMap.find( pVals[ i ].Name ); 1754 if( it != m_aPropertyMap.end() ) 1755 { 1756 if( it->second != pVals[ i ].Value ) 1757 bElementChanged = true; 1758 } 1759 else 1760 bElementChanged = true; 1761 1762 if( bElementChanged ) 1763 { 1764 if( o_pChangeProp ) 1765 o_pChangeProp->insert( pVals[ i ].Name ); 1766 m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value; 1767 bChanged = true; 1768 } 1769 } 1770 return bChanged; 1771 } 1772 1773 void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< beans::PropertyValue >& io_rProps ) const 1774 { 1775 if( m_aUIProperties.getLength() > 0 ) 1776 { 1777 sal_Int32 nIndex = io_rProps.getLength(); 1778 io_rProps.realloc( nIndex+1 ); 1779 PropertyValue aVal; 1780 aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExtraPrintUIOptions" ) ); 1781 aVal.Value = makeAny( m_aUIProperties ); 1782 io_rProps[ nIndex ] = aVal; 1783 } 1784 } 1785 1786 Any PrinterOptionsHelper::getUIControlOpt( const rtl::OUString& i_rTitle, 1787 const Sequence< rtl::OUString >& i_rHelpIds, 1788 const rtl::OUString& i_rType, 1789 const PropertyValue* i_pVal, 1790 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1791 ) 1792 { 1793 sal_Int32 nElements = 1794 1 // ControlType 1795 + (i_rTitle.getLength() ? 1 : 0) // Text 1796 + (i_rHelpIds.getLength() ? 1 : 0) // HelpId 1797 + (i_pVal ? 1 : 0) // Property 1798 + i_rControlOptions.maAddProps.getLength() // additional props 1799 + (i_rControlOptions.maGroupHint.getLength() ? 1 : 0) // grouping 1800 + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint 1801 + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled 1802 ; 1803 if( i_rControlOptions.maDependsOnName.getLength() ) 1804 { 1805 nElements += 1; 1806 if( i_rControlOptions.mnDependsOnEntry != -1 ) 1807 nElements += 1; 1808 if( i_rControlOptions.mbAttachToDependency ) 1809 nElements += 1; 1810 } 1811 1812 Sequence< PropertyValue > aCtrl( nElements ); 1813 sal_Int32 nUsed = 0; 1814 if( i_rTitle.getLength() ) 1815 { 1816 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); 1817 aCtrl[nUsed++].Value = makeAny( i_rTitle ); 1818 } 1819 if( i_rHelpIds.getLength() ) 1820 { 1821 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpId" ) ); 1822 aCtrl[nUsed++].Value = makeAny( i_rHelpIds ); 1823 } 1824 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlType" ) ); 1825 aCtrl[nUsed++].Value = makeAny( i_rType ); 1826 if( i_pVal ) 1827 { 1828 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property" ) ); 1829 aCtrl[nUsed++].Value = makeAny( *i_pVal ); 1830 } 1831 if( i_rControlOptions.maDependsOnName.getLength() ) 1832 { 1833 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnName" ) ); 1834 aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName ); 1835 if( i_rControlOptions.mnDependsOnEntry != -1 ) 1836 { 1837 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnEntry" ) ); 1838 aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry ); 1839 } 1840 if( i_rControlOptions.mbAttachToDependency ) 1841 { 1842 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AttachToDependency" ) ); 1843 aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency ); 1844 } 1845 } 1846 if( i_rControlOptions.maGroupHint.getLength() ) 1847 { 1848 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GroupingHint" ) ); 1849 aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint; 1850 } 1851 if( i_rControlOptions.mbInternalOnly ) 1852 { 1853 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InternalUIOnly" ) ); 1854 aCtrl[nUsed++].Value <<= sal_True; 1855 } 1856 if( ! i_rControlOptions.mbEnabled ) 1857 { 1858 aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); 1859 aCtrl[nUsed++].Value <<= sal_False; 1860 } 1861 1862 sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength(); 1863 for( sal_Int32 i = 0; i < nAddProps; i++ ) 1864 aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i]; 1865 1866 DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" ); 1867 1868 return makeAny( aCtrl ); 1869 } 1870 1871 Any PrinterOptionsHelper::getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpId ) 1872 { 1873 Sequence< rtl::OUString > aHelpId; 1874 if( i_rHelpId.getLength() > 0 ) 1875 { 1876 aHelpId.realloc( 1 ); 1877 *aHelpId.getArray() = i_rHelpId; 1878 } 1879 return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Group" ) ) ); 1880 } 1881 1882 Any PrinterOptionsHelper::getSubgroupControlOpt( const rtl::OUString& i_rTitle, 1883 const rtl::OUString& i_rHelpId, 1884 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1885 ) 1886 { 1887 Sequence< rtl::OUString > aHelpId; 1888 if( i_rHelpId.getLength() > 0 ) 1889 { 1890 aHelpId.realloc( 1 ); 1891 *aHelpId.getArray() = i_rHelpId; 1892 } 1893 return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Subgroup" ) ), 1894 NULL, i_rControlOptions ); 1895 } 1896 1897 Any PrinterOptionsHelper::getBoolControlOpt( const rtl::OUString& i_rTitle, 1898 const rtl::OUString& i_rHelpId, 1899 const rtl::OUString& i_rProperty, 1900 sal_Bool i_bValue, 1901 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1902 ) 1903 { 1904 Sequence< rtl::OUString > aHelpId; 1905 if( i_rHelpId.getLength() > 0 ) 1906 { 1907 aHelpId.realloc( 1 ); 1908 *aHelpId.getArray() = i_rHelpId; 1909 } 1910 PropertyValue aVal; 1911 aVal.Name = i_rProperty; 1912 aVal.Value = makeAny( i_bValue ); 1913 return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bool" ) ), &aVal, i_rControlOptions ); 1914 } 1915 1916 Any PrinterOptionsHelper::getChoiceControlOpt( const rtl::OUString& i_rTitle, 1917 const Sequence< rtl::OUString >& i_rHelpId, 1918 const rtl::OUString& i_rProperty, 1919 const Sequence< rtl::OUString >& i_rChoices, 1920 sal_Int32 i_nValue, 1921 const rtl::OUString& i_rType, 1922 const Sequence< sal_Bool >& i_rDisabledChoices, 1923 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1924 ) 1925 { 1926 UIControlOptions aOpt( i_rControlOptions ); 1927 sal_Int32 nUsed = aOpt.maAddProps.getLength(); 1928 aOpt.maAddProps.realloc( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) ); 1929 aOpt.maAddProps[nUsed].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Choices" ) ); 1930 aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices ); 1931 if( i_rDisabledChoices.getLength() ) 1932 { 1933 aOpt.maAddProps[nUsed+1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChoicesDisabled" ) ); 1934 aOpt.maAddProps[nUsed+1].Value = makeAny( i_rDisabledChoices ); 1935 } 1936 1937 PropertyValue aVal; 1938 aVal.Name = i_rProperty; 1939 aVal.Value = makeAny( i_nValue ); 1940 return getUIControlOpt( i_rTitle, i_rHelpId, i_rType, &aVal, aOpt ); 1941 } 1942 1943 Any PrinterOptionsHelper::getRangeControlOpt( const rtl::OUString& i_rTitle, 1944 const rtl::OUString& i_rHelpId, 1945 const rtl::OUString& i_rProperty, 1946 sal_Int32 i_nValue, 1947 sal_Int32 i_nMinValue, 1948 sal_Int32 i_nMaxValue, 1949 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1950 ) 1951 { 1952 UIControlOptions aOpt( i_rControlOptions ); 1953 if( i_nMaxValue >= i_nMinValue ) 1954 { 1955 sal_Int32 nUsed = aOpt.maAddProps.getLength(); 1956 aOpt.maAddProps.realloc( nUsed + 2 ); 1957 aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MinValue" ) ); 1958 aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue ); 1959 aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxValue" ) ); 1960 aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue ); 1961 } 1962 1963 Sequence< rtl::OUString > aHelpId; 1964 if( i_rHelpId.getLength() > 0 ) 1965 { 1966 aHelpId.realloc( 1 ); 1967 *aHelpId.getArray() = i_rHelpId; 1968 } 1969 PropertyValue aVal; 1970 aVal.Name = i_rProperty; 1971 aVal.Value = makeAny( i_nValue ); 1972 return getUIControlOpt( i_rTitle, 1973 aHelpId, 1974 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Range" ) ), 1975 &aVal, 1976 aOpt 1977 ); 1978 } 1979 1980 Any PrinterOptionsHelper::getEditControlOpt( const rtl::OUString& i_rTitle, 1981 const rtl::OUString& i_rHelpId, 1982 const rtl::OUString& i_rProperty, 1983 const rtl::OUString& i_rValue, 1984 const PrinterOptionsHelper::UIControlOptions& i_rControlOptions 1985 ) 1986 { 1987 Sequence< rtl::OUString > aHelpId; 1988 if( i_rHelpId.getLength() > 0 ) 1989 { 1990 aHelpId.realloc( 1 ); 1991 *aHelpId.getArray() = i_rHelpId; 1992 } 1993 PropertyValue aVal; 1994 aVal.Name = i_rProperty; 1995 aVal.Value = makeAny( i_rValue ); 1996 return getUIControlOpt( i_rTitle, 1997 aHelpId, 1998 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Edit" ) ), 1999 &aVal, 2000 i_rControlOptions 2001 ); 2002 } 2003