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