LCOV - code coverage report
Current view: top level - vcl/generic/print - genprnpsp.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 154 661 23.3 %
Date: 2015-06-13 12:38:46 Functions: 15 66 22.7 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11