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