Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / vcl / generic / print / genprnpsp.cxx
blob6800e01ed506427ff02e21ba3019c1450a77cab3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**
22 this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
23 and some printer relevant methods of SalInstance and SalGraphicsData )
25 as aunderlying library the printer features of psprint are used.
27 The query methods of a SalInfoPrinter are implemented by querying psprint
29 The job methods of a SalPrinter are implemented by calling psprint
30 printer job functions.
33 // For spawning PDF and FAX generation
34 #if defined( UNX )
35 # include <unistd.h>
36 # include <sys/wait.h>
37 # include <sys/stat.h>
38 #endif
40 #include "rtl/ustring.hxx"
42 #include "osl/module.h"
44 #include "vcl/svapp.hxx"
45 #include "vcl/print.hxx"
46 #include "vcl/pdfwriter.hxx"
47 #include "vcl/printerinfomanager.hxx"
49 #include "saldatabasic.hxx"
50 #include "generic/genprn.h"
51 #include "generic/geninst.h"
52 #include "generic/genpspgraphics.h"
54 #include "jobset.h"
55 #include "print.h"
56 #include "salptype.hxx"
58 #include <com/sun/star/beans/PropertyValue.hpp>
60 using namespace psp;
61 using namespace com::sun::star;
63 using ::rtl::OUString;
64 using ::rtl::OUStringHash;
65 using ::rtl::OUStringToOString;
68 * static helpers
71 #if defined( UNX ) && !( defined( QUARTZ ) || defined( IOS ) || defined( ANDROID ) )
72 static oslModule driverLib = NULL;
73 #endif
74 extern "C"
76 typedef int(*setupFunction)(PrinterInfo&);
77 static setupFunction pSetupFunction = NULL;
78 typedef int(*faxFunction)(OUString&);
79 static faxFunction pFaxNrFunction = NULL;
82 static rtl::OUString getPdfDir( const PrinterInfo& rInfo )
84 rtl::OUString aDir;
85 sal_Int32 nIndex = 0;
86 while( nIndex != -1 )
88 rtl::OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
89 if( ! aToken.compareToAscii( "pdf=", 4 ) )
91 sal_Int32 nPos = 0;
92 aDir = aToken.getToken( 1, '=', nPos );
93 if( aDir.isEmpty() && getenv( "HOME" ) )
94 aDir = rtl::OUString( getenv( "HOME" ), strlen( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
95 break;
98 return aDir;
101 static void getPaLib()
103 #if defined( UNX ) && !( defined( QUARTZ ) || defined( IOS ) || defined( ANDROID ) )
104 if( ! driverLib )
106 OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) );
107 driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT );
108 if ( !driverLib )
110 return;
113 pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
114 if ( !pSetupFunction )
115 fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
117 pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
118 if ( !pFaxNrFunction )
119 fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
121 #endif
124 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
126 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
128 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
130 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
132 // copy page size
133 OUString aPaper;
134 int width, height;
136 rData.m_aContext.getPageSize( aPaper, width, height );
137 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
139 pJobSetup->mnPaperWidth = 0;
140 pJobSetup->mnPaperHeight = 0;
141 if( pJobSetup->mePaperFormat == PAPER_USER )
143 // transform to 100dth mm
144 width = PtTo10Mu( width );
145 height = PtTo10Mu( height );
147 if( rData.m_eOrientation == psp::orientation::Portrait )
149 pJobSetup->mnPaperWidth = width;
150 pJobSetup->mnPaperHeight= height;
152 else
154 pJobSetup->mnPaperWidth = height;
155 pJobSetup->mnPaperHeight= width;
159 // copy input slot
160 const PPDKey* pKey = NULL;
161 const PPDValue* pValue = NULL;
163 pJobSetup->mnPaperBin = 0;
164 if( rData.m_pParser )
165 pKey = rData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
166 if( pKey )
167 pValue = rData.m_aContext.getValue( pKey );
168 if( pKey && pValue )
170 for( pJobSetup->mnPaperBin = 0;
171 pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
172 pJobSetup->mnPaperBin < pKey->countValues();
173 pJobSetup->mnPaperBin++ )
175 if( pJobSetup->mnPaperBin >= pKey->countValues() )
176 pJobSetup->mnPaperBin = 0;
179 // copy duplex
180 pKey = NULL;
181 pValue = NULL;
183 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
184 if( rData.m_pParser )
185 pKey = rData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
186 if( pKey )
187 pValue = rData.m_aContext.getValue( pKey );
188 if( pKey && pValue )
190 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
191 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
194 pJobSetup->meDuplexMode = DUPLEX_OFF;
196 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
198 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
200 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
202 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
206 // copy the whole context
207 if( pJobSetup->mpDriverData )
208 rtl_freeMemory( pJobSetup->mpDriverData );
210 int nBytes;
211 void* pBuffer = NULL;
212 if( rData.getStreamBuffer( pBuffer, nBytes ) )
214 pJobSetup->mnDriverDataLen = nBytes;
215 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
217 else
219 pJobSetup->mnDriverDataLen = 0;
220 pJobSetup->mpDriverData = NULL;
224 // Needs a cleaner abstraction ...
225 #if defined( UNX )
226 static bool passFileToCommandLine( const OUString& rFilename, const OUString& rCommandLine, bool bRemoveFile = true )
228 bool bSuccess = false;
230 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
231 rtl::OString aCmdLine(rtl::OUStringToOString(rCommandLine, aEncoding));
232 rtl::OString aFilename(rtl::OUStringToOString(rFilename, aEncoding));
234 bool bPipe = aCmdLine.indexOf( "(TMP)" ) != -1 ? false : true;
236 // setup command line for exec
237 if( ! bPipe )
238 aCmdLine = aCmdLine.replaceAll(rtl::OString("(TMP)"), aFilename);
240 #if OSL_DEBUG_LEVEL > 1
241 fprintf( stderr, "%s commandline: \"%s\"\n",
242 bPipe ? "piping to" : "executing",
243 aCmdLine.getStr() );
244 struct stat aStat;
245 if( stat( aFilename.getStr(), &aStat ) )
246 fprintf( stderr, "stat( %s ) failed\n", aFilename.getStr() );
247 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.getStr(), (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.getStr();
254 argv[ 3 ] = 0;
256 bool bHavePipes = false;
257 int pid, fd[2];
259 if( bPipe )
260 bHavePipes = pipe( fd ) ? false : true;
261 if( ( pid = fork() ) > 0 )
263 if( bPipe && bHavePipes )
265 close( fd[0] );
266 char aBuffer[ 2048 ];
267 FILE* fp = fopen( aFilename.getStr(), "r" );
268 while (fp && !feof(fp))
270 size_t nBytesRead = fread(aBuffer, 1, sizeof( aBuffer ), fp);
271 if (nBytesRead )
273 size_t nBytesWritten = write(fd[1], aBuffer, nBytesRead);
274 OSL_ENSURE(nBytesWritten == nBytesRead, "short write");
275 if (nBytesWritten != nBytesRead)
276 break;
279 fclose( fp );
280 close( fd[ 1 ] );
282 int status = 0;
283 waitpid( pid, &status, 0 );
284 if( ! status )
285 bSuccess = true;
287 else if( ! pid )
289 if( bPipe && bHavePipes )
291 close( fd[1] );
292 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
293 dup2( fd[0], STDIN_FILENO );
295 execv( argv[0], const_cast<char**>(argv) );
296 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.getStr() );
297 _exit( 1 );
299 else
300 fprintf( stderr, "failed to fork\n" );
302 // clean up the mess
303 if( bRemoveFile )
304 unlink( aFilename.getStr() );
306 return bSuccess;
308 #endif
310 static bool sendAFax( const OUString& rFaxNumber, const OUString& rFileName, const OUString& rCommand )
312 #if defined( UNX )
313 std::list< OUString > aFaxNumbers;
315 if( rFaxNumber.isEmpty() )
317 getPaLib();
318 if( pFaxNrFunction )
320 OUString aNewNr;
321 if( pFaxNrFunction( aNewNr ) )
322 aFaxNumbers.push_back( aNewNr );
325 else
327 sal_Int32 nIndex = 0;
328 OUString aFaxes( rFaxNumber );
329 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
330 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
331 while( nIndex != -1 )
333 nIndex = aFaxes.indexOf( aBeginToken, nIndex );
334 if( nIndex != -1 )
336 sal_Int32 nBegin = nIndex + aBeginToken.getLength();
337 nIndex = aFaxes.indexOf( aEndToken, nIndex );
338 if( nIndex != -1 )
340 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
341 nIndex += aEndToken.getLength();
347 bool bSuccess = true;
348 if( aFaxNumbers.begin() != aFaxNumbers.end() )
350 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
352 OUString aFaxNumber( aFaxNumbers.front() );
353 aFaxNumbers.pop_front();
354 OUString aCmdLine(
355 rCommand.replaceAll("(PHONE)", aFaxNumber));
356 #if OSL_DEBUG_LEVEL > 1
357 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
358 #endif
359 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
362 else
363 bSuccess = false;
365 // clean up temp file
366 unlink(rtl::OUStringToOString(rFileName, osl_getThreadTextEncoding()).getStr());
368 return bSuccess;
369 #else
370 (void)rFaxNumber; (void)rFileName; (void)rCommand;
371 return false;
372 #endif
375 static bool createPdf( const OUString& rToFile, const OUString& rFromFile, const OUString& rCommandLine )
377 #if defined( UNX )
378 OUString aCommandLine(
379 rCommandLine.replaceAll("(OUTFILE)", rToFile));
381 return passFileToCommandLine( rFromFile, aCommandLine );
382 #else
383 (void)rToFile; (void)rFromFile; (void)rCommandLine;
384 return false;
385 #endif
389 * SalInstance
392 void SalGenericInstance::configurePspInfoPrinter(PspSalInfoPrinter *pPrinter,
393 SalPrinterQueueInfo* pQueueInfo, ImplJobSetup* pJobSetup)
395 if( pJobSetup )
397 PrinterInfoManager& rManager( PrinterInfoManager::get() );
398 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
399 pPrinter->m_aJobData = aInfo;
400 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
402 if( pJobSetup->mpDriverData )
403 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
405 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
406 pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
407 pJobSetup->maDriver = aInfo.m_aDriverName;
408 copyJobDataToJobSetup( pJobSetup, aInfo );
412 SalInfoPrinter* SalGenericInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
413 ImplJobSetup* pJobSetup )
415 mbPrinterInit = true;
416 // create and initialize SalInfoPrinter
417 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter();
418 configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup);
419 return pPrinter;
422 void SalGenericInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
424 delete pPrinter;
427 SalPrinter* SalGenericInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
429 mbPrinterInit = true;
430 // create and initialize SalPrinter
431 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
432 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
434 return pPrinter;
437 void SalGenericInstance::DestroyPrinter( SalPrinter* pPrinter )
439 delete pPrinter;
442 void SalGenericInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
444 mbPrinterInit = true;
445 PrinterInfoManager& rManager( PrinterInfoManager::get() );
446 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
447 if( ! pNoSyncDetection || ! *pNoSyncDetection )
449 // #i62663# synchronize possible asynchronouse printer detection now
450 rManager.checkPrintersChanged( true );
452 ::std::list< OUString > aPrinters;
453 rManager.listPrinters( aPrinters );
455 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
457 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
458 // Neuen Eintrag anlegen
459 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
460 pInfo->maPrinterName = *it;
461 pInfo->maDriver = rInfo.m_aDriverName;
462 pInfo->maLocation = rInfo.m_aLocation;
463 pInfo->maComment = rInfo.m_aComment;
464 pInfo->mpSysData = NULL;
466 sal_Int32 nIndex = 0;
467 while( nIndex != -1 )
469 rtl::OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
470 if( aToken.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("pdf=") ) )
472 pInfo->maLocation = getPdfDir( rInfo );
473 break;
477 pList->Add( pInfo );
481 void SalGenericInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
483 delete pInfo;
486 void SalGenericInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
488 mbPrinterInit = true;
491 rtl::OUString SalGenericInstance::GetDefaultPrinter()
493 mbPrinterInit = true;
494 PrinterInfoManager& rManager( PrinterInfoManager::get() );
495 return rManager.getDefaultPrinter();
498 PspSalInfoPrinter::PspSalInfoPrinter()
499 : m_pGraphics( NULL )
503 PspSalInfoPrinter::~PspSalInfoPrinter()
505 if( m_pGraphics )
507 delete m_pGraphics;
508 m_pGraphics = NULL;
512 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
514 m_aPaperFormats.clear();
515 m_bPapersInit = true;
517 if( m_aJobData.m_pParser )
519 const PPDKey* pKey = m_aJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
520 if( pKey )
522 int nValues = pKey->countValues();
523 for( int i = 0; i < nValues; i++ )
525 const PPDValue* pValue = pKey->getValue( i );
526 int nWidth = 0, nHeight = 0;
527 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
528 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
529 m_aPaperFormats.push_back( aInfo );
535 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
537 return 900;
540 SalGraphics* PspSalInfoPrinter::GetGraphics()
542 // return a valid pointer only once
543 // the reasoning behind this is that we could have different
544 // SalGraphics that can run in multiple threads
545 // (future plans)
546 SalGraphics* pRet = NULL;
547 if( ! m_pGraphics )
549 m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
550 m_pGraphics->Init( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
551 pRet = m_pGraphics;
553 return pRet;
556 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
558 if( pGraphics == m_pGraphics )
560 delete pGraphics;
561 m_pGraphics = NULL;
563 return;
566 sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
568 if( ! pFrame || ! pJobSetup )
569 return sal_False;
571 getPaLib();
573 if( ! pSetupFunction )
574 return sal_False;
576 PrinterInfoManager& rManager = PrinterInfoManager::get();
578 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
579 if ( pJobSetup->mpDriverData )
581 SetData( ~0, pJobSetup );
582 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
585 if( pSetupFunction( aInfo ) )
587 aInfo.resolveDefaultBackend();
588 rtl_freeMemory( pJobSetup->mpDriverData );
589 pJobSetup->mpDriverData = NULL;
591 int nBytes;
592 void* pBuffer = NULL;
593 aInfo.getStreamBuffer( pBuffer, nBytes );
594 pJobSetup->mnDriverDataLen = nBytes;
595 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
597 // copy everything to job setup
598 copyJobDataToJobSetup( pJobSetup, aInfo );
599 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
600 return sal_True;
602 return sal_False;
605 // This function gets the driver data and puts it into pJobSetup
606 // If pJobSetup->mpDriverData is NOT NULL, then the independend
607 // data should be merged into the driver data
608 // If pJobSetup->mpDriverData IS NULL, then the driver defaults
609 // should be merged into the independent data
610 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
612 if( pJobSetup->mpDriverData )
613 return SetData( ~0, pJobSetup );
615 copyJobDataToJobSetup( pJobSetup, m_aJobData );
617 return sal_True;
620 // This function merges the independ driver data
621 // and sets the new independ data in pJobSetup
622 // Only the data must be changed, where the bit
623 // in nGetDataFlags is set
624 sal_Bool PspSalInfoPrinter::SetData(
625 sal_uLong nSetDataFlags,
626 ImplJobSetup* pJobSetup )
628 JobData aData;
629 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
631 if( aData.m_pParser )
633 const PPDKey* pKey;
634 const PPDValue* pValue;
636 // merge papersize if necessary
637 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
639 OUString aPaper;
641 if( pJobSetup->mePaperFormat == PAPER_USER )
642 aPaper = aData.m_pParser->matchPaper(
643 TenMuToPt( pJobSetup->mnPaperWidth ),
644 TenMuToPt( pJobSetup->mnPaperHeight ) );
645 else
646 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
648 pKey = aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
649 pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
651 // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
652 // try to find the correct paper anyway using the size
653 if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
655 PaperInfo aInfo( pJobSetup->mePaperFormat );
656 aPaper = aData.m_pParser->matchPaper(
657 TenMuToPt( aInfo.getWidth() ),
658 TenMuToPt( aInfo.getHeight() ) );
659 pValue = pKey->getValueCaseInsensitive( aPaper );
662 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
663 return sal_False;
666 // merge paperbin if necessary
667 if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
669 pKey = aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
670 if( pKey )
672 int nPaperBin = pJobSetup->mnPaperBin;
673 if( nPaperBin >= pKey->countValues() )
674 pValue = pKey->getDefaultValue();
675 else
676 pValue = pKey->getValue( pJobSetup->mnPaperBin );
678 // may fail due to constraints;
679 // real paper bin is copied back to jobsetup in that case
680 aData.m_aContext.setValue( pKey, pValue );
682 // if printer has no InputSlot key simply ignore this setting
683 // (e.g. SGENPRT has no InputSlot)
686 // merge orientation if necessary
687 if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
688 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
690 // merge duplex if necessary
691 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
693 pKey = aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
694 if( pKey )
696 pValue = NULL;
697 switch( pJobSetup->meDuplexMode )
699 case DUPLEX_OFF:
700 pValue = pKey->getValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
701 if( pValue == NULL )
702 pValue = pKey->getValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
703 break;
704 case DUPLEX_SHORTEDGE:
705 pValue = pKey->getValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
706 break;
707 case DUPLEX_LONGEDGE:
708 pValue = pKey->getValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
709 break;
710 case DUPLEX_UNKNOWN:
711 default:
712 pValue = 0;
713 break;
715 if( ! pValue )
716 pValue = pKey->getDefaultValue();
717 aData.m_aContext.setValue( pKey, pValue );
721 m_aJobData = aData;
722 copyJobDataToJobSetup( pJobSetup, aData );
723 return sal_True;
726 return sal_False;
729 void PspSalInfoPrinter::GetPageInfo(
730 const ImplJobSetup* pJobSetup,
731 long& rOutWidth, long& rOutHeight,
732 long& rPageOffX, long& rPageOffY,
733 long& rPageWidth, long& rPageHeight )
735 if( ! pJobSetup )
736 return;
738 JobData aData;
739 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
741 // get the selected page size
742 if( aData.m_pParser )
745 OUString aPaper;
746 int width, height;
747 int left = 0, top = 0, right = 0, bottom = 0;
748 int nDPI = aData.m_aContext.getRenderResolution();
751 if( aData.m_eOrientation == psp::orientation::Portrait )
753 aData.m_aContext.getPageSize( aPaper, width, height );
754 aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
756 else
758 aData.m_aContext.getPageSize( aPaper, height, width );
759 aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
762 rPageWidth = width * nDPI / 72;
763 rPageHeight = height * nDPI / 72;
764 rPageOffX = left * nDPI / 72;
765 rPageOffY = top * nDPI / 72;
766 rOutWidth = ( width - left - right ) * nDPI / 72;
767 rOutHeight = ( height - top - bottom ) * nDPI / 72;
771 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
773 if( ! pJobSetup )
774 return 0;
776 JobData aData;
777 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
779 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
780 return pKey ? pKey->countValues() : 0;
783 rtl::OUString PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
785 JobData aData;
786 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
788 OUString aRet;
789 if( aData.m_pParser )
791 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
792 if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
793 aRet = aData.m_pParser->getDefaultInputSlot();
794 else
796 const PPDValue* pValue = pKey->getValue( nPaperBin );
797 if( pValue )
798 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
802 return aRet;
805 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
807 switch( nType )
809 case PRINTER_CAPABILITIES_SUPPORTDIALOG:
810 return 1;
811 case PRINTER_CAPABILITIES_COPIES:
812 return 0xffff;
813 case PRINTER_CAPABILITIES_COLLATECOPIES:
815 // see if the PPD contains a value to set Collate to True
816 JobData aData;
817 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
819 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
820 const PPDValue* pVal = pKey ? pKey->getValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
822 // PPDs don't mention the number of possible collated copies.
823 // so let's guess as many as we want ?
824 return pVal ? 0xffff : 0;
826 case PRINTER_CAPABILITIES_SETORIENTATION:
827 return 1;
828 case PRINTER_CAPABILITIES_SETDUPLEX:
829 return 1;
830 case PRINTER_CAPABILITIES_SETPAPERBIN:
831 return 1;
832 case PRINTER_CAPABILITIES_SETPAPERSIZE:
833 return 1;
834 case PRINTER_CAPABILITIES_SETPAPER:
835 return 0;
836 case PRINTER_CAPABILITIES_FAX:
837 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
838 case PRINTER_CAPABILITIES_PDF:
839 if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
840 return 1;
841 else
843 // see if the PPD contains a value to set Collate to True
844 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
845 if( pJobSetup->mpDriverData )
846 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
847 return aData.m_nPDFDevice > 0 ? 1 : 0;
849 case PRINTER_CAPABILITIES_EXTERNALDIALOG:
850 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
851 case PRINTER_CAPABILITIES_USEPULLMODEL:
853 // see if the PPD contains a value to set Collate to True
854 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
855 if( pJobSetup->mpDriverData )
856 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
857 return aData.m_nPDFDevice > 0 ? 1 : 0;
859 default: break;
861 return 0;
865 * SalPrinter
867 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
868 : m_bFax( false ),
869 m_bPdf( false ),
870 m_bSwallowFaxNo( false ),
871 m_bIsPDFWriterJob( false ),
872 m_pGraphics( NULL ),
873 m_nCopies( 1 ),
874 m_bCollate( false ),
875 m_pInfoPrinter( pInfoPrinter )
879 PspSalPrinter::~PspSalPrinter()
883 static rtl::OUString getTmpName()
885 rtl::OUString aTmp, aSys;
886 osl_createTempFile( NULL, NULL, &aTmp.pData );
887 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
889 return aSys;
892 sal_Bool PspSalPrinter::StartJob(
893 const rtl::OUString* pFileName,
894 const rtl::OUString& rJobName,
895 const rtl::OUString& rAppName,
896 sal_uLong nCopies,
897 bool bCollate,
898 bool bDirect,
899 ImplJobSetup* pJobSetup )
901 OSL_TRACE("PspSalPrinter::StartJob");
902 GetSalData()->m_pInstance->jobStartedPrinterUpdate();
904 m_bFax = false;
905 m_bPdf = false;
906 m_aFileName = pFileName ? *pFileName : rtl::OUString();
907 m_aTmpFile = rtl::OUString();
908 m_nCopies = nCopies;
909 m_bCollate = bCollate;
911 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
912 if( m_nCopies > 1 )
914 // in case user did not do anything (m_nCopies=1)
915 // take the default from jobsetup
916 m_aJobData.m_nCopies = m_nCopies;
917 m_aJobData.setCollate( bCollate );
920 int nMode = 0;
921 #if defined( UNX )
922 // check whether this printer is configured as fax
923 sal_Int32 nIndex = 0;
924 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
925 while( nIndex != -1 )
927 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
928 if( ! aToken.compareToAscii( "fax", 3 ) )
930 m_bFax = true;
931 m_aTmpFile = getTmpName();
932 nMode = S_IRUSR | S_IWUSR;
934 ::boost::unordered_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
935 it = pJobSetup->maValueMap.find( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FAX#")) );
936 if( it != pJobSetup->maValueMap.end() )
937 m_aFaxNr = it->second;
939 sal_Int32 nPos = 0;
940 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
942 break;
944 if( ! aToken.compareToAscii( "pdf=", 4 ) )
946 m_bPdf = true;
947 m_aTmpFile = getTmpName();
948 nMode = S_IRUSR | S_IWUSR;
950 if( m_aFileName.isEmpty() )
952 rtl::OUStringBuffer aFileName( getPdfDir( rInfo ) );
953 aFileName.append( '/' );
954 aFileName.append( rJobName );
955 aFileName.appendAscii( RTL_CONSTASCII_STRINGPARAM( ".pdf" ) );
956 m_aFileName = aFileName.makeStringAndClear();
958 break;
961 #endif
962 m_aPrinterGfx.Init( m_aJobData );
964 return m_aPrintJob.StartJob( ! m_aTmpFile.isEmpty() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False;
967 sal_Bool PspSalPrinter::EndJob()
969 sal_Bool bSuccess = sal_False;
970 if( m_bIsPDFWriterJob )
971 bSuccess = sal_True;
972 else
974 bSuccess = m_aPrintJob.EndJob();
975 OSL_TRACE("PspSalPrinter::EndJob %d", bSuccess);
977 if( bSuccess )
979 // check for fax
980 if( m_bFax )
982 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
983 // sendAFax removes the file after use
984 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
986 else if( m_bPdf )
988 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
989 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
993 GetSalData()->m_pInstance->jobEndedPrinterUpdate();
994 return bSuccess;
997 sal_Bool PspSalPrinter::AbortJob()
999 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
1000 GetSalData()->m_pInstance->jobEndedPrinterUpdate();
1001 return bAbort;
1004 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
1006 OSL_TRACE("PspSalPrinter::StartPage");
1008 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
1009 m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
1010 m_pGraphics->Init( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL,
1011 m_bSwallowFaxNo, m_pInfoPrinter );
1012 if( m_nCopies > 1 )
1014 // in case user did not do anything (m_nCopies=1)
1015 // take the default from jobsetup
1016 m_aJobData.m_nCopies = m_nCopies;
1017 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
1020 m_aPrintJob.StartPage( m_aJobData );
1021 m_aPrinterGfx.Init( m_aPrintJob );
1023 return m_pGraphics;
1026 sal_Bool PspSalPrinter::EndPage()
1028 sal_Bool bResult = m_aPrintJob.EndPage();
1029 m_aPrinterGfx.Clear();
1030 OSL_TRACE("PspSalPrinter::EndPage");
1031 return bResult ? sal_True : sal_False;
1034 sal_uLong PspSalPrinter::GetErrorCode()
1036 return 0;
1039 struct PDFNewJobParameters
1041 Size maPageSize;
1042 sal_uInt16 mnPaperBin;
1044 PDFNewJobParameters( const Size& i_rSize = Size(),
1045 sal_uInt16 i_nPaperBin = 0xffff )
1046 : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
1048 bool operator!=(const PDFNewJobParameters& rComp ) const
1050 Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() );
1051 return
1052 (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize)
1053 || mnPaperBin != rComp.mnPaperBin
1057 bool operator==(const PDFNewJobParameters& rComp) const
1059 return ! this->operator!=(rComp);
1063 struct PDFPrintFile
1065 rtl::OUString maTmpURL;
1066 PDFNewJobParameters maParameters;
1068 PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
1069 : maTmpURL( i_rURL )
1070 , maParameters( i_rNewParameters ) {}
1073 sal_Bool PspSalPrinter::StartJob( const rtl::OUString* i_pFileName, const rtl::OUString& i_rJobName, const rtl::OUString& i_rAppName,
1074 ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
1076 OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
1077 // mark for endjob
1078 m_bIsPDFWriterJob = true;
1079 // reset IsLastPage
1080 i_rController.setLastPage( sal_False );
1082 // update job data
1083 if( i_pSetupData )
1084 JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
1086 OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
1087 m_aJobData.m_nPDFDevice = 1;
1089 // possibly create one job for collated output
1090 sal_Bool bSinglePrintJobs = sal_False;
1091 beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
1092 if( pSingleValue )
1094 pSingleValue->Value >>= bSinglePrintJobs;
1097 int nCopies = i_rController.getPrinter()->GetCopyCount();
1098 bool bCollate = i_rController.getPrinter()->IsCollateCopy();
1100 // notify start of real print job
1101 i_rController.jobStarted();
1103 // setup PDFWriter context
1104 vcl::PDFWriter::PDFWriterContext aContext;
1105 aContext.Version = vcl::PDFWriter::PDF_1_4;
1106 aContext.Tagged = false;
1107 aContext.EmbedStandardFonts = true;
1108 aContext.DocumentLocale = Application::GetSettings().GetLanguageTag().getLocale();
1109 aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
1110 ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
1112 // prepare doc info
1113 aContext.DocumentInfo.Title = i_rJobName;
1114 aContext.DocumentInfo.Creator = i_rAppName;
1115 aContext.DocumentInfo.Producer = i_rAppName;
1117 // define how we handle metafiles in PDFWriter
1118 vcl::PDFWriter::PlayMetafileContext aMtfContext;
1119 aMtfContext.m_bOnlyLosslessCompression = true;
1121 boost::shared_ptr<vcl::PDFWriter> pWriter;
1122 std::vector< PDFPrintFile > aPDFFiles;
1123 boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
1124 int nAllPages = i_rController.getFilteredPageCount();
1125 i_rController.createProgressDialog();
1126 bool bAborted = false;
1127 PDFNewJobParameters aLastParm;
1129 aContext.DPIx = pPrinter->ImplGetDPIX();
1130 aContext.DPIy = pPrinter->ImplGetDPIY();
1131 for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
1133 if( nPage == nAllPages-1 )
1134 i_rController.setLastPage( sal_True );
1136 // get the page's metafile
1137 GDIMetaFile aPageFile;
1138 vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
1139 if( i_rController.isProgressCanceled() )
1141 bAborted = true;
1142 if( nPage != nAllPages-1 )
1144 i_rController.createProgressDialog();
1145 i_rController.setLastPage( sal_True );
1146 i_rController.getFilteredPageFile( nPage, aPageFile );
1149 else
1151 pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1152 pPrinter->SetPaperSizeUser( aPageSize.aSize, true );
1153 PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() );
1155 // create PDF writer on demand
1156 // either on first page
1157 // or on paper format change - cups does not support multiple paper formats per job (yet?)
1158 // so we need to start a new job to get a new paper format from the printer
1159 // orientation switches (that is switch of height and width) is handled transparently by CUPS
1160 if( ! pWriter ||
1161 (aNewParm != aLastParm && ! i_pFileName ) )
1163 if( pWriter )
1165 pWriter->Emit();
1167 // produce PDF file
1168 OUString aPDFUrl;
1169 if( i_pFileName )
1170 aPDFUrl = *i_pFileName;
1171 else
1172 osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
1173 // normalize to file URL
1174 if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 )
1176 // this is not a file URL, but it should
1177 // form it into a osl friendly file URL
1178 rtl::OUString aTmp;
1179 osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
1180 aPDFUrl = aTmp;
1182 // save current file and paper format
1183 aLastParm = aNewParm;
1184 aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
1185 // update context
1186 aContext.URL = aPDFUrl;
1188 // create and initialize PDFWriter
1189 #if defined __SUNPRO_CC
1190 #pragma disable_warn
1191 #endif
1192 pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
1193 #if defined __SUNPRO_CC
1194 #pragma enable_warn
1195 #endif
1198 pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
1199 TenMuToPt( aNewParm.maPageSize.Height() ),
1200 vcl::PDFWriter::Portrait );
1202 pWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
1206 // emit the last file
1207 if( pWriter )
1208 pWriter->Emit();
1210 // handle collate, copy count and multiple jobs correctly
1211 int nOuterJobs = 1;
1212 if( bSinglePrintJobs )
1214 nOuterJobs = nCopies;
1215 m_aJobData.m_nCopies = 1;
1217 else
1219 if( bCollate )
1221 if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) )
1223 m_aJobData.setCollate( true );
1224 m_aJobData.m_nCopies = nCopies;
1226 else
1228 nOuterJobs = nCopies;
1229 m_aJobData.m_nCopies = 1;
1232 else
1234 m_aJobData.setCollate( false );
1235 m_aJobData.m_nCopies = nCopies;
1239 // spool files
1240 if( ! i_pFileName && ! bAborted )
1242 bool bFirstJob = true;
1243 for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
1245 for( size_t i = 0; i < aPDFFiles.size(); i++ )
1247 oslFileHandle pFile = NULL;
1248 osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
1249 if (pFile && (osl_setFilePos(pFile, osl_Pos_Absolut, 0) == osl_File_E_None))
1251 std::vector< char > buffer( 0x10000, 0 );
1252 // update job data with current page size
1253 Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
1254 m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
1255 // update job data with current paperbin
1256 m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
1258 // spool current file
1259 FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() );
1260 if( fp )
1262 sal_uInt64 nBytesRead = 0;
1265 osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
1266 if( nBytesRead > 0 )
1268 size_t nBytesWritten = fwrite(&buffer[0], 1, nBytesRead, fp);
1269 OSL_ENSURE(nBytesRead == nBytesWritten, "short write");
1270 if (nBytesRead != nBytesWritten)
1271 break;
1273 } while( nBytesRead == buffer.size() );
1274 rtl::OUStringBuffer aBuf( i_rJobName.getLength() + 8 );
1275 aBuf.append( i_rJobName );
1276 if( i > 0 || nCurJob > 0 )
1278 aBuf.append( sal_Unicode(' ') );
1279 aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
1281 PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob );
1282 bFirstJob = false;
1285 osl_closeFile( pFile );
1290 // job has been spooled
1291 i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED );
1293 // clean up the temporary PDF files
1294 if( ! i_pFileName || bAborted )
1296 for( size_t i = 0; i < aPDFFiles.size(); i++ )
1298 osl_removeFile( aPDFFiles[i].maTmpURL.pData );
1299 OSL_TRACE( "removed print PDF file %s", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1303 return sal_True;
1307 class PrinterUpdate
1309 static Timer* pPrinterUpdateTimer;
1310 static int nActiveJobs;
1312 static void doUpdate();
1313 DECL_STATIC_LINK( PrinterUpdate, UpdateTimerHdl, void* );
1314 public:
1315 static void update(SalGenericInstance &rInstance);
1316 static void jobStarted() { nActiveJobs++; }
1317 static void jobEnded();
1320 Timer* PrinterUpdate::pPrinterUpdateTimer = NULL;
1321 int PrinterUpdate::nActiveJobs = 0;
1323 void PrinterUpdate::doUpdate()
1325 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
1326 SalGenericInstance *pInst = static_cast<SalGenericInstance *>( GetSalData()->m_pInstance );
1327 if( pInst && rManager.checkPrintersChanged( false ) )
1328 pInst->PostPrintersChanged();
1331 // -----------------------------------------------------------------------
1333 IMPL_STATIC_LINK_NOINSTANCE( PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
1335 if( nActiveJobs < 1 )
1337 doUpdate();
1338 delete pPrinterUpdateTimer;
1339 pPrinterUpdateTimer = NULL;
1341 else
1342 pPrinterUpdateTimer->Start();
1344 return 0;
1347 void PrinterUpdate::update(SalGenericInstance &rInstance)
1349 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
1350 return;
1352 if( ! rInstance.isPrinterInit() )
1354 // #i45389# start background printer detection
1355 psp::PrinterInfoManager::get();
1356 return;
1359 if( nActiveJobs < 1 )
1360 doUpdate();
1361 else if( ! pPrinterUpdateTimer )
1363 pPrinterUpdateTimer = new Timer();
1364 pPrinterUpdateTimer->SetTimeout( 500 );
1365 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, PrinterUpdate, UpdateTimerHdl ) );
1366 pPrinterUpdateTimer->Start();
1370 void SalGenericInstance::updatePrinterUpdate()
1372 PrinterUpdate::update(*this);
1375 void SalGenericInstance::jobStartedPrinterUpdate()
1377 PrinterUpdate::jobStarted();
1380 void PrinterUpdate::jobEnded()
1382 nActiveJobs--;
1383 if( nActiveJobs < 1 )
1385 if( pPrinterUpdateTimer )
1387 pPrinterUpdateTimer->Stop();
1388 delete pPrinterUpdateTimer;
1389 pPrinterUpdateTimer = NULL;
1390 doUpdate();
1395 void SalGenericInstance::jobEndedPrinterUpdate()
1397 PrinterUpdate::jobEnded();
1400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */