Change-Id: Ibfa971952cd330ddf430e7e951c5c235d2ae6bd8 Reviewed-on: https://gerrit.libreoffice.org/16314 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Stahl <mstahl@redhat.com>
1374 lines
43 KiB
C++
1374 lines
43 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
/**
|
|
this file implements the sal printer interface (SalPrinter, SalInfoPrinter
|
|
and some printer relevant methods of SalInstance and SalGraphicsData)
|
|
|
|
as underlying library the printer features of psprint are used.
|
|
|
|
The query methods of a SalInfoPrinter are implemented by querying psprint
|
|
|
|
The job methods of a SalPrinter are implemented by calling psprint
|
|
printer job functions.
|
|
*/
|
|
|
|
// For spawning PDF and FAX generation
|
|
#if defined( UNX )
|
|
# include <unistd.h>
|
|
# include <sys/wait.h>
|
|
# include <sys/stat.h>
|
|
#endif
|
|
|
|
#include "rtl/ustring.hxx"
|
|
|
|
#include "vcl/button.hxx"
|
|
#include "vcl/dialog.hxx"
|
|
#include "vcl/edit.hxx"
|
|
#include "vcl/fixed.hxx"
|
|
#include "vcl/idle.hxx"
|
|
#include "vcl/svapp.hxx"
|
|
#include "vcl/print.hxx"
|
|
#include "vcl/pdfwriter.hxx"
|
|
#include "vcl/printerinfomanager.hxx"
|
|
#include "vcl/settings.hxx"
|
|
#include "svids.hrc"
|
|
#include "saldatabasic.hxx"
|
|
#include "generic/genprn.h"
|
|
#include "generic/geninst.h"
|
|
#include "generic/genpspgraphics.h"
|
|
|
|
#include "jobset.h"
|
|
#include "print.h"
|
|
#include "prtsetup.hxx"
|
|
#include "salptype.hxx"
|
|
|
|
#include <com/sun/star/beans/PropertyValue.hpp>
|
|
|
|
using namespace psp;
|
|
using namespace com::sun::star;
|
|
|
|
/*
|
|
* static helpers
|
|
*/
|
|
static OUString getPdfDir( const PrinterInfo& rInfo )
|
|
{
|
|
OUString aDir;
|
|
sal_Int32 nIndex = 0;
|
|
while( nIndex != -1 )
|
|
{
|
|
OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
|
|
if( aToken.startsWith( "pdf=" ) )
|
|
{
|
|
sal_Int32 nPos = 0;
|
|
aDir = aToken.getToken( 1, '=', nPos );
|
|
if( aDir.isEmpty() && getenv( "HOME" ) )
|
|
aDir = OUString( getenv( "HOME" ), strlen( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
|
|
break;
|
|
}
|
|
}
|
|
return aDir;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class QueryString : public ModalDialog
|
|
{
|
|
private:
|
|
VclPtr<OKButton> m_pOKButton;
|
|
VclPtr<FixedText> m_pFixedText;
|
|
VclPtr<Edit> m_pEdit;
|
|
OUString& m_rReturnValue;
|
|
|
|
DECL_LINK( ClickBtnHdl, Button* );
|
|
|
|
public:
|
|
// parent window, Query text, initial value
|
|
QueryString(vcl::Window*, OUString &, OUString &);
|
|
virtual ~QueryString() { disposeOnce(); }
|
|
virtual void dispose() SAL_OVERRIDE
|
|
{
|
|
m_pOKButton.clear();
|
|
m_pFixedText.clear();
|
|
m_pEdit.clear();
|
|
ModalDialog::dispose();
|
|
}
|
|
};
|
|
|
|
/*
|
|
* QueryString
|
|
*/
|
|
QueryString::QueryString(vcl::Window* pParent, OUString& rQuery, OUString& rRet)
|
|
: ModalDialog(pParent, "QueryDialog",
|
|
"vcl/ui/querydialog.ui" )
|
|
, m_rReturnValue( rRet )
|
|
{
|
|
get(m_pOKButton, "ok");
|
|
get(m_pFixedText, "label");
|
|
get(m_pEdit, "entry");
|
|
|
|
m_pOKButton->SetClickHdl(LINK(this, QueryString, ClickBtnHdl));
|
|
m_pFixedText->SetText(rQuery);
|
|
m_pEdit->SetText(m_rReturnValue);
|
|
SetText(rQuery);
|
|
}
|
|
|
|
IMPL_LINK( QueryString, ClickBtnHdl, Button*, pButton )
|
|
{
|
|
if (pButton == m_pOKButton)
|
|
{
|
|
m_rReturnValue = m_pEdit->GetText();
|
|
EndDialog( 1 );
|
|
}
|
|
else
|
|
EndDialog(0);
|
|
return 0;
|
|
}
|
|
|
|
int QueryFaxNumber(OUString& rNumber)
|
|
{
|
|
OUString aTmpString(VclResId(SV_PRINT_QUERYFAXNUMBER_TXT));
|
|
ScopedVclPtrInstance< QueryString > aQuery( nullptr, aTmpString, rNumber );
|
|
return aQuery->Execute();
|
|
}
|
|
}
|
|
|
|
inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
|
|
|
|
inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
|
|
|
|
static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
|
|
{
|
|
pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
|
|
|
|
// copy page size
|
|
OUString aPaper;
|
|
int width, height;
|
|
|
|
rData.m_aContext.getPageSize( aPaper, width, height );
|
|
pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
|
|
|
|
pJobSetup->mnPaperWidth = 0;
|
|
pJobSetup->mnPaperHeight = 0;
|
|
if( pJobSetup->mePaperFormat == PAPER_USER )
|
|
{
|
|
// transform to 100dth mm
|
|
width = PtTo10Mu( width );
|
|
height = PtTo10Mu( height );
|
|
|
|
if( rData.m_eOrientation == psp::orientation::Portrait )
|
|
{
|
|
pJobSetup->mnPaperWidth = width;
|
|
pJobSetup->mnPaperHeight= height;
|
|
}
|
|
else
|
|
{
|
|
pJobSetup->mnPaperWidth = height;
|
|
pJobSetup->mnPaperHeight= width;
|
|
}
|
|
}
|
|
|
|
// copy input slot
|
|
const PPDKey* pKey = NULL;
|
|
const PPDValue* pValue = NULL;
|
|
|
|
pJobSetup->mnPaperBin = 0;
|
|
if( rData.m_pParser )
|
|
pKey = rData.m_pParser->getKey( OUString("InputSlot") );
|
|
if( pKey )
|
|
pValue = rData.m_aContext.getValue( pKey );
|
|
if( pKey && pValue )
|
|
{
|
|
for( pJobSetup->mnPaperBin = 0;
|
|
pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
|
|
pJobSetup->mnPaperBin < pKey->countValues();
|
|
pJobSetup->mnPaperBin++ )
|
|
;
|
|
if( pJobSetup->mnPaperBin >= pKey->countValues() )
|
|
pJobSetup->mnPaperBin = 0;
|
|
}
|
|
|
|
// copy duplex
|
|
pKey = NULL;
|
|
pValue = NULL;
|
|
|
|
pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
|
|
if( rData.m_pParser )
|
|
pKey = rData.m_pParser->getKey( OUString("Duplex") );
|
|
if( pKey )
|
|
pValue = rData.m_aContext.getValue( pKey );
|
|
if( pKey && pValue )
|
|
{
|
|
if( pValue->m_aOption.equalsIgnoreAsciiCase( "None" ) ||
|
|
pValue->m_aOption.startsWithIgnoreAsciiCase( "Simplex" )
|
|
)
|
|
{
|
|
pJobSetup->meDuplexMode = DUPLEX_OFF;
|
|
}
|
|
else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexNoTumble" ) )
|
|
{
|
|
pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
|
|
}
|
|
else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexTumble" ) )
|
|
{
|
|
pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
|
|
}
|
|
}
|
|
|
|
// copy the whole context
|
|
if( pJobSetup->mpDriverData )
|
|
rtl_freeMemory( pJobSetup->mpDriverData );
|
|
|
|
int nBytes;
|
|
void* pBuffer = NULL;
|
|
if( rData.getStreamBuffer( pBuffer, nBytes ) )
|
|
{
|
|
pJobSetup->mnDriverDataLen = nBytes;
|
|
pJobSetup->mpDriverData = static_cast<sal_uInt8*>(pBuffer);
|
|
}
|
|
else
|
|
{
|
|
pJobSetup->mnDriverDataLen = 0;
|
|
pJobSetup->mpDriverData = NULL;
|
|
}
|
|
}
|
|
|
|
// Needs a cleaner abstraction ...
|
|
#if defined( UNX )
|
|
static bool passFileToCommandLine( const OUString& rFilename, const OUString& rCommandLine, bool bRemoveFile = true )
|
|
{
|
|
bool bSuccess = false;
|
|
|
|
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
|
|
OString aCmdLine(OUStringToOString(rCommandLine, aEncoding));
|
|
OString aFilename(OUStringToOString(rFilename, aEncoding));
|
|
|
|
bool bPipe = aCmdLine.indexOf( "(TMP)" ) == -1;
|
|
|
|
// setup command line for exec
|
|
if( ! bPipe )
|
|
aCmdLine = aCmdLine.replaceAll(OString("(TMP)"), aFilename);
|
|
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
fprintf( stderr, "%s commandline: \"%s\"\n",
|
|
bPipe ? "piping to" : "executing",
|
|
aCmdLine.getStr() );
|
|
struct stat aStat;
|
|
if( stat( aFilename.getStr(), &aStat ) )
|
|
fprintf( stderr, "stat( %s ) failed\n", aFilename.getStr() );
|
|
fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.getStr(), (long)aStat.st_mode );
|
|
#endif
|
|
const char* argv[4];
|
|
if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
|
|
argv[ 0 ] = "/bin/sh";
|
|
argv[ 1 ] = "-c";
|
|
argv[ 2 ] = aCmdLine.getStr();
|
|
argv[ 3 ] = 0;
|
|
|
|
bool bHavePipes = false;
|
|
int pid, fd[2];
|
|
|
|
if( bPipe )
|
|
bHavePipes = pipe( fd ) == 0;
|
|
if( ( pid = fork() ) > 0 )
|
|
{
|
|
if( bPipe && bHavePipes )
|
|
{
|
|
close( fd[0] );
|
|
char aBuffer[ 2048 ];
|
|
FILE* fp = fopen( aFilename.getStr(), "r" );
|
|
while (fp && !feof(fp))
|
|
{
|
|
size_t nBytesRead = fread(aBuffer, 1, sizeof( aBuffer ), fp);
|
|
if (nBytesRead )
|
|
{
|
|
size_t nBytesWritten = write(fd[1], aBuffer, nBytesRead);
|
|
OSL_ENSURE(nBytesWritten == nBytesRead, "short write");
|
|
if (nBytesWritten != nBytesRead)
|
|
break;
|
|
}
|
|
}
|
|
fclose( fp );
|
|
close( fd[ 1 ] );
|
|
}
|
|
int status = 0;
|
|
if(waitpid( pid, &status, 0 ) != -1)
|
|
{
|
|
if( ! status )
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
else if( ! pid )
|
|
{
|
|
if( bPipe && bHavePipes )
|
|
{
|
|
close( fd[1] );
|
|
if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
|
|
dup2( fd[0], STDIN_FILENO );
|
|
}
|
|
execv( argv[0], const_cast<char**>(argv) );
|
|
fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.getStr() );
|
|
_exit( 1 );
|
|
}
|
|
else
|
|
fprintf( stderr, "failed to fork\n" );
|
|
|
|
// clean up the mess
|
|
if( bRemoveFile )
|
|
unlink( aFilename.getStr() );
|
|
|
|
return bSuccess;
|
|
}
|
|
#endif
|
|
|
|
static std::vector<OUString> getFaxNumbers()
|
|
{
|
|
std::vector<OUString> aFaxNumbers;
|
|
|
|
OUString aNewNr;
|
|
if (QueryFaxNumber(aNewNr))
|
|
{
|
|
sal_Int32 nIndex = 0;
|
|
do
|
|
{
|
|
OUString sToken = aNewNr.getToken( 0, ';', nIndex );
|
|
aFaxNumbers.push_back(sToken);
|
|
}
|
|
while (nIndex >= 0);
|
|
}
|
|
|
|
return aFaxNumbers;
|
|
}
|
|
|
|
static bool createPdf( const OUString& rToFile, const OUString& rFromFile, const OUString& rCommandLine )
|
|
{
|
|
#if defined( UNX )
|
|
OUString aCommandLine(
|
|
rCommandLine.replaceAll("(OUTFILE)", rToFile));
|
|
|
|
return passFileToCommandLine( rFromFile, aCommandLine );
|
|
#else
|
|
(void)rToFile; (void)rFromFile; (void)rCommandLine;
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* SalInstance
|
|
*/
|
|
|
|
void SalGenericInstance::configurePspInfoPrinter(PspSalInfoPrinter *pPrinter,
|
|
SalPrinterQueueInfo* pQueueInfo, ImplJobSetup* pJobSetup)
|
|
{
|
|
if( pJobSetup )
|
|
{
|
|
PrinterInfoManager& rManager( PrinterInfoManager::get() );
|
|
PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
|
|
pPrinter->m_aJobData = aInfo;
|
|
pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
|
|
|
|
if( pJobSetup->mpDriverData )
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
|
|
|
|
pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
|
|
pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
|
|
pJobSetup->maDriver = aInfo.m_aDriverName;
|
|
copyJobDataToJobSetup( pJobSetup, aInfo );
|
|
}
|
|
}
|
|
|
|
SalInfoPrinter* SalGenericInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
|
|
ImplJobSetup* pJobSetup )
|
|
{
|
|
mbPrinterInit = true;
|
|
// create and initialize SalInfoPrinter
|
|
PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter();
|
|
configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup);
|
|
return pPrinter;
|
|
}
|
|
|
|
void SalGenericInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
|
|
{
|
|
delete pPrinter;
|
|
}
|
|
|
|
SalPrinter* SalGenericInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
|
|
{
|
|
mbPrinterInit = true;
|
|
// create and initialize SalPrinter
|
|
PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
|
|
pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
|
|
|
|
return pPrinter;
|
|
}
|
|
|
|
void SalGenericInstance::DestroyPrinter( SalPrinter* pPrinter )
|
|
{
|
|
delete pPrinter;
|
|
}
|
|
|
|
void SalGenericInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
|
|
{
|
|
mbPrinterInit = true;
|
|
PrinterInfoManager& rManager( PrinterInfoManager::get() );
|
|
static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
|
|
if( ! pNoSyncDetection || ! *pNoSyncDetection )
|
|
{
|
|
// #i62663# synchronize possible asynchronouse printer detection now
|
|
rManager.checkPrintersChanged( true );
|
|
}
|
|
::std::list< OUString > aPrinters;
|
|
rManager.listPrinters( aPrinters );
|
|
|
|
for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
|
|
{
|
|
const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
|
|
// Neuen Eintrag anlegen
|
|
SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
|
|
pInfo->maPrinterName = *it;
|
|
pInfo->maDriver = rInfo.m_aDriverName;
|
|
pInfo->maLocation = rInfo.m_aLocation;
|
|
pInfo->maComment = rInfo.m_aComment;
|
|
pInfo->mpSysData = NULL;
|
|
|
|
sal_Int32 nIndex = 0;
|
|
while( nIndex != -1 )
|
|
{
|
|
OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
|
|
if( aToken.match( "pdf=" ) )
|
|
{
|
|
pInfo->maLocation = getPdfDir( rInfo );
|
|
break;
|
|
}
|
|
}
|
|
|
|
pList->Add( pInfo );
|
|
}
|
|
}
|
|
|
|
void SalGenericInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
|
|
{
|
|
delete pInfo;
|
|
}
|
|
|
|
void SalGenericInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
|
|
{
|
|
mbPrinterInit = true;
|
|
}
|
|
|
|
OUString SalGenericInstance::GetDefaultPrinter()
|
|
{
|
|
mbPrinterInit = true;
|
|
PrinterInfoManager& rManager( PrinterInfoManager::get() );
|
|
return rManager.getDefaultPrinter();
|
|
}
|
|
|
|
PspSalInfoPrinter::PspSalInfoPrinter()
|
|
: m_pGraphics( NULL )
|
|
{
|
|
}
|
|
|
|
PspSalInfoPrinter::~PspSalInfoPrinter()
|
|
{
|
|
if( m_pGraphics )
|
|
{
|
|
delete m_pGraphics;
|
|
m_pGraphics = NULL;
|
|
}
|
|
}
|
|
|
|
void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
|
|
{
|
|
m_aPaperFormats.clear();
|
|
m_bPapersInit = true;
|
|
|
|
if( m_aJobData.m_pParser )
|
|
{
|
|
const PPDKey* pKey = m_aJobData.m_pParser->getKey( OUString("PageSize") );
|
|
if( pKey )
|
|
{
|
|
int nValues = pKey->countValues();
|
|
for( int i = 0; i < nValues; i++ )
|
|
{
|
|
const PPDValue* pValue = pKey->getValue( i );
|
|
int nWidth = 0, nHeight = 0;
|
|
m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
|
|
PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
|
|
m_aPaperFormats.push_back( aInfo );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
|
|
{
|
|
return 900;
|
|
}
|
|
|
|
SalGraphics* PspSalInfoPrinter::AcquireGraphics()
|
|
{
|
|
// return a valid pointer only once
|
|
// the reasoning behind this is that we could have different
|
|
// SalGraphics that can run in multiple threads
|
|
// (future plans)
|
|
SalGraphics* pRet = NULL;
|
|
if( ! m_pGraphics )
|
|
{
|
|
m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
|
|
m_pGraphics->Init(&m_aJobData, &m_aPrinterGfx, this);
|
|
pRet = m_pGraphics;
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
|
|
{
|
|
if( pGraphics == m_pGraphics )
|
|
{
|
|
delete pGraphics;
|
|
m_pGraphics = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
|
|
{
|
|
if( ! pFrame || ! pJobSetup )
|
|
return false;
|
|
|
|
PrinterInfoManager& rManager = PrinterInfoManager::get();
|
|
|
|
PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
|
|
if ( pJobSetup->mpDriverData )
|
|
{
|
|
SetData( ~0, pJobSetup );
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
|
|
}
|
|
|
|
if (SetupPrinterDriver(aInfo))
|
|
{
|
|
aInfo.resolveDefaultBackend();
|
|
rtl_freeMemory( pJobSetup->mpDriverData );
|
|
pJobSetup->mpDriverData = NULL;
|
|
|
|
int nBytes;
|
|
void* pBuffer = NULL;
|
|
aInfo.getStreamBuffer( pBuffer, nBytes );
|
|
pJobSetup->mnDriverDataLen = nBytes;
|
|
pJobSetup->mpDriverData = static_cast<sal_uInt8*>(pBuffer);
|
|
|
|
// copy everything to job setup
|
|
copyJobDataToJobSetup( pJobSetup, aInfo );
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// This function gets the driver data and puts it into pJobSetup
|
|
// If pJobSetup->mpDriverData is NOT NULL, then the independent
|
|
// data should be merged into the driver data
|
|
// If pJobSetup->mpDriverData IS NULL, then the driver defaults
|
|
// should be merged into the independent data
|
|
bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
|
|
{
|
|
if( pJobSetup->mpDriverData )
|
|
return SetData( ~0, pJobSetup );
|
|
|
|
copyJobDataToJobSetup( pJobSetup, m_aJobData );
|
|
|
|
return true;
|
|
}
|
|
|
|
// This function merges the independ driver data
|
|
// and sets the new independ data in pJobSetup
|
|
// Only the data must be changed, where the bit
|
|
// in nGetDataFlags is set
|
|
bool PspSalInfoPrinter::SetData(
|
|
sal_uLong nSetDataFlags,
|
|
ImplJobSetup* pJobSetup )
|
|
{
|
|
JobData aData;
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
|
|
if( aData.m_pParser )
|
|
{
|
|
const PPDKey* pKey;
|
|
const PPDValue* pValue;
|
|
|
|
// merge papersize if necessary
|
|
if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
|
|
{
|
|
OUString aPaper;
|
|
|
|
if( pJobSetup->mePaperFormat == PAPER_USER )
|
|
aPaper = aData.m_pParser->matchPaper(
|
|
TenMuToPt( pJobSetup->mnPaperWidth ),
|
|
TenMuToPt( pJobSetup->mnPaperHeight ) );
|
|
else
|
|
aPaper = OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
|
|
|
|
pKey = aData.m_pParser->getKey( OUString("PageSize") );
|
|
pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
|
|
|
|
// some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
|
|
// try to find the correct paper anyway using the size
|
|
if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
|
|
{
|
|
PaperInfo aInfo( pJobSetup->mePaperFormat );
|
|
aPaper = aData.m_pParser->matchPaper(
|
|
TenMuToPt( aInfo.getWidth() ),
|
|
TenMuToPt( aInfo.getHeight() ) );
|
|
pValue = pKey->getValueCaseInsensitive( aPaper );
|
|
}
|
|
|
|
if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
|
|
return false;
|
|
}
|
|
|
|
// merge paperbin if necessary
|
|
if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
|
|
{
|
|
pKey = aData.m_pParser->getKey( OUString("InputSlot") );
|
|
if( pKey )
|
|
{
|
|
int nPaperBin = pJobSetup->mnPaperBin;
|
|
if( nPaperBin >= pKey->countValues() )
|
|
pValue = pKey->getDefaultValue();
|
|
else
|
|
pValue = pKey->getValue( pJobSetup->mnPaperBin );
|
|
|
|
// may fail due to constraints;
|
|
// real paper bin is copied back to jobsetup in that case
|
|
aData.m_aContext.setValue( pKey, pValue );
|
|
}
|
|
// if printer has no InputSlot key simply ignore this setting
|
|
// (e.g. SGENPRT has no InputSlot)
|
|
}
|
|
|
|
// merge orientation if necessary
|
|
if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
|
|
aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
|
|
|
|
// merge duplex if necessary
|
|
if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
|
|
{
|
|
pKey = aData.m_pParser->getKey( OUString("Duplex") );
|
|
if( pKey )
|
|
{
|
|
pValue = NULL;
|
|
switch( pJobSetup->meDuplexMode )
|
|
{
|
|
case DUPLEX_OFF:
|
|
pValue = pKey->getValue( OUString("None") );
|
|
if( pValue == NULL )
|
|
pValue = pKey->getValue( OUString("SimplexNoTumble") );
|
|
break;
|
|
case DUPLEX_SHORTEDGE:
|
|
pValue = pKey->getValue( OUString("DuplexTumble") );
|
|
break;
|
|
case DUPLEX_LONGEDGE:
|
|
pValue = pKey->getValue( OUString("DuplexNoTumble") );
|
|
break;
|
|
case DUPLEX_UNKNOWN:
|
|
default:
|
|
pValue = 0;
|
|
break;
|
|
}
|
|
if( ! pValue )
|
|
pValue = pKey->getDefaultValue();
|
|
aData.m_aContext.setValue( pKey, pValue );
|
|
}
|
|
}
|
|
|
|
m_aJobData = aData;
|
|
copyJobDataToJobSetup( pJobSetup, aData );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void PspSalInfoPrinter::GetPageInfo(
|
|
const ImplJobSetup* pJobSetup,
|
|
long& rOutWidth, long& rOutHeight,
|
|
long& rPageOffX, long& rPageOffY,
|
|
long& rPageWidth, long& rPageHeight )
|
|
{
|
|
if( ! pJobSetup )
|
|
return;
|
|
|
|
JobData aData;
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
|
|
// get the selected page size
|
|
if( aData.m_pParser )
|
|
{
|
|
|
|
OUString aPaper;
|
|
int width, height;
|
|
int left = 0, top = 0, right = 0, bottom = 0;
|
|
int nDPI = aData.m_aContext.getRenderResolution();
|
|
|
|
if( aData.m_eOrientation == psp::orientation::Portrait )
|
|
{
|
|
aData.m_aContext.getPageSize( aPaper, width, height );
|
|
aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
|
|
}
|
|
else
|
|
{
|
|
aData.m_aContext.getPageSize( aPaper, height, width );
|
|
aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
|
|
}
|
|
|
|
rPageWidth = width * nDPI / 72;
|
|
rPageHeight = height * nDPI / 72;
|
|
rPageOffX = left * nDPI / 72;
|
|
rPageOffY = top * nDPI / 72;
|
|
rOutWidth = ( width - left - right ) * nDPI / 72;
|
|
rOutHeight = ( height - top - bottom ) * nDPI / 72;
|
|
}
|
|
}
|
|
|
|
sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
|
|
{
|
|
if( ! pJobSetup )
|
|
return 0;
|
|
|
|
JobData aData;
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
|
|
const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString("InputSlot") ): NULL;
|
|
return pKey ? pKey->countValues() : 0;
|
|
}
|
|
|
|
OUString PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
|
|
{
|
|
JobData aData;
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
|
|
OUString aRet;
|
|
if( aData.m_pParser )
|
|
{
|
|
const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString("InputSlot") ): NULL;
|
|
if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
|
|
aRet = aData.m_pParser->getDefaultInputSlot();
|
|
else
|
|
{
|
|
const PPDValue* pValue = pKey->getValue( nPaperBin );
|
|
if( pValue )
|
|
aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
|
|
}
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, PrinterCapType nType )
|
|
{
|
|
switch( nType )
|
|
{
|
|
case PrinterCapType::SupportDialog:
|
|
return 1;
|
|
case PrinterCapType::Copies:
|
|
return 0xffff;
|
|
case PrinterCapType::CollateCopies:
|
|
{
|
|
// PPDs don't mention the number of possible collated copies.
|
|
// so let's guess as many as we want ?
|
|
return 0xffff;
|
|
}
|
|
case PrinterCapType::SetOrientation:
|
|
return 1;
|
|
case PrinterCapType::SetDuplex:
|
|
return 1;
|
|
case PrinterCapType::SetPaperBin:
|
|
return 1;
|
|
case PrinterCapType::SetPaperSize:
|
|
return 1;
|
|
case PrinterCapType::SetPaper:
|
|
return 0;
|
|
case PrinterCapType::Fax:
|
|
{
|
|
// see if the PPD contains the fax4CUPS "Dial" option and that it's not set
|
|
// to "manually"
|
|
JobData aData = PrinterInfoManager::get().getPrinterInfo(pJobSetup->maPrinterName);
|
|
if( pJobSetup->mpDriverData )
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey(OUString("Dial")) : NULL;
|
|
const PPDValue* pValue = pKey ? aData.m_aContext.getValue(pKey) : NULL;
|
|
if (pValue && !pValue->m_aOption.equalsIgnoreAsciiCase("Manually"))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
case PrinterCapType::PDF:
|
|
if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
|
|
return 1;
|
|
else
|
|
{
|
|
// see if the PPD contains a value to set PDF device
|
|
JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
|
|
if( pJobSetup->mpDriverData )
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
return aData.m_nPDFDevice > 0 ? 1 : 0;
|
|
}
|
|
case PrinterCapType::ExternalDialog:
|
|
return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
|
|
case PrinterCapType::UsePullModel:
|
|
{
|
|
// see if the PPD contains a value to set PDF device
|
|
JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
|
|
if( pJobSetup->mpDriverData )
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
|
|
return aData.m_nPDFDevice > 0 ? 1 : 0;
|
|
}
|
|
default: break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* SalPrinter
|
|
*/
|
|
PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
|
|
: m_bPdf( false ),
|
|
m_bIsPDFWriterJob( false ),
|
|
m_pGraphics( NULL ),
|
|
m_nCopies( 1 ),
|
|
m_bCollate( false ),
|
|
m_pInfoPrinter( pInfoPrinter )
|
|
{
|
|
}
|
|
|
|
PspSalPrinter::~PspSalPrinter()
|
|
{
|
|
}
|
|
|
|
static OUString getTmpName()
|
|
{
|
|
OUString aTmp, aSys;
|
|
osl_createTempFile( NULL, NULL, &aTmp.pData );
|
|
osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
|
|
|
|
return aSys;
|
|
}
|
|
|
|
bool PspSalPrinter::StartJob(
|
|
const OUString* pFileName,
|
|
const OUString& rJobName,
|
|
const OUString& rAppName,
|
|
sal_uLong nCopies,
|
|
bool bCollate,
|
|
bool bDirect,
|
|
ImplJobSetup* pJobSetup )
|
|
{
|
|
OSL_TRACE("PspSalPrinter::StartJob");
|
|
GetSalData()->m_pInstance->jobStartedPrinterUpdate();
|
|
m_bPdf = false;
|
|
if (pFileName)
|
|
m_aFileName = *pFileName;
|
|
else
|
|
m_aFileName.clear();
|
|
m_aTmpFile.clear();
|
|
m_nCopies = nCopies;
|
|
m_bCollate = bCollate;
|
|
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
|
|
if( m_nCopies > 1 )
|
|
{
|
|
// in case user did not do anything (m_nCopies=1)
|
|
// take the default from jobsetup
|
|
m_aJobData.m_nCopies = m_nCopies;
|
|
m_aJobData.setCollate( bCollate );
|
|
}
|
|
|
|
int nMode = 0;
|
|
#if defined( UNX )
|
|
// check whether this printer is configured as fax
|
|
sal_Int32 nIndex = 0;
|
|
const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
|
|
while( nIndex != -1 )
|
|
{
|
|
OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
|
|
if( aToken.startsWith( "pdf=" ) )
|
|
{
|
|
m_bPdf = true;
|
|
m_aTmpFile = getTmpName();
|
|
nMode = S_IRUSR | S_IWUSR;
|
|
|
|
if( m_aFileName.isEmpty() )
|
|
{
|
|
OUStringBuffer aFileName( getPdfDir( rInfo ) );
|
|
aFileName.append( '/' );
|
|
aFileName.append( rJobName );
|
|
aFileName.appendAscii( ".pdf" );
|
|
m_aFileName = aFileName.makeStringAndClear();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
m_aPrinterGfx.Init( m_aJobData );
|
|
|
|
return m_aPrintJob.StartJob( ! m_aTmpFile.isEmpty() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect );
|
|
}
|
|
|
|
bool PspSalPrinter::EndJob()
|
|
{
|
|
bool bSuccess = false;
|
|
if( m_bIsPDFWriterJob )
|
|
bSuccess = true;
|
|
else
|
|
{
|
|
bSuccess = m_aPrintJob.EndJob();
|
|
OSL_TRACE("PspSalPrinter::EndJob %d", bSuccess);
|
|
|
|
if( bSuccess && m_bPdf )
|
|
{
|
|
const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
|
|
bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
|
|
}
|
|
}
|
|
GetSalData()->m_pInstance->jobEndedPrinterUpdate();
|
|
return bSuccess;
|
|
}
|
|
|
|
bool PspSalPrinter::AbortJob()
|
|
{
|
|
bool bAbort = m_aPrintJob.AbortJob();
|
|
GetSalData()->m_pInstance->jobEndedPrinterUpdate();
|
|
return bAbort;
|
|
}
|
|
|
|
SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, bool )
|
|
{
|
|
OSL_TRACE("PspSalPrinter::StartPage");
|
|
|
|
JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
|
|
m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
|
|
m_pGraphics->Init(&m_aJobData, &m_aPrinterGfx, m_pInfoPrinter);
|
|
|
|
if( m_nCopies > 1 )
|
|
{
|
|
// in case user did not do anything (m_nCopies=1)
|
|
// take the default from jobsetup
|
|
m_aJobData.m_nCopies = m_nCopies;
|
|
m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
|
|
}
|
|
|
|
m_aPrintJob.StartPage( m_aJobData );
|
|
m_aPrinterGfx.Init( m_aPrintJob );
|
|
|
|
return m_pGraphics;
|
|
}
|
|
|
|
bool PspSalPrinter::EndPage()
|
|
{
|
|
bool bResult = m_aPrintJob.EndPage();
|
|
m_aPrinterGfx.Clear();
|
|
OSL_TRACE("PspSalPrinter::EndPage");
|
|
return bResult;
|
|
}
|
|
|
|
sal_uLong PspSalPrinter::GetErrorCode()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
struct PDFNewJobParameters
|
|
{
|
|
Size maPageSize;
|
|
sal_uInt16 mnPaperBin;
|
|
|
|
PDFNewJobParameters( const Size& i_rSize = Size(),
|
|
sal_uInt16 i_nPaperBin = 0xffff )
|
|
: maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
|
|
|
|
bool operator==(const PDFNewJobParameters& rComp ) const
|
|
{
|
|
const long nRotatedWidth = rComp.maPageSize.Height();
|
|
const long nRotatedHeight = rComp.maPageSize.Width();
|
|
Size aCompLSSize(nRotatedWidth, nRotatedHeight);
|
|
return
|
|
(maPageSize == rComp.maPageSize || maPageSize == aCompLSSize)
|
|
&& mnPaperBin == rComp.mnPaperBin
|
|
;
|
|
}
|
|
|
|
bool operator!=(const PDFNewJobParameters& rComp) const
|
|
{
|
|
return ! this->operator==(rComp);
|
|
}
|
|
};
|
|
|
|
struct PDFPrintFile
|
|
{
|
|
OUString maTmpURL;
|
|
PDFNewJobParameters maParameters;
|
|
|
|
PDFPrintFile( const OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
|
|
: maTmpURL( i_rURL )
|
|
, maParameters( i_rNewParameters ) {}
|
|
};
|
|
|
|
bool PspSalPrinter::StartJob( const OUString* i_pFileName, const OUString& i_rJobName, const OUString& i_rAppName,
|
|
ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
|
|
{
|
|
OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
|
|
// mark for endjob
|
|
m_bIsPDFWriterJob = true;
|
|
// reset IsLastPage
|
|
i_rController.setLastPage( false );
|
|
// is this a fax device
|
|
bool bFax = m_pInfoPrinter->GetCapabilities(i_pSetupData, PrinterCapType::Fax) == 1;
|
|
|
|
// update job data
|
|
if( i_pSetupData )
|
|
JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
|
|
|
|
OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
|
|
m_aJobData.m_nPDFDevice = 1;
|
|
|
|
// possibly create one job for collated output
|
|
bool bSinglePrintJobs = false;
|
|
beans::PropertyValue* pSingleValue = i_rController.getValue( OUString( "PrintCollateAsSingleJobs" ) );
|
|
if( pSingleValue )
|
|
{
|
|
pSingleValue->Value >>= bSinglePrintJobs;
|
|
}
|
|
|
|
int nCopies = i_rController.getPrinter()->GetCopyCount();
|
|
bool bCollate = i_rController.getPrinter()->IsCollateCopy();
|
|
|
|
// notify start of real print job
|
|
i_rController.jobStarted();
|
|
|
|
// setup PDFWriter context
|
|
vcl::PDFWriter::PDFWriterContext aContext;
|
|
aContext.Version = vcl::PDFWriter::PDF_1_4;
|
|
aContext.Tagged = false;
|
|
aContext.DocumentLocale = Application::GetSettings().GetLanguageTag().getLocale();
|
|
aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
|
|
? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
|
|
|
|
// prepare doc info
|
|
aContext.DocumentInfo.Title = i_rJobName;
|
|
aContext.DocumentInfo.Creator = i_rAppName;
|
|
aContext.DocumentInfo.Producer = i_rAppName;
|
|
|
|
// define how we handle metafiles in PDFWriter
|
|
vcl::PDFWriter::PlayMetafileContext aMtfContext;
|
|
aMtfContext.m_bOnlyLosslessCompression = true;
|
|
|
|
std::shared_ptr<vcl::PDFWriter> xWriter;
|
|
std::vector< PDFPrintFile > aPDFFiles;
|
|
VclPtr<Printer> xPrinter( i_rController.getPrinter() );
|
|
int nAllPages = i_rController.getFilteredPageCount();
|
|
i_rController.createProgressDialog();
|
|
bool bAborted = false;
|
|
PDFNewJobParameters aLastParm;
|
|
|
|
aContext.DPIx = xPrinter->GetDPIX();
|
|
aContext.DPIy = xPrinter->GetDPIY();
|
|
for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
|
|
{
|
|
if( nPage == nAllPages-1 )
|
|
i_rController.setLastPage( true );
|
|
|
|
// get the page's metafile
|
|
GDIMetaFile aPageFile;
|
|
vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
|
|
if( i_rController.isProgressCanceled() )
|
|
{
|
|
bAborted = true;
|
|
if( nPage != nAllPages-1 )
|
|
{
|
|
i_rController.createProgressDialog();
|
|
i_rController.setLastPage( true );
|
|
i_rController.getFilteredPageFile( nPage, aPageFile );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
|
|
xPrinter->SetPaperSizeUser( aPageSize.aSize, true );
|
|
PDFNewJobParameters aNewParm(xPrinter->GetPaperSize(), xPrinter->GetPaperBin());
|
|
|
|
// create PDF writer on demand
|
|
// either on first page
|
|
// or on paper format change - cups does not support multiple paper formats per job (yet?)
|
|
// so we need to start a new job to get a new paper format from the printer
|
|
// orientation switches (that is switch of height and width) is handled transparently by CUPS
|
|
if( ! xWriter ||
|
|
(aNewParm != aLastParm && ! i_pFileName ) )
|
|
{
|
|
if( xWriter )
|
|
{
|
|
xWriter->Emit();
|
|
}
|
|
// produce PDF file
|
|
OUString aPDFUrl;
|
|
if( i_pFileName )
|
|
aPDFUrl = *i_pFileName;
|
|
else
|
|
osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
|
|
// normalize to file URL
|
|
if( !aPDFUrl.startsWith( "file:" ) )
|
|
{
|
|
// this is not a file URL, but it should
|
|
// form it into a osl friendly file URL
|
|
OUString aTmp;
|
|
osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
|
|
aPDFUrl = aTmp;
|
|
}
|
|
// save current file and paper format
|
|
aLastParm = aNewParm;
|
|
aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
|
|
// update context
|
|
aContext.URL = aPDFUrl;
|
|
|
|
// create and initialize PDFWriter
|
|
xWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
|
|
}
|
|
|
|
xWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
|
|
TenMuToPt( aNewParm.maPageSize.Height() ),
|
|
vcl::PDFWriter::Portrait );
|
|
|
|
xWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
|
|
}
|
|
}
|
|
|
|
// emit the last file
|
|
if( xWriter )
|
|
xWriter->Emit();
|
|
|
|
// handle collate, copy count and multiple jobs correctly
|
|
int nOuterJobs = 1;
|
|
if( bSinglePrintJobs )
|
|
{
|
|
nOuterJobs = nCopies;
|
|
m_aJobData.m_nCopies = 1;
|
|
}
|
|
else
|
|
{
|
|
if( bCollate )
|
|
{
|
|
if (aPDFFiles.size() == 1 && xPrinter->HasSupport(SUPPORT_COLLATECOPY))
|
|
{
|
|
m_aJobData.setCollate( true );
|
|
m_aJobData.m_nCopies = nCopies;
|
|
}
|
|
else
|
|
{
|
|
nOuterJobs = nCopies;
|
|
m_aJobData.m_nCopies = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_aJobData.setCollate( false );
|
|
m_aJobData.m_nCopies = nCopies;
|
|
}
|
|
}
|
|
|
|
std::vector<OUString> aFaxNumbers;
|
|
|
|
// check for fax numbers
|
|
if (!bAborted && bFax)
|
|
{
|
|
aFaxNumbers = getFaxNumbers();
|
|
bAborted = aFaxNumbers.empty();
|
|
}
|
|
|
|
bool bSuccess(true);
|
|
// spool files
|
|
if( ! i_pFileName && ! bAborted )
|
|
{
|
|
do
|
|
{
|
|
OUString sFaxNumber;
|
|
if (!aFaxNumbers.empty())
|
|
{
|
|
sFaxNumber = aFaxNumbers.back();
|
|
aFaxNumbers.pop_back();
|
|
}
|
|
|
|
bool bFirstJob = true;
|
|
for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
|
|
{
|
|
for( size_t i = 0; i < aPDFFiles.size(); i++ )
|
|
{
|
|
oslFileHandle pFile = NULL;
|
|
osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
|
|
if (pFile && (osl_setFilePos(pFile, osl_Pos_Absolut, 0) == osl_File_E_None))
|
|
{
|
|
std::vector< char > buffer( 0x10000, 0 );
|
|
// update job data with current page size
|
|
Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
|
|
m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
|
|
// update job data with current paperbin
|
|
m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
|
|
|
|
// spool current file
|
|
FILE* fp = PrinterInfoManager::get().startSpool(xPrinter->GetName(), i_rController.isDirectPrint());
|
|
if( fp )
|
|
{
|
|
sal_uInt64 nBytesRead = 0;
|
|
do
|
|
{
|
|
osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
|
|
if( nBytesRead > 0 )
|
|
{
|
|
size_t nBytesWritten = fwrite(&buffer[0], 1, nBytesRead, fp);
|
|
OSL_ENSURE(nBytesRead == nBytesWritten, "short write");
|
|
if (nBytesRead != nBytesWritten)
|
|
break;
|
|
}
|
|
} while( nBytesRead == buffer.size() );
|
|
OUStringBuffer aBuf( i_rJobName.getLength() + 8 );
|
|
aBuf.append( i_rJobName );
|
|
if( i > 0 || nCurJob > 0 )
|
|
{
|
|
aBuf.append( ' ' );
|
|
aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
|
|
}
|
|
bSuccess &=
|
|
PrinterInfoManager::get().endSpool(xPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob, sFaxNumber);
|
|
bFirstJob = false;
|
|
}
|
|
}
|
|
osl_closeFile( pFile );
|
|
}
|
|
}
|
|
}
|
|
while (!aFaxNumbers.empty());
|
|
}
|
|
|
|
// job has been spooled
|
|
i_rController.setJobState( (bAborted)
|
|
? view::PrintableState_JOB_ABORTED
|
|
: ((bSuccess) ? view::PrintableState_JOB_SPOOLED
|
|
: view::PrintableState_JOB_SPOOLING_FAILED));
|
|
|
|
// clean up the temporary PDF files
|
|
if( ! i_pFileName || bAborted )
|
|
{
|
|
for( size_t i = 0; i < aPDFFiles.size(); i++ )
|
|
{
|
|
osl_removeFile( aPDFFiles[i].maTmpURL.pData );
|
|
OSL_TRACE( "removed print PDF file %s", OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
class PrinterUpdate
|
|
{
|
|
static Idle* pPrinterUpdateIdle;
|
|
static int nActiveJobs;
|
|
|
|
static void doUpdate();
|
|
DECL_STATIC_LINK_TYPED( PrinterUpdate, UpdateTimerHdl, Idle*, void );
|
|
public:
|
|
static void update(SalGenericInstance &rInstance);
|
|
static void jobStarted() { nActiveJobs++; }
|
|
static void jobEnded();
|
|
};
|
|
|
|
Idle* PrinterUpdate::pPrinterUpdateIdle = NULL;
|
|
int PrinterUpdate::nActiveJobs = 0;
|
|
|
|
void PrinterUpdate::doUpdate()
|
|
{
|
|
::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
|
|
SalGenericInstance *pInst = static_cast<SalGenericInstance *>( GetSalData()->m_pInstance );
|
|
if( pInst && rManager.checkPrintersChanged( false ) )
|
|
pInst->PostPrintersChanged();
|
|
}
|
|
|
|
IMPL_STATIC_LINK_NOARG_TYPED( PrinterUpdate, UpdateTimerHdl, Idle*, void )
|
|
{
|
|
if( nActiveJobs < 1 )
|
|
{
|
|
doUpdate();
|
|
delete pPrinterUpdateIdle;
|
|
pPrinterUpdateIdle = NULL;
|
|
}
|
|
else
|
|
pPrinterUpdateIdle->Start();
|
|
}
|
|
|
|
void PrinterUpdate::update(SalGenericInstance &rInstance)
|
|
{
|
|
if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
|
|
return;
|
|
|
|
if( ! rInstance.isPrinterInit() )
|
|
{
|
|
// #i45389# start background printer detection
|
|
psp::PrinterInfoManager::get();
|
|
return;
|
|
}
|
|
|
|
if( nActiveJobs < 1 )
|
|
doUpdate();
|
|
else if( ! pPrinterUpdateIdle )
|
|
{
|
|
pPrinterUpdateIdle = new Idle();
|
|
pPrinterUpdateIdle->SetPriority( SchedulerPriority::LOWEST );
|
|
pPrinterUpdateIdle->SetIdleHdl( LINK( NULL, PrinterUpdate, UpdateTimerHdl ) );
|
|
pPrinterUpdateIdle->Start();
|
|
}
|
|
}
|
|
|
|
void SalGenericInstance::updatePrinterUpdate()
|
|
{
|
|
PrinterUpdate::update(*this);
|
|
}
|
|
|
|
void SalGenericInstance::jobStartedPrinterUpdate()
|
|
{
|
|
PrinterUpdate::jobStarted();
|
|
}
|
|
|
|
void PrinterUpdate::jobEnded()
|
|
{
|
|
nActiveJobs--;
|
|
if( nActiveJobs < 1 )
|
|
{
|
|
if( pPrinterUpdateIdle )
|
|
{
|
|
pPrinterUpdateIdle->Stop();
|
|
delete pPrinterUpdateIdle;
|
|
pPrinterUpdateIdle = NULL;
|
|
doUpdate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SalGenericInstance::jobEndedPrinterUpdate()
|
|
{
|
|
PrinterUpdate::jobEnded();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|