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