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