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