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