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