1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 /** 32 this file implements the sal printer interface ( SalPrinter, SalInfoPrinter 33 and some printer relevant methods of SalInstance and SalGraphicsData ) 34 35 as aunderlying library the printer features of psprint are used. 36 37 The query methods of a SalInfoPrinter are implemented by querying psprint 38 39 The job methods of a SalPrinter are implemented by calling psprint 40 printer job functions. 41 */ 42 43 #include <unistd.h> 44 #include <sys/wait.h> 45 #include <sys/stat.h> 46 47 #include "rtl/ustring.hxx" 48 49 #include "osl/module.h" 50 51 #include "vcl/svapp.hxx" 52 #include "vcl/print.hxx" 53 #include "vcl/pdfwriter.hxx" 54 #include "vcl/printerinfomanager.hxx" 55 56 #include <unx/salunx.h> 57 #include "unx/saldisp.hxx" 58 #include "unx/salinst.h" 59 #include "unx/salprn.h" 60 #include "unx/salframe.h" 61 #include "unx/pspgraphics.h" 62 #include "unx/saldata.hxx" 63 64 #include "jobset.h" 65 #include "print.h" 66 #include "salptype.hxx" 67 68 using namespace psp; 69 using namespace rtl; 70 using namespace com::sun::star; 71 72 /* 73 * static helpers 74 */ 75 76 static oslModule driverLib = NULL; 77 extern "C" 78 { 79 typedef int(*setupFunction)(PrinterInfo&); 80 static setupFunction pSetupFunction = NULL; 81 typedef int(*faxFunction)(String&); 82 static faxFunction pFaxNrFunction = NULL; 83 } 84 85 static String getPdfDir( const PrinterInfo& rInfo ) 86 { 87 String aDir; 88 sal_Int32 nIndex = 0; 89 while( nIndex != -1 ) 90 { 91 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 92 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 93 { 94 sal_Int32 nPos = 0; 95 aDir = aToken.getToken( 1, '=', nPos ); 96 if( ! aDir.Len() ) 97 aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() ); 98 break; 99 } 100 } 101 return aDir; 102 } 103 104 static void getPaLib() 105 { 106 if( ! driverLib ) 107 { 108 OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) ); 109 driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT ); 110 if ( !driverLib ) 111 { 112 return; 113 } 114 115 pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" ); 116 if ( !pSetupFunction ) 117 fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" ); 118 119 pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" ); 120 if ( !pFaxNrFunction ) 121 fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" ); 122 } 123 } 124 125 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); } 126 127 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); } 128 129 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) 130 { 131 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT); 132 133 // copy page size 134 String aPaper; 135 int width, height; 136 137 rData.m_aContext.getPageSize( aPaper, width, height ); 138 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 )); 139 140 pJobSetup->mnPaperWidth = 0; 141 pJobSetup->mnPaperHeight = 0; 142 if( pJobSetup->mePaperFormat == PAPER_USER ) 143 { 144 // transform to 100dth mm 145 width = PtTo10Mu( width ); 146 height = PtTo10Mu( height ); 147 148 if( rData.m_eOrientation == psp::orientation::Portrait ) 149 { 150 pJobSetup->mnPaperWidth = width; 151 pJobSetup->mnPaperHeight= height; 152 } 153 else 154 { 155 pJobSetup->mnPaperWidth = height; 156 pJobSetup->mnPaperHeight= width; 157 } 158 } 159 160 // copy input slot 161 const PPDKey* pKey = NULL; 162 const PPDValue* pValue = NULL; 163 164 pJobSetup->mnPaperBin = 0; 165 if( rData.m_pParser ) 166 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 167 if( pKey ) 168 pValue = rData.m_aContext.getValue( pKey ); 169 if( pKey && pValue ) 170 { 171 for( pJobSetup->mnPaperBin = 0; 172 pValue != pKey->getValue( pJobSetup->mnPaperBin ) && 173 pJobSetup->mnPaperBin < pKey->countValues(); 174 pJobSetup->mnPaperBin++ ) 175 ; 176 if( pJobSetup->mnPaperBin >= pKey->countValues() ) 177 pJobSetup->mnPaperBin = 0; 178 } 179 180 // copy duplex 181 pKey = NULL; 182 pValue = NULL; 183 184 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; 185 if( rData.m_pParser ) 186 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 187 if( pKey ) 188 pValue = rData.m_aContext.getValue( pKey ); 189 if( pKey && pValue ) 190 { 191 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || 192 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) 193 ) 194 { 195 pJobSetup->meDuplexMode = DUPLEX_OFF; 196 } 197 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) 198 { 199 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; 200 } 201 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) 202 { 203 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; 204 } 205 } 206 207 // copy the whole context 208 if( pJobSetup->mpDriverData ) 209 rtl_freeMemory( pJobSetup->mpDriverData ); 210 211 int nBytes; 212 void* pBuffer = NULL; 213 if( rData.getStreamBuffer( pBuffer, nBytes ) ) 214 { 215 pJobSetup->mnDriverDataLen = nBytes; 216 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; 217 } 218 else 219 { 220 pJobSetup->mnDriverDataLen = 0; 221 pJobSetup->mpDriverData = NULL; 222 } 223 } 224 225 static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true ) 226 { 227 bool bSuccess = false; 228 229 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); 230 ByteString aCmdLine( rCommandLine, aEncoding ); 231 ByteString aFilename( rFilename, aEncoding ); 232 233 bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true; 234 235 // setup command line for exec 236 if( ! bPipe ) 237 while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND ) 238 ; 239 240 #if OSL_DEBUG_LEVEL > 1 241 fprintf( stderr, "%s commandline: \"%s\"\n", 242 bPipe ? "piping to" : "executing", 243 aCmdLine.GetBuffer() ); 244 struct stat aStat; 245 if( stat( aFilename.GetBuffer(), &aStat ) ) 246 fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() ); 247 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode ); 248 #endif 249 const char* argv[4]; 250 if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) ) 251 argv[ 0 ] = "/bin/sh"; 252 argv[ 1 ] = "-c"; 253 argv[ 2 ] = aCmdLine.GetBuffer(); 254 argv[ 3 ] = 0; 255 256 bool bHavePipes = false; 257 int pid, fd[2]; 258 259 if( bPipe ) 260 bHavePipes = pipe( fd ) ? false : true; 261 if( ( pid = fork() ) > 0 ) 262 { 263 if( bPipe && bHavePipes ) 264 { 265 close( fd[0] ); 266 char aBuffer[ 2048 ]; 267 FILE* fp = fopen( aFilename.GetBuffer(), "r" ); 268 while( fp && ! feof( fp ) ) 269 { 270 int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp ); 271 if( nBytes ) 272 write( fd[ 1 ], aBuffer, nBytes ); 273 } 274 fclose( fp ); 275 close( fd[ 1 ] ); 276 } 277 int status = 0; 278 waitpid( pid, &status, 0 ); 279 if( ! status ) 280 bSuccess = true; 281 } 282 else if( ! pid ) 283 { 284 if( bPipe && bHavePipes ) 285 { 286 close( fd[1] ); 287 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :) 288 dup2( fd[0], STDIN_FILENO ); 289 } 290 execv( argv[0], const_cast<char**>(argv) ); 291 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() ); 292 _exit( 1 ); 293 } 294 else 295 fprintf( stderr, "failed to fork\n" ); 296 297 // clean up the mess 298 if( bRemoveFile ) 299 unlink( aFilename.GetBuffer() ); 300 301 return bSuccess; 302 } 303 304 static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand ) 305 { 306 std::list< OUString > aFaxNumbers; 307 308 if( ! rFaxNumber.Len() ) 309 { 310 getPaLib(); 311 if( pFaxNrFunction ) 312 { 313 String aNewNr; 314 if( pFaxNrFunction( aNewNr ) ) 315 aFaxNumbers.push_back( OUString( aNewNr ) ); 316 } 317 } 318 else 319 { 320 sal_Int32 nIndex = 0; 321 OUString aFaxes( rFaxNumber ); 322 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") ); 323 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") ); 324 while( nIndex != -1 ) 325 { 326 nIndex = aFaxes.indexOf( aBeginToken, nIndex ); 327 if( nIndex != -1 ) 328 { 329 sal_Int32 nBegin = nIndex + aBeginToken.getLength(); 330 nIndex = aFaxes.indexOf( aEndToken, nIndex ); 331 if( nIndex != -1 ) 332 { 333 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) ); 334 nIndex += aEndToken.getLength(); 335 } 336 } 337 } 338 } 339 340 bool bSuccess = true; 341 if( aFaxNumbers.begin() != aFaxNumbers.end() ) 342 { 343 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess ) 344 { 345 String aCmdLine( rCommand ); 346 String aFaxNumber( aFaxNumbers.front() ); 347 aFaxNumbers.pop_front(); 348 while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND ) 349 ; 350 #if OSL_DEBUG_LEVEL > 1 351 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() ); 352 #endif 353 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false ); 354 } 355 } 356 else 357 bSuccess = false; 358 359 // clean up temp file 360 unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() ); 361 362 return bSuccess; 363 } 364 365 static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine ) 366 { 367 String aCommandLine( rCommandLine ); 368 while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND ) 369 ; 370 return passFileToCommandLine( rFromFile, aCommandLine ); 371 } 372 373 /* 374 * SalInstance 375 */ 376 377 // ----------------------------------------------------------------------- 378 379 SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 380 ImplJobSetup* pJobSetup ) 381 { 382 mbPrinterInit = true; 383 // create and initialize SalInfoPrinter 384 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; 385 386 if( pJobSetup ) 387 { 388 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 389 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) ); 390 pPrinter->m_aJobData = aInfo; 391 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData ); 392 393 if( pJobSetup->mpDriverData ) 394 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); 395 396 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX; 397 pJobSetup->maPrinterName = pQueueInfo->maPrinterName; 398 pJobSetup->maDriver = aInfo.m_aDriverName; 399 copyJobDataToJobSetup( pJobSetup, aInfo ); 400 401 // set/clear backwards compatibility flag 402 bool bStrictSO52Compatibility = false; 403 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 404 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 405 406 if( compat_it != pJobSetup->maValueMap.end() ) 407 { 408 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 409 bStrictSO52Compatibility = true; 410 } 411 pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 412 } 413 414 415 return pPrinter; 416 } 417 418 // ----------------------------------------------------------------------- 419 420 void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 421 { 422 delete pPrinter; 423 } 424 425 // ----------------------------------------------------------------------- 426 427 SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 428 { 429 mbPrinterInit = true; 430 // create and initialize SalPrinter 431 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter ); 432 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; 433 434 return pPrinter; 435 } 436 437 // ----------------------------------------------------------------------- 438 439 void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter ) 440 { 441 delete pPrinter; 442 } 443 444 // ----------------------------------------------------------------------- 445 446 void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 447 { 448 mbPrinterInit = true; 449 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 450 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); 451 if( ! pNoSyncDetection || ! *pNoSyncDetection ) 452 { 453 // #i62663# synchronize possible asynchronouse printer detection now 454 rManager.checkPrintersChanged( true ); 455 } 456 ::std::list< OUString > aPrinters; 457 rManager.listPrinters( aPrinters ); 458 459 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it ) 460 { 461 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) ); 462 // Neuen Eintrag anlegen 463 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 464 pInfo->maPrinterName = *it; 465 pInfo->maDriver = rInfo.m_aDriverName; 466 pInfo->maLocation = rInfo.m_aLocation; 467 pInfo->maComment = rInfo.m_aComment; 468 pInfo->mpSysData = NULL; 469 470 sal_Int32 nIndex = 0; 471 while( nIndex != -1 ) 472 { 473 String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 474 if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL ) 475 { 476 pInfo->maLocation = getPdfDir( rInfo ); 477 break; 478 } 479 } 480 481 pList->Add( pInfo ); 482 } 483 } 484 485 // ----------------------------------------------------------------------- 486 487 void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 488 { 489 delete pInfo; 490 } 491 492 // ----------------------------------------------------------------------- 493 494 void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 495 { 496 mbPrinterInit = true; 497 } 498 499 // ----------------------------------------------------------------------- 500 501 String X11SalInstance::GetDefaultPrinter() 502 { 503 mbPrinterInit = true; 504 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 505 return rManager.getDefaultPrinter(); 506 } 507 508 // ======================================================================= 509 510 PspSalInfoPrinter::PspSalInfoPrinter() 511 { 512 m_pGraphics = NULL; 513 m_bPapersInit = false; 514 } 515 516 // ----------------------------------------------------------------------- 517 518 PspSalInfoPrinter::~PspSalInfoPrinter() 519 { 520 if( m_pGraphics ) 521 { 522 delete m_pGraphics; 523 m_pGraphics = NULL; 524 } 525 } 526 527 // ----------------------------------------------------------------------- 528 529 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) 530 { 531 m_aPaperFormats.clear(); 532 m_bPapersInit = true; 533 534 if( m_aJobData.m_pParser ) 535 { 536 const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 537 if( pKey ) 538 { 539 int nValues = pKey->countValues(); 540 for( int i = 0; i < nValues; i++ ) 541 { 542 const PPDValue* pValue = pKey->getValue( i ); 543 int nWidth = 0, nHeight = 0; 544 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight ); 545 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight )); 546 m_aPaperFormats.push_back( aInfo ); 547 } 548 } 549 } 550 } 551 552 // ----------------------------------------------------------------------- 553 554 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) 555 { 556 return 900; 557 } 558 559 // ----------------------------------------------------------------------- 560 561 SalGraphics* PspSalInfoPrinter::GetGraphics() 562 { 563 // return a valid pointer only once 564 // the reasoning behind this is that we could have different 565 // SalGraphics that can run in multiple threads 566 // (future plans) 567 SalGraphics* pRet = NULL; 568 if( ! m_pGraphics ) 569 { 570 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this ); 571 m_pGraphics->SetLayout( 0 ); 572 pRet = m_pGraphics; 573 } 574 return pRet; 575 } 576 577 // ----------------------------------------------------------------------- 578 579 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics ) 580 { 581 if( pGraphics == m_pGraphics ) 582 { 583 delete pGraphics; 584 m_pGraphics = NULL; 585 } 586 return; 587 } 588 589 // ----------------------------------------------------------------------- 590 591 sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup ) 592 { 593 if( ! pFrame || ! pJobSetup ) 594 return sal_False; 595 596 getPaLib(); 597 598 if( ! pSetupFunction ) 599 return sal_False; 600 601 PrinterInfoManager& rManager = PrinterInfoManager::get(); 602 603 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) ); 604 if ( pJobSetup->mpDriverData ) 605 { 606 SetData( ~0, pJobSetup ); 607 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); 608 } 609 610 if( pSetupFunction( aInfo ) ) 611 { 612 rtl_freeMemory( pJobSetup->mpDriverData ); 613 pJobSetup->mpDriverData = NULL; 614 615 int nBytes; 616 void* pBuffer = NULL; 617 aInfo.getStreamBuffer( pBuffer, nBytes ); 618 pJobSetup->mnDriverDataLen = nBytes; 619 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; 620 621 // copy everything to job setup 622 copyJobDataToJobSetup( pJobSetup, aInfo ); 623 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 624 return sal_True; 625 } 626 return sal_False; 627 } 628 629 // ----------------------------------------------------------------------- 630 631 // This function gets the driver data and puts it into pJobSetup 632 // If pJobSetup->mpDriverData is NOT NULL, then the independend 633 // data should be merged into the driver data 634 // If pJobSetup->mpDriverData IS NULL, then the driver defaults 635 // should be merged into the independent data 636 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup ) 637 { 638 // set/clear backwards compatibility flag 639 bool bStrictSO52Compatibility = false; 640 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 641 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 642 643 if( compat_it != pJobSetup->maValueMap.end() ) 644 { 645 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 646 bStrictSO52Compatibility = true; 647 } 648 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 649 650 if( pJobSetup->mpDriverData ) 651 return SetData( ~0, pJobSetup ); 652 653 copyJobDataToJobSetup( pJobSetup, m_aJobData ); 654 655 return sal_True; 656 } 657 658 // ----------------------------------------------------------------------- 659 660 // This function merges the independ driver data 661 // and sets the new independ data in pJobSetup 662 // Only the data must be changed, where the bit 663 // in nGetDataFlags is set 664 sal_Bool PspSalInfoPrinter::SetData( 665 sal_uLong nSetDataFlags, 666 ImplJobSetup* pJobSetup ) 667 { 668 JobData aData; 669 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 670 671 if( aData.m_pParser ) 672 { 673 const PPDKey* pKey; 674 const PPDValue* pValue; 675 676 // merge papersize if necessary 677 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE ) 678 { 679 int nWidth, nHeight; 680 if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT ) 681 { 682 nWidth = pJobSetup->mnPaperWidth; 683 nHeight = pJobSetup->mnPaperHeight; 684 } 685 else 686 { 687 nWidth = pJobSetup->mnPaperHeight; 688 nHeight = pJobSetup->mnPaperWidth; 689 } 690 String aPaper; 691 692 if( pJobSetup->mePaperFormat == PAPER_USER ) 693 aPaper = aData.m_pParser->matchPaper( 694 TenMuToPt( pJobSetup->mnPaperWidth ), 695 TenMuToPt( pJobSetup->mnPaperHeight ) ); 696 else 697 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1); 698 699 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 700 pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL; 701 702 // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5) 703 // try to find the correct paper anyway using the size 704 if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER ) 705 { 706 PaperInfo aInfo( pJobSetup->mePaperFormat ); 707 aPaper = aData.m_pParser->matchPaper( 708 TenMuToPt( aInfo.getWidth() ), 709 TenMuToPt( aInfo.getHeight() ) ); 710 pValue = pKey->getValueCaseInsensitive( aPaper ); 711 } 712 713 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) ) 714 return sal_False; 715 } 716 717 // merge paperbin if necessary 718 if( nSetDataFlags & SAL_JOBSET_PAPERBIN ) 719 { 720 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 721 if( pKey ) 722 { 723 int nPaperBin = pJobSetup->mnPaperBin; 724 if( nPaperBin >= pKey->countValues() ) 725 pValue = pKey->getDefaultValue(); 726 else 727 pValue = pKey->getValue( pJobSetup->mnPaperBin ); 728 729 // may fail due to constraints; 730 // real paper bin is copied back to jobsetup in that case 731 aData.m_aContext.setValue( pKey, pValue ); 732 } 733 // if printer has no InputSlot key simply ignore this setting 734 // (e.g. SGENPRT has no InputSlot) 735 } 736 737 // merge orientation if necessary 738 if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) 739 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; 740 741 // merge duplex if necessary 742 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE ) 743 { 744 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 745 if( pKey ) 746 { 747 pValue = NULL; 748 switch( pJobSetup->meDuplexMode ) 749 { 750 case DUPLEX_OFF: 751 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); 752 if( pValue == NULL ) 753 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) ); 754 break; 755 case DUPLEX_SHORTEDGE: 756 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) ); 757 break; 758 case DUPLEX_LONGEDGE: 759 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) ); 760 break; 761 case DUPLEX_UNKNOWN: 762 default: 763 pValue = 0; 764 break; 765 } 766 if( ! pValue ) 767 pValue = pKey->getDefaultValue(); 768 aData.m_aContext.setValue( pKey, pValue ); 769 } 770 } 771 772 m_aJobData = aData; 773 copyJobDataToJobSetup( pJobSetup, aData ); 774 return sal_True; 775 } 776 777 return sal_False; 778 } 779 780 // ----------------------------------------------------------------------- 781 782 void PspSalInfoPrinter::GetPageInfo( 783 const ImplJobSetup* pJobSetup, 784 long& rOutWidth, long& rOutHeight, 785 long& rPageOffX, long& rPageOffY, 786 long& rPageWidth, long& rPageHeight ) 787 { 788 if( ! pJobSetup ) 789 return; 790 791 JobData aData; 792 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 793 794 // get the selected page size 795 if( aData.m_pParser ) 796 { 797 798 String aPaper; 799 int width, height; 800 int left = 0, top = 0, right = 0, bottom = 0; 801 int nDPI = aData.m_aContext.getRenderResolution(); 802 803 804 if( aData.m_eOrientation == psp::orientation::Portrait ) 805 { 806 aData.m_aContext.getPageSize( aPaper, width, height ); 807 aData.m_pParser->getMargins( aPaper, left, right, top, bottom ); 808 } 809 else 810 { 811 aData.m_aContext.getPageSize( aPaper, height, width ); 812 aData.m_pParser->getMargins( aPaper, top, bottom, right, left ); 813 } 814 815 rPageWidth = width * nDPI / 72; 816 rPageHeight = height * nDPI / 72; 817 rPageOffX = left * nDPI / 72; 818 rPageOffY = top * nDPI / 72; 819 rOutWidth = ( width - left - right ) * nDPI / 72; 820 rOutHeight = ( height - top - bottom ) * nDPI / 72; 821 } 822 } 823 824 // ----------------------------------------------------------------------- 825 826 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup ) 827 { 828 if( ! pJobSetup ) 829 return 0; 830 831 JobData aData; 832 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 833 834 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 835 return pKey ? pKey->countValues() : 0; 836 } 837 838 // ----------------------------------------------------------------------- 839 840 String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin ) 841 { 842 JobData aData; 843 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 844 845 String aRet; 846 if( aData.m_pParser ) 847 { 848 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 849 if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() ) 850 aRet = aData.m_pParser->getDefaultInputSlot(); 851 else 852 { 853 const PPDValue* pValue = pKey->getValue( nPaperBin ); 854 if( pValue ) 855 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption ); 856 } 857 } 858 859 return aRet; 860 } 861 862 // ----------------------------------------------------------------------- 863 864 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType ) 865 { 866 switch( nType ) 867 { 868 case PRINTER_CAPABILITIES_SUPPORTDIALOG: 869 return 1; 870 case PRINTER_CAPABILITIES_COPIES: 871 return 0xffff; 872 case PRINTER_CAPABILITIES_COLLATECOPIES: 873 { 874 // see if the PPD contains a value to set Collate to True 875 JobData aData; 876 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 877 878 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL; 879 const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL; 880 881 // PPDs don't mention the number of possible collated copies. 882 // so let's guess as many as we want ? 883 return pVal ? 0xffff : 0; 884 } 885 case PRINTER_CAPABILITIES_SETORIENTATION: 886 return 1; 887 case PRINTER_CAPABILITIES_SETDUPLEX: 888 return 1; 889 case PRINTER_CAPABILITIES_SETPAPERBIN: 890 return 1; 891 case PRINTER_CAPABILITIES_SETPAPERSIZE: 892 return 1; 893 case PRINTER_CAPABILITIES_SETPAPER: 894 return 0; 895 case PRINTER_CAPABILITIES_FAX: 896 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0; 897 case PRINTER_CAPABILITIES_PDF: 898 if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) ) 899 return 1; 900 else 901 { 902 // see if the PPD contains a value to set Collate to True 903 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ); 904 if( pJobSetup->mpDriverData ) 905 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 906 return aData.m_nPDFDevice > 0 ? 1 : 0; 907 } 908 case PRINTER_CAPABILITIES_EXTERNALDIALOG: 909 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0; 910 case PRINTER_CAPABILITIES_USEPULLMODEL: 911 { 912 // see if the PPD contains a value to set Collate to True 913 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ); 914 if( pJobSetup->mpDriverData ) 915 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 916 return aData.m_nPDFDevice > 0 ? 1 : 0; 917 } 918 default: break; 919 }; 920 return 0; 921 } 922 923 // ======================================================================= 924 925 /* 926 * SalPrinter 927 */ 928 929 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter ) 930 : m_bFax( false ), 931 m_bPdf( false ), 932 m_bSwallowFaxNo( false ), 933 m_bIsPDFWriterJob( false ), 934 m_pGraphics( NULL ), 935 m_nCopies( 1 ), 936 m_bCollate( false ), 937 m_pInfoPrinter( pInfoPrinter ) 938 { 939 } 940 941 // ----------------------------------------------------------------------- 942 943 PspSalPrinter::~PspSalPrinter() 944 { 945 } 946 947 // ----------------------------------------------------------------------- 948 949 static String getTmpName() 950 { 951 rtl::OUString aTmp, aSys; 952 osl_createTempFile( NULL, NULL, &aTmp.pData ); 953 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData ); 954 955 return aSys; 956 } 957 958 sal_Bool PspSalPrinter::StartJob( 959 const XubString* pFileName, 960 const XubString& rJobName, 961 const XubString& rAppName, 962 sal_uLong nCopies, 963 bool bCollate, 964 bool bDirect, 965 ImplJobSetup* pJobSetup ) 966 { 967 vcl_sal::PrinterUpdate::jobStarted(); 968 969 m_bFax = false; 970 m_bPdf = false; 971 m_aFileName = pFileName ? *pFileName : String(); 972 m_aTmpFile = String(); 973 m_nCopies = nCopies; 974 m_bCollate = bCollate; 975 976 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 977 if( m_nCopies > 1 ) 978 { 979 // in case user did not do anything (m_nCopies=1) 980 // take the default from jobsetup 981 m_aJobData.m_nCopies = m_nCopies; 982 m_aJobData.setCollate( bCollate ); 983 } 984 985 // check wether this printer is configured as fax 986 int nMode = 0; 987 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 988 sal_Int32 nIndex = 0; 989 while( nIndex != -1 ) 990 { 991 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 992 if( ! aToken.compareToAscii( "fax", 3 ) ) 993 { 994 m_bFax = true; 995 m_aTmpFile = getTmpName(); 996 nMode = S_IRUSR | S_IWUSR; 997 998 ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it; 999 it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) ); 1000 if( it != pJobSetup->maValueMap.end() ) 1001 m_aFaxNr = it->second; 1002 1003 sal_Int32 nPos = 0; 1004 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false; 1005 1006 break; 1007 } 1008 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 1009 { 1010 m_bPdf = true; 1011 m_aTmpFile = getTmpName(); 1012 nMode = S_IRUSR | S_IWUSR; 1013 1014 if( ! m_aFileName.Len() ) 1015 { 1016 m_aFileName = getPdfDir( rInfo ); 1017 m_aFileName.Append( '/' ); 1018 m_aFileName.Append( rJobName ); 1019 m_aFileName.AppendAscii( ".pdf" ); 1020 } 1021 break; 1022 } 1023 } 1024 m_aPrinterGfx.Init( m_aJobData ); 1025 1026 // set/clear backwards compatibility flag 1027 bool bStrictSO52Compatibility = false; 1028 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 1029 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 1030 1031 if( compat_it != pJobSetup->maValueMap.end() ) 1032 { 1033 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 1034 bStrictSO52Compatibility = true; 1035 } 1036 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 1037 1038 return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False; 1039 } 1040 1041 // ----------------------------------------------------------------------- 1042 1043 sal_Bool PspSalPrinter::EndJob() 1044 { 1045 sal_Bool bSuccess = sal_False; 1046 if( m_bIsPDFWriterJob ) 1047 bSuccess = sal_True; 1048 else 1049 { 1050 bSuccess = m_aPrintJob.EndJob(); 1051 1052 if( bSuccess ) 1053 { 1054 // check for fax 1055 if( m_bFax ) 1056 { 1057 1058 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 1059 // sendAFax removes the file after use 1060 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand ); 1061 } 1062 else if( m_bPdf ) 1063 { 1064 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 1065 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand ); 1066 } 1067 } 1068 } 1069 vcl_sal::PrinterUpdate::jobEnded(); 1070 return bSuccess; 1071 } 1072 1073 // ----------------------------------------------------------------------- 1074 1075 sal_Bool PspSalPrinter::AbortJob() 1076 { 1077 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False; 1078 vcl_sal::PrinterUpdate::jobEnded(); 1079 return bAbort; 1080 } 1081 1082 // ----------------------------------------------------------------------- 1083 1084 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool ) 1085 { 1086 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 1087 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter ); 1088 m_pGraphics->SetLayout( 0 ); 1089 if( m_nCopies > 1 ) 1090 { 1091 // in case user did not do anything (m_nCopies=1) 1092 // take the default from jobsetup 1093 m_aJobData.m_nCopies = m_nCopies; 1094 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate ); 1095 } 1096 1097 m_aPrintJob.StartPage( m_aJobData ); 1098 m_aPrinterGfx.Init( m_aPrintJob ); 1099 1100 return m_pGraphics; 1101 } 1102 1103 // ----------------------------------------------------------------------- 1104 1105 sal_Bool PspSalPrinter::EndPage() 1106 { 1107 sal_Bool bResult = m_aPrintJob.EndPage(); 1108 m_aPrinterGfx.Clear(); 1109 return bResult ? sal_True : sal_False; 1110 } 1111 1112 // ----------------------------------------------------------------------- 1113 1114 sal_uLong PspSalPrinter::GetErrorCode() 1115 { 1116 return 0; 1117 } 1118 1119 // ----------------------------------------------------------------------- 1120 1121 struct PDFNewJobParameters 1122 { 1123 Size maPageSize; 1124 sal_uInt16 mnPaperBin; 1125 1126 PDFNewJobParameters( const Size& i_rSize = Size(), 1127 sal_uInt16 i_nPaperBin = 0xffff ) 1128 : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {} 1129 1130 bool operator!=(const PDFNewJobParameters& rComp ) const 1131 { 1132 Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() ); 1133 return 1134 (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize) 1135 || mnPaperBin != rComp.mnPaperBin 1136 ; 1137 } 1138 1139 bool operator==(const PDFNewJobParameters& rComp) const 1140 { 1141 return ! this->operator!=(rComp); 1142 } 1143 }; 1144 1145 struct PDFPrintFile 1146 { 1147 rtl::OUString maTmpURL; 1148 PDFNewJobParameters maParameters; 1149 1150 PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters ) 1151 : maTmpURL( i_rURL ) 1152 , maParameters( i_rNewParameters ) {} 1153 }; 1154 1155 sal_Bool PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobName, const String& i_rAppName, 1156 ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController ) 1157 { 1158 OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" ); 1159 // mark for endjob 1160 m_bIsPDFWriterJob = true; 1161 // reset IsLastPage 1162 i_rController.setLastPage( sal_False ); 1163 1164 // update job data 1165 if( i_pSetupData ) 1166 JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData ); 1167 1168 OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 ); 1169 m_aJobData.m_nPDFDevice = 1; 1170 1171 // possibly create one job for collated output 1172 sal_Bool bSinglePrintJobs = sal_False; 1173 beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) ); 1174 if( pSingleValue ) 1175 { 1176 pSingleValue->Value >>= bSinglePrintJobs; 1177 } 1178 1179 int nCopies = i_rController.getPrinter()->GetCopyCount(); 1180 bool bCollate = i_rController.getPrinter()->IsCollateCopy(); 1181 1182 // notify start of real print job 1183 i_rController.jobStarted(); 1184 1185 // setup PDFWriter context 1186 vcl::PDFWriter::PDFWriterContext aContext; 1187 aContext.Version = vcl::PDFWriter::PDF_1_4; 1188 aContext.Tagged = false; 1189 aContext.EmbedStandardFonts = true; 1190 aContext.DocumentLocale = Application::GetSettings().GetLocale(); 1191 aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales() 1192 ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor; 1193 1194 // prepare doc info 1195 aContext.DocumentInfo.Title = i_rJobName; 1196 aContext.DocumentInfo.Creator = i_rAppName; 1197 aContext.DocumentInfo.Producer = i_rAppName; 1198 1199 // define how we handle metafiles in PDFWriter 1200 vcl::PDFWriter::PlayMetafileContext aMtfContext; 1201 aMtfContext.m_bOnlyLosslessCompression = true; 1202 1203 boost::shared_ptr<vcl::PDFWriter> pWriter; 1204 std::vector< PDFPrintFile > aPDFFiles; 1205 boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() ); 1206 int nAllPages = i_rController.getFilteredPageCount(); 1207 i_rController.createProgressDialog(); 1208 bool bAborted = false; 1209 PDFNewJobParameters aLastParm; 1210 1211 aContext.DPIx = pPrinter->ImplGetDPIX(); 1212 aContext.DPIy = pPrinter->ImplGetDPIY(); 1213 for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ ) 1214 { 1215 if( nPage == nAllPages-1 ) 1216 i_rController.setLastPage( sal_True ); 1217 1218 // get the page's metafile 1219 GDIMetaFile aPageFile; 1220 vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile ); 1221 if( i_rController.isProgressCanceled() ) 1222 { 1223 bAborted = true; 1224 if( nPage != nAllPages-1 ) 1225 { 1226 i_rController.createProgressDialog(); 1227 i_rController.setLastPage( sal_True ); 1228 i_rController.getFilteredPageFile( nPage, aPageFile ); 1229 } 1230 } 1231 else 1232 { 1233 pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); 1234 pPrinter->SetPaperSizeUser( aPageSize.aSize, true ); 1235 PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() ); 1236 1237 // create PDF writer on demand 1238 // either on first page 1239 // or on paper format change - cups does not support multiple paper formats per job (yet?) 1240 // so we need to start a new job to get a new paper format from the printer 1241 // orientation switches (that is switch of height and width) is handled transparently by CUPS 1242 if( ! pWriter || 1243 (aNewParm != aLastParm && ! i_pFileName ) ) 1244 { 1245 if( pWriter ) 1246 { 1247 pWriter->Emit(); 1248 } 1249 // produce PDF file 1250 OUString aPDFUrl; 1251 if( i_pFileName ) 1252 aPDFUrl = *i_pFileName; 1253 else 1254 osl_createTempFile( NULL, NULL, &aPDFUrl.pData ); 1255 // normalize to file URL 1256 if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 ) 1257 { 1258 // this is not a file URL, but it should 1259 // form it into a osl friendly file URL 1260 rtl::OUString aTmp; 1261 osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData ); 1262 aPDFUrl = aTmp; 1263 } 1264 // save current file and paper format 1265 aLastParm = aNewParm; 1266 aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) ); 1267 // update context 1268 aContext.URL = aPDFUrl; 1269 1270 // create and initialize PDFWriter 1271 #if defined __SUNPRO_CC 1272 #pragma disable_warn 1273 #endif 1274 pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) ); 1275 #if defined __SUNPRO_CC 1276 #pragma enable_warn 1277 #endif 1278 } 1279 1280 pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ), 1281 TenMuToPt( aNewParm.maPageSize.Height() ), 1282 vcl::PDFWriter::Portrait ); 1283 1284 pWriter->PlayMetafile( aPageFile, aMtfContext, NULL ); 1285 } 1286 } 1287 1288 // emit the last file 1289 if( pWriter ) 1290 pWriter->Emit(); 1291 1292 // handle collate, copy count and multiple jobs correctly 1293 int nOuterJobs = 1; 1294 if( bSinglePrintJobs ) 1295 { 1296 nOuterJobs = nCopies; 1297 m_aJobData.m_nCopies = 1; 1298 } 1299 else 1300 { 1301 if( bCollate ) 1302 { 1303 if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) ) 1304 { 1305 m_aJobData.setCollate( true ); 1306 m_aJobData.m_nCopies = nCopies; 1307 } 1308 else 1309 { 1310 nOuterJobs = nCopies; 1311 m_aJobData.m_nCopies = 1; 1312 } 1313 } 1314 else 1315 { 1316 m_aJobData.setCollate( false ); 1317 m_aJobData.m_nCopies = nCopies; 1318 } 1319 } 1320 1321 // spool files 1322 if( ! i_pFileName && ! bAborted ) 1323 { 1324 bool bFirstJob = true; 1325 for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ ) 1326 { 1327 for( size_t i = 0; i < aPDFFiles.size(); i++ ) 1328 { 1329 oslFileHandle pFile = NULL; 1330 osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read ); 1331 if( pFile ) 1332 { 1333 osl_setFilePos( pFile, osl_Pos_Absolut, 0 ); 1334 std::vector< char > buffer( 0x10000, 0 ); 1335 // update job data with current page size 1336 Size aPageSize( aPDFFiles[i].maParameters.maPageSize ); 1337 m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) ); 1338 // update job data with current paperbin 1339 m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin ); 1340 1341 // spool current file 1342 FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() ); 1343 if( fp ) 1344 { 1345 sal_uInt64 nBytesRead = 0; 1346 do 1347 { 1348 osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead ); 1349 if( nBytesRead > 0 ) 1350 fwrite( &buffer[0], 1, nBytesRead, fp ); 1351 } while( nBytesRead == buffer.size() ); 1352 rtl::OUStringBuffer aBuf( i_rJobName.Len() + 8 ); 1353 aBuf.append( i_rJobName ); 1354 if( i > 0 || nCurJob > 0 ) 1355 { 1356 aBuf.append( sal_Unicode(' ') ); 1357 aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) ); 1358 } 1359 PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob ); 1360 bFirstJob = false; 1361 } 1362 } 1363 osl_closeFile( pFile ); 1364 } 1365 } 1366 } 1367 1368 // job has been spooled 1369 i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED ); 1370 1371 // clean up the temporary PDF files 1372 if( ! i_pFileName || bAborted ) 1373 { 1374 for( size_t i = 0; i < aPDFFiles.size(); i++ ) 1375 { 1376 osl_removeFile( aPDFFiles[i].maTmpURL.pData ); 1377 OSL_TRACE( "removed print PDF file %s\n", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1378 } 1379 } 1380 1381 return sal_True; 1382 } 1383 1384 1385 1386 /* 1387 * vcl::PrinterUpdate 1388 */ 1389 1390 Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL; 1391 int vcl_sal::PrinterUpdate::nActiveJobs = 0; 1392 1393 void vcl_sal::PrinterUpdate::doUpdate() 1394 { 1395 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() ); 1396 if( rManager.checkPrintersChanged( false ) ) 1397 { 1398 SalDisplay* pDisp = GetX11SalData()->GetDisplay(); 1399 const std::list< SalFrame* >& rList = pDisp->getFrames(); 1400 for( std::list< SalFrame* >::const_iterator it = rList.begin(); 1401 it != rList.end(); ++it ) 1402 pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED ); 1403 } 1404 } 1405 1406 // ----------------------------------------------------------------------- 1407 1408 IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG ) 1409 { 1410 if( nActiveJobs < 1 ) 1411 { 1412 doUpdate(); 1413 delete pPrinterUpdateTimer; 1414 pPrinterUpdateTimer = NULL; 1415 } 1416 else 1417 pPrinterUpdateTimer->Start(); 1418 1419 return 0; 1420 } 1421 1422 // ----------------------------------------------------------------------- 1423 1424 void vcl_sal::PrinterUpdate::update() 1425 { 1426 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) 1427 return; 1428 1429 if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() ) 1430 { 1431 // #i45389# start background printer detection 1432 psp::PrinterInfoManager::get(); 1433 return; 1434 } 1435 1436 if( nActiveJobs < 1 ) 1437 doUpdate(); 1438 else if( ! pPrinterUpdateTimer ) 1439 { 1440 pPrinterUpdateTimer = new Timer(); 1441 pPrinterUpdateTimer->SetTimeout( 500 ); 1442 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) ); 1443 pPrinterUpdateTimer->Start(); 1444 } 1445 } 1446 1447 // ----------------------------------------------------------------------- 1448 1449 void vcl_sal::PrinterUpdate::jobEnded() 1450 { 1451 nActiveJobs--; 1452 if( nActiveJobs < 1 ) 1453 { 1454 if( pPrinterUpdateTimer ) 1455 { 1456 pPrinterUpdateTimer->Stop(); 1457 delete pPrinterUpdateTimer; 1458 pPrinterUpdateTimer = NULL; 1459 doUpdate(); 1460 } 1461 } 1462 } 1463