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