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