diff options
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r-- | vcl/source/gdi/bmpconv.cxx | 3 | ||||
-rw-r--r-- | vcl/source/gdi/gdimtf.cxx | 34 | ||||
-rw-r--r-- | vcl/source/gdi/impprn.cxx | 2 | ||||
-rw-r--r-- | vcl/source/gdi/jobset.cxx | 26 | ||||
-rw-r--r--[-rwxr-xr-x] | vcl/source/gdi/makefile.mk | 4 | ||||
-rw-r--r-- | vcl/source/gdi/oldprintadaptor.cxx | 117 | ||||
-rw-r--r-- | vcl/source/gdi/print.cxx | 484 | ||||
-rw-r--r-- | vcl/source/gdi/print2.cxx | 35 | ||||
-rw-r--r-- | vcl/source/gdi/print3.cxx | 1765 | ||||
-rw-r--r-- | vcl/source/gdi/virdev.cxx | 29 |
10 files changed, 2152 insertions, 347 deletions
diff --git a/vcl/source/gdi/bmpconv.cxx b/vcl/source/gdi/bmpconv.cxx index 9d9b81ba50d4..03d85acb0159 100644 --- a/vcl/source/gdi/bmpconv.cxx +++ b/vcl/source/gdi/bmpconv.cxx @@ -192,7 +192,8 @@ BmpTransporter::BmpTransporter( const Bitmap& rBM ) m_aSize.Height = rBM.GetSizePixel().Height(); SvMemoryStream aStream; rBM.Write( aStream, FALSE, TRUE ); - m_aBM = Sequence<sal_Int8>((const sal_Int8*)aStream.GetData(), aStream.GetSize() ); + m_aBM = Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()), + aStream.GetEndOfData()); } BmpTransporter::~BmpTransporter() diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index 6483c8292df7..951d80f9af9d 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -876,6 +876,40 @@ void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY ) // ------------------------------------------------------------------------ +void GDIMetaFile::Clip( const Rectangle& i_rClipRect ) +{ + Rectangle aCurRect( i_rClipRect ); + VirtualDevice aMapVDev; + + aMapVDev.EnableOutput( FALSE ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() ) + { + const long nType = pAct->GetType(); + + if( ( META_MAPMODE_ACTION == nType ) || + ( META_PUSH_ACTION == nType ) || + ( META_POP_ACTION == nType ) ) + { + pAct->Execute( &aMapVDev ); + aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() ); + } + else if( nType == META_CLIPREGION_ACTION ) + { + MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct; + Region aNewReg( aCurRect ); + if( pOldAct->IsClipping() ) + aNewReg.Intersect( pOldAct->GetRegion() ); + MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, TRUE ); + Replace( pNewAct, GetCurPos() ); + pOldAct->Delete(); + } + } +} + +// ------------------------------------------------------------------------ + Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt, const Size& rOffset, double fSin, double fCos ) { diff --git a/vcl/source/gdi/impprn.cxx b/vcl/source/gdi/impprn.cxx index 539c879c89ea..28d92a0b3832 100644 --- a/vcl/source/gdi/impprn.cxx +++ b/vcl/source/gdi/impprn.cxx @@ -478,10 +478,12 @@ void ImplQPrinter::EndQueuePrint() DBG_ASSERT( mpPrinter, "no SalPrinter in ImplQPrinter" ); if( mpPrinter ) { + #if 0 mpPrinter->StartJob( mbPrintFile ? &maPrintFile : NULL, Application::GetDisplayName(), maJobSetup.ImplGetConstData(), this ); + #endif EndJob(); mpParent->ImplEndPrint(); } diff --git a/vcl/source/gdi/jobset.cxx b/vcl/source/gdi/jobset.cxx index 686d33593466..4823a5492ded 100644 --- a/vcl/source/gdi/jobset.cxx +++ b/vcl/source/gdi/jobset.cxx @@ -73,6 +73,7 @@ ImplJobSetup::ImplJobSetup() mnRefCount = 1; mnSystem = 0; meOrientation = ORIENTATION_PORTRAIT; + meDuplexMode = DUPLEX_UNKNOWN; mnPaperBin = 0; mePaperFormat = PAPER_USER; mnPaperWidth = 0; @@ -90,6 +91,7 @@ ImplJobSetup::ImplJobSetup( const ImplJobSetup& rJobSetup ) : mnRefCount = 1; mnSystem = rJobSetup.mnSystem; meOrientation = rJobSetup.meOrientation; + meDuplexMode = rJobSetup.meDuplexMode; mnPaperBin = rJobSetup.mnPaperBin; mePaperFormat = rJobSetup.mePaperFormat; mnPaperWidth = rJobSetup.mnPaperWidth; @@ -277,6 +279,7 @@ BOOL JobSetup::operator==( const JobSetup& rJobSetup ) const (pData1->maPrinterName == pData2->maPrinterName) && (pData1->maDriver == pData2->maDriver) && (pData1->meOrientation == pData2->meOrientation) && + (pData1->meDuplexMode == pData2->meDuplexMode) && (pData1->mnPaperBin == pData2->mnPaperBin) && (pData1->mePaperFormat == pData2->mePaperFormat) && (pData1->mnPaperWidth == pData2->mnPaperWidth) && @@ -337,6 +340,7 @@ SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup ) pJobData->mnSystem = SVBT16ToShort( pOldJobData->nSystem ); pJobData->mnDriverDataLen = SVBT32ToUInt32( pOldJobData->nDriverDataLen ); pJobData->meOrientation = (Orientation)SVBT16ToShort( pOldJobData->nOrientation ); + pJobData->meDuplexMode = DUPLEX_UNKNOWN; pJobData->mnPaperBin = SVBT16ToShort( pOldJobData->nPaperBin ); pJobData->mePaperFormat = (Paper)SVBT16ToShort( pOldJobData->nPaperFormat ); pJobData->mnPaperWidth = (long)SVBT32ToUInt32( pOldJobData->nPaperWidth ); @@ -355,7 +359,19 @@ SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup ) String aKey, aValue; rIStream.ReadByteString( aKey, RTL_TEXTENCODING_UTF8 ); rIStream.ReadByteString( aValue, RTL_TEXTENCODING_UTF8 ); - pJobData->maValueMap[ aKey ] = aValue; + if( aKey.EqualsAscii( "COMPAT_DUPLEX_MODE" ) ) + { + if( aValue.EqualsAscii( "DUPLEX_UNKNOWN" ) ) + pJobData->meDuplexMode = DUPLEX_UNKNOWN; + else if( aValue.EqualsAscii( "DUPLEX_OFF" ) ) + pJobData->meDuplexMode = DUPLEX_OFF; + else if( aValue.EqualsAscii( "DUPLEX_SHORTEDGE" ) ) + pJobData->meDuplexMode = DUPLEX_SHORTEDGE; + else if( aValue.EqualsAscii( "DUPLEX_LONGEDGE" ) ) + pJobData->meDuplexMode = DUPLEX_LONGEDGE; + } + else + pJobData->maValueMap[ aKey ] = aValue; } DBG_ASSERT( rIStream.Tell() == nFirstPos+nLen, "corrupted job setup" ); // ensure correct stream position @@ -421,6 +437,14 @@ SvStream& operator<<( SvStream& rOStream, const JobSetup& rJobSetup ) rOStream.WriteByteString( it->first, RTL_TEXTENCODING_UTF8 ); rOStream.WriteByteString( it->second, RTL_TEXTENCODING_UTF8 ); } + rOStream.WriteByteString( "COMPAT_DUPLEX_MODE" ) ; + switch( pJobData->meDuplexMode ) + { + case DUPLEX_UNKNOWN: rOStream.WriteByteString( "DUPLEX_UNKNOWN" );break; + case DUPLEX_OFF: rOStream.WriteByteString( "DUPLEX_OFF" );break; + case DUPLEX_SHORTEDGE: rOStream.WriteByteString( "DUPLEX_SHORTEDGE" );break; + case DUPLEX_LONGEDGE: rOStream.WriteByteString( "DUPLEX_LONGEDGE" );break; + } nLen = sal::static_int_cast<USHORT>(rOStream.Tell() - nPos); rOStream.Seek( nPos ); rOStream << nLen; diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk index eda537bf629a..ed2a9b2ba1e1 100755..100644 --- a/vcl/source/gdi/makefile.mk +++ b/vcl/source/gdi/makefile.mk @@ -57,6 +57,8 @@ EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/gfxlink.obj \ $(SLO)$/print.obj \ $(SLO)$/print2.obj \ + $(SLO)$/print3.obj \ + $(SLO)$/oldprintadaptor.obj \ $(SLO)$/configsettings.obj \ $(SLO)$/sallayout.obj \ $(SLO)$/image.obj \ @@ -72,7 +74,6 @@ EXCEPTIONSFILES= $(SLO)$/salmisc.obj \ $(SLO)$/pngread.obj \ $(SLO)$/pngwrite.obj \ $(SLO)$/virdev.obj \ - $(SLO)$/impprn.obj \ $(SLO)$/gdimtf.obj \ $(SLO)$/graphictools.obj \ $(SLO)$/textlayout.obj \ @@ -118,6 +119,7 @@ SLOFILES= $(EXCEPTIONSFILES) \ $(SLO)$/extoutdevdata.obj \ $(SLO)$/salnativewidgets-none.obj + # --- Targets ------------------------------------------------------ .INCLUDE : target.mk diff --git a/vcl/source/gdi/oldprintadaptor.cxx b/vcl/source/gdi/oldprintadaptor.cxx new file mode 100644 index 000000000000..cffd11daaad6 --- /dev/null +++ b/vcl/source/gdi/oldprintadaptor.cxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/oldprintadaptor.hxx" +#include "vcl/gdimtf.hxx" + +#include "com/sun/star/awt/Size.hpp" + +#include <vector> + +namespace vcl +{ + struct AdaptorPage + { + GDIMetaFile maPage; + com::sun::star::awt::Size maPageSize; + }; + + struct ImplOldStyleAdaptorData + { + std::vector< AdaptorPage > maPages; + }; +} + +using namespace vcl; +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; + +OldStylePrintAdaptor::OldStylePrintAdaptor( const boost::shared_ptr< Printer >& i_pPrinter ) + : PrinterController( i_pPrinter ) + , mpData( new ImplOldStyleAdaptorData() ) +{ +} + +OldStylePrintAdaptor::~OldStylePrintAdaptor() +{ +} + +void OldStylePrintAdaptor::StartPage() +{ + Size aPaperSize( getPrinter()->PixelToLogic( getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + mpData->maPages.push_back( AdaptorPage() ); + mpData->maPages.back().maPageSize.Width = aPaperSize.getWidth(); + mpData->maPages.back().maPageSize.Height = aPaperSize.getHeight(); + getPrinter()->SetConnectMetaFile( &mpData->maPages.back().maPage ); + + // copy state into metafile + boost::shared_ptr<Printer> pPrinter( getPrinter() ); + pPrinter->SetMapMode( pPrinter->GetMapMode() ); + pPrinter->SetFont( pPrinter->GetFont() ); + pPrinter->SetDrawMode( pPrinter->GetDrawMode() ); + pPrinter->SetLineColor( pPrinter->GetLineColor() ); + pPrinter->SetFillColor( pPrinter->GetFillColor() ); +} + +void OldStylePrintAdaptor::EndPage() +{ + getPrinter()->SetConnectMetaFile( NULL ); + mpData->maPages.back().maPage.WindStart(); +} + +int OldStylePrintAdaptor::getPageCount() const +{ + return int(mpData->maPages.size()); +} + +Sequence< PropertyValue > OldStylePrintAdaptor::getPageParameters( int i_nPage ) const +{ + Sequence< PropertyValue > aRet( 1 ); + aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("PageSize") ); + if( i_nPage < int(mpData->maPages.size() ) ) + aRet[0].Value = makeAny( mpData->maPages[i_nPage].maPageSize ); + else + { + awt::Size aEmpty( 0, 0 ); + aRet[0].Value = makeAny( aEmpty ); + } + return aRet; +} + +void OldStylePrintAdaptor::printPage( int i_nPage ) const +{ + if( i_nPage < int(mpData->maPages.size()) ) + { + mpData->maPages[ i_nPage ].maPage.WindStart(); + mpData->maPages[ i_nPage ].maPage.Play( getPrinter().get() ); + } +} + diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index 937d966b3978..16f6b53af7a8 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: print.cxx,v $ - * $Revision: 1.65 $ + * $Revision: 1.65.114.1 $ * * This file is part of OpenOffice.org. * @@ -31,8 +31,6 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#define _SPOOLPRINTER_EXT -#define _RMPRINTER_EXT #define ENABLE_BYTESTRING_STREAM_OPERATORS #include <list> @@ -58,7 +56,6 @@ #include <vcl/print.h> #include <vcl/gdimtf.hxx> #include <vcl/metaact.hxx> -#include <vcl/impprn.hxx> #include <vcl/print.hxx> #include <comphelper/processfactory.hxx> @@ -280,7 +277,9 @@ static void ImplInitPrnQueueList() pSVData->maGDIData.mpPrinterQueueList = new ImplPrnQueueList; - pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList ); + static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" ); + if( !pEnv || !*pEnv ) + pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList ); } // ----------------------------------------------------------------------- @@ -339,16 +338,20 @@ const QueueInfo* Printer::GetQueueInfo( const String& rPrinterName, bool bStatus XubString Printer::GetDefaultPrinterName() { - ImplSVData* pSVData = ImplGetSVData(); + static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" ); + if( !pEnv || !*pEnv ) + { + ImplSVData* pSVData = ImplGetSVData(); - return pSVData->mpDefInst->GetDefaultPrinter(); + return pSVData->mpDefInst->GetDefaultPrinter(); + } + return XubString(); } // ======================================================================= void Printer::ImplInitData() { - mpPrinterData = new ImplPrivatePrinterData(); mbDevOutput = FALSE; meOutDevType = OUTDEV_PRINTER; mbDefPrinter = FALSE; @@ -366,8 +369,6 @@ void Printer::ImplInitData() mpInfoPrinter = NULL; mpPrinter = NULL; mpDisplayDev = NULL; - mpQPrinter = NULL; - mpQMtf = NULL; mbIsQueuePrinter = FALSE; mpPrinterOptions = new PrinterOptions; @@ -414,7 +415,6 @@ void Printer::ImplInit( SalPrinterQueueInfo* pInfo ) mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, pJobSetup ); mpPrinter = NULL; - mpJobPrinter = NULL; mpJobGraphics = NULL; ImplUpdateJobSetupPaper( maJobSetup ); @@ -446,7 +446,6 @@ void Printer::ImplInitDisplay( const Window* pWindow ) mpInfoPrinter = NULL; mpPrinter = NULL; - mpJobPrinter = NULL; mpJobGraphics = NULL; if ( pWindow ) @@ -518,6 +517,26 @@ void Printer::ImplUpdatePageData() mnOutWidth, mnOutHeight, maPageOffset.X(), maPageOffset.Y(), maPaperSize.Width(), maPaperSize.Height() ); + static const char* pDebugOffset = getenv( "SAL_DBG_PAGEOFFSET" ); + if( pDebugOffset ) + { + rtl::OString aLine( pDebugOffset ); + sal_Int32 nIndex = 0; + rtl::OString aToken( aLine.getToken( 0, ',', nIndex ) ); + sal_Int32 nLeft = aToken.toInt32(); + sal_Int32 nTop = nLeft; + if( nIndex > 0 ) + { + aToken = aLine.getToken( 0, ',', nIndex ); + nTop = aToken.toInt32(); + } + maPageOffset = LogicToPixel( Point( static_cast<long>(nLeft), + static_cast<long>(nTop) ), + MapMode( MAP_100TH_MM ) + ); + mnOutWidth = maPaperSize.Width() - 2*maPageOffset.X(); + mnOutWidth = maPaperSize.Width() - 2*maPageOffset.Y(); + } } // ----------------------------------------------------------------------- @@ -602,11 +621,6 @@ Printer::~Printer() { DBG_ASSERT( !IsPrinting(), "Printer::~Printer() - Job is printing" ); DBG_ASSERT( !IsJobActive(), "Printer::~Printer() - Job is active" ); - DBG_ASSERT( !mpQPrinter, "Printer::~Printer() - QueuePrinter not destroyed" ); - DBG_ASSERT( !mpQMtf, "Printer::~Printer() - QueueMetafile not destroyed" ); - - delete mpPrinterData; - mpPrinterData = NULL; delete mpPrinterOptions; @@ -653,21 +667,11 @@ Printer::~Printer() } // ----------------------------------------------------------------------- -void Printer::SetNextJobIsQuick( bool bQuick ) -{ - mpPrinterData->mbNextJobIsQuick = bQuick; - if( mpQPrinter ) - mpQPrinter->SetNextJobIsQuick( bQuick ); -} - -// ----------------------------------------------------------------------- void Printer::Compat_OldPrinterMetrics( bool bSet ) { // propagate flag if( mpInfoPrinter ) mpInfoPrinter->m_bCompatMetrics = bSet; - if( mpQPrinter ) - mpQPrinter->Compat_OldPrinterMetrics( bSet ); // get new font data ImplUpdateFontData( TRUE ); @@ -977,12 +981,13 @@ USHORT Printer::GetPaperBin() const // ----------------------------------------------------------------------- // Map user paper format to a available printer paper formats -void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) +void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup, bool bMatchNearest ) { ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); int nLandscapeAngle = GetLandscapeAngle(); int nPaperCount = GetPaperInfoCount(); + bool bFound = false; PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight); @@ -995,6 +1000,8 @@ void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) { pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(), rPaperInfo.getHeight() ); + pSetupData->meOrientation = ORIENTATION_PORTRAIT; + bFound = true; break; } } @@ -1017,10 +1024,49 @@ void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) { pSetupData->mePaperFormat = ImplGetPaperFormat( rPaperInfo.getWidth(), rPaperInfo.getHeight() ); + pSetupData->meOrientation = ORIENTATION_LANDSCAPE; + bFound = true; break; } } } + + if( ! bFound && bMatchNearest ) + { + sal_Int64 nBestMatch = SAL_MAX_INT64; + int nBestIndex = 0; + Orientation eBestOrientation = ORIENTATION_PORTRAIT; + for( int i = 0; i < nPaperCount; i++ ) + { + const PaperInfo& rPaperInfo = GetPaperInfo( i ); + + // check protrait match + sal_Int64 nDX = pSetupData->mnPaperWidth - rPaperInfo.getWidth(); + sal_Int64 nDY = pSetupData->mnPaperHeight - rPaperInfo.getHeight(); + sal_Int64 nMatch = nDX*nDX + nDY*nDY; + if( nMatch < nBestMatch ) + { + nBestMatch = nMatch; + nBestIndex = i; + eBestOrientation = ORIENTATION_PORTRAIT; + } + + // check landscape match + nDX = pSetupData->mnPaperWidth - rPaperInfo.getHeight(); + nDY = pSetupData->mnPaperHeight - rPaperInfo.getWidth(); + nMatch = nDX*nDX + nDY*nDY; + if( nMatch < nBestMatch ) + { + nBestMatch = nMatch; + nBestIndex = i; + eBestOrientation = ORIENTATION_LANDSCAPE; + } + } + const PaperInfo& rBestInfo = GetPaperInfo( nBestIndex ); + pSetupData->mePaperFormat = ImplGetPaperFormat( rBestInfo.getWidth(), + rBestInfo.getHeight() ); + pSetupData->meOrientation = eBestOrientation; + } } // ----------------------------------------------------------------------- @@ -1051,7 +1097,7 @@ BOOL Printer::SetPaper( Paper ePaper ) ImplReleaseGraphics(); if ( ePaper == PAPER_USER ) - ImplFindPaperFormatForUserSize( aJobSetup ); + ImplFindPaperFormatForUserSize( aJobSetup, false ); if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) ) { ImplUpdateJobSetupPaper( aJobSetup ); @@ -1072,6 +1118,11 @@ BOOL Printer::SetPaper( Paper ePaper ) BOOL Printer::SetPaperSizeUser( const Size& rSize ) { + return SetPaperSizeUser( rSize, false ); +} + +BOOL Printer::SetPaperSizeUser( const Size& rSize, bool bMatchNearest ) +{ if ( mbInPrintPage ) return FALSE; @@ -1095,7 +1146,7 @@ BOOL Printer::SetPaperSizeUser( const Size& rSize ) } ImplReleaseGraphics(); - ImplFindPaperFormatForUserSize( aJobSetup ); + ImplFindPaperFormatForUserSize( aJobSetup, bMatchNearest ); // Changing the paper size can also change the orientation! if ( mpInfoPrinter->SetData( SAL_JOBSET_PAPERSIZE|SAL_JOBSET_ORIENTATION, pSetupData ) ) @@ -1142,7 +1193,44 @@ const PaperInfo& Printer::GetPaperInfo( int nPaper ) const DuplexMode Printer::GetDuplexMode() const { - return mpInfoPrinter ? mpInfoPrinter->GetDuplexMode( maJobSetup.ImplGetConstData() ) : DUPLEX_UNKNOWN; + return maJobSetup.ImplGetConstData()->meDuplexMode; +} + +// ----------------------------------------------------------------------- + +BOOL Printer::SetDuplexMode( DuplexMode eDuplex ) +{ + if ( mbInPrintPage ) + return FALSE; + + if ( maJobSetup.ImplGetConstData()->meDuplexMode != eDuplex ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup* pSetupData = aJobSetup.ImplGetData(); + pSetupData->meDuplexMode = eDuplex; + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + return TRUE; + } + + ImplReleaseGraphics(); + if ( mpInfoPrinter->SetData( SAL_JOBSET_DUPLEXMODE, pSetupData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = TRUE; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return TRUE; + } + else + return FALSE; + } + + return TRUE; } // ----------------------------------------------------------------------- @@ -1184,9 +1272,10 @@ XubString Printer::GetPaperBinName( USHORT nPaperBin ) const // ----------------------------------------------------------------------- -BOOL Printer::SetCopyCount( USHORT nCopy, BOOL /*bCollate*/ ) +BOOL Printer::SetCopyCount( USHORT nCopy, BOOL bCollate ) { mnCopyCount = nCopy; + mbCollateCopy = bCollate; return TRUE; } @@ -1199,29 +1288,8 @@ void Printer::Error() // ----------------------------------------------------------------------- -void Printer::StartPrint() -{ - maStartPrintHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -void Printer::EndPrint() -{ - maEndPrintHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -void Printer::PrintPage() -{ - maPrintPageHdl.Call( this ); -} - -// ----------------------------------------------------------------------- - -ULONG ImplSalPrinterErrorCodeToVCL( ULONG nError ) +ULONG Printer::ImplSalPrinterErrorCodeToVCL( ULONG nError ) { ULONG nVCLError; switch ( nError ) @@ -1247,12 +1315,6 @@ void Printer::ImplEndPrint() mbPrinting = FALSE; mnCurPrintPage = 0; maJobName.Erase(); - if( mpQPrinter ) // not necessarily filled e.g. after AbortJob - { - mpQPrinter->Destroy(); - mpQPrinter = NULL; - } - EndPrint(); } // ----------------------------------------------------------------------- @@ -1267,180 +1329,6 @@ IMPL_LINK( Printer, ImplDestroyPrinterAsync, void*, pSalPrinter ) // ----------------------------------------------------------------------- -void Printer::ImplUpdateQuickStatus() -{ - // remove possibly added "IsQuickJob" - if( mpPrinterData->mbNextJobIsQuick ) - { - rtl::OUString aKey( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ); - // const data means not really const, but change all references - // to refcounted job setup - ImplJobSetup* pImpSetup = maJobSetup.ImplGetConstData(); - pImpSetup->maValueMap.erase( aKey ); - mpPrinterData->mbNextJobIsQuick = false; - } -} - -class QuickGuard -{ - Printer* mpPrinter; - public: - QuickGuard( Printer* pPrn ) : mpPrinter( pPrn ) {} - ~QuickGuard() - { - mpPrinter->ImplUpdateQuickStatus(); - } -}; - -BOOL Printer::StartJob( const XubString& rJobName ) -{ - mnError = PRINTER_OK; - - if ( IsDisplayPrinter() ) - return FALSE; - - if ( IsJobActive() || IsPrinting() ) - return FALSE; - - if( mpPrinterData->mbNextJobIsQuick ) - { - String aKey( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ); - if( maJobSetup.GetValue( aKey ).Len() == 0 ) - maJobSetup.SetValue( aKey, String( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) ); - } - - QuickGuard aQGuard( this ); - - ULONG nCopies = mnCopyCount; - BOOL bCollateCopy = mbCollateCopy; - BOOL bUserCopy = FALSE; - if ( IsQueuePrinter() ) - { - if ( ((ImplQPrinter*)this)->IsUserCopy() ) - { - nCopies = 1; - bCollateCopy = FALSE; - } - } - else - { - if ( nCopies > 1 ) - { - ULONG nDevCopy; - - if ( bCollateCopy ) - nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ); - else - nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES ); - - // Muessen Kopien selber gemacht werden? - if ( nCopies > nDevCopy ) - { - bUserCopy = TRUE; - nCopies = 1; - bCollateCopy = FALSE; - } - } - else - bCollateCopy = FALSE; - - // we need queue printing - if( !mnPageQueueSize ) - mnPageQueueSize = 1; - } - - if ( !mnPageQueueSize ) - { - ImplSVData* pSVData = ImplGetSVData(); - mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); - - if ( !mpPrinter ) - return FALSE; - - XubString* pPrintFile; - if ( mbPrintFile ) - pPrintFile = &maPrintFile; - else - pPrintFile = NULL; - - // #125075# StartJob can Reschedule on Windows, sfx - // depends on IsPrinting() in case of closing a document - BOOL bSaveNewJobSetup = mbNewJobSetup; - mbNewJobSetup = FALSE; - String aSaveJobName = maJobName; - maJobName = rJobName; - mnCurPage = 1; - mnCurPrintPage = 1; - mbPrinting = TRUE; - - if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel ) - { - // in the pull model the job can only be started when - // we have collected all pages to be printed - if ( !mpPrinter->StartJob( pPrintFile, rJobName, Application::GetDisplayName(), - nCopies, bCollateCopy, - maJobSetup.ImplGetConstData() ) ) - { - mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); - if ( !mnError ) - mnError = PRINTER_GENERALERROR; - pSVData->mpDefInst->DestroyPrinter( mpPrinter ); - mbNewJobSetup = bSaveNewJobSetup; - maJobName = aSaveJobName; - mnCurPage = 0; - mnCurPrintPage = 0; - mbPrinting = FALSE; - mpPrinter = NULL; - return FALSE; - } - } - - mbJobActive = TRUE; - StartPrint(); - } - else - { - mpQPrinter = new ImplQPrinter( this ); - if( mpInfoPrinter ) - mpQPrinter->Compat_OldPrinterMetrics( mpInfoPrinter->m_bCompatMetrics ); - mpQPrinter->SetDigitLanguage( GetDigitLanguage() ); - mpQPrinter->SetUserCopy( bUserCopy ); - mpQPrinter->SetPrinterOptions( *mpPrinterOptions ); - - // #125075# StartJob can Reschedule on Windows, sfx - // depends on IsPrinting() in case of closing a document - BOOL bSaveNewJobSetup = mbNewJobSetup; - mbNewJobSetup = FALSE; - String aSaveJobName = maJobName; - maJobName = rJobName; - mnCurPage = 1; - mbPrinting = TRUE; - - if ( mpQPrinter->StartJob( rJobName ) ) - { - mbJobActive = TRUE; - StartPrint(); - mpQPrinter->StartQueuePrint(); - } - else - { - mbNewJobSetup = bSaveNewJobSetup; - maJobName = aSaveJobName; - mnCurPage = 0; - mbPrinting = FALSE; - mnError = mpQPrinter->GetErrorCode(); - mpQPrinter->Destroy(); - mpQPrinter = NULL; - return FALSE; - } - } - - - return TRUE; -} - -// ----------------------------------------------------------------------- - BOOL Printer::EndJob() { BOOL bRet = FALSE; @@ -1451,7 +1339,7 @@ BOOL Printer::EndJob() mbJobActive = FALSE; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { ImplReleaseGraphics(); @@ -1459,23 +1347,17 @@ BOOL Printer::EndJob() bRet = TRUE; - if ( mpPrinter ) - { - mbPrinting = FALSE; - mnCurPrintPage = 0; - maJobName.Erase(); - - mbDevOutput = FALSE; - bRet = mpPrinter->EndJob(); - // Hier den Drucker nicht asyncron zerstoeren, da es - // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird - // und ein Druckerobjekt zerstoert wird - ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter ); - mpPrinter = NULL; - EndPrint(); - } - else - mpQPrinter->EndQueuePrint(); + mbPrinting = FALSE; + mnCurPrintPage = 0; + maJobName.Erase(); + + mbDevOutput = FALSE; + bRet = mpPrinter->EndJob(); + // Hier den Drucker nicht asyncron zerstoeren, da es + // W95 nicht verkraftet, wenn gleichzeitig gedruckt wird + // und ein Druckerobjekt zerstoert wird + ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter ); + mpPrinter = NULL; } return bRet; @@ -1494,35 +1376,18 @@ BOOL Printer::AbortJob() mbInPrintPage = FALSE; mpJobGraphics = NULL; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { mbPrinting = FALSE; mnCurPage = 0; mnCurPrintPage = 0; maJobName.Erase(); - if ( mpPrinter ) - { - ImplReleaseGraphics(); - mbDevOutput = FALSE; - mpPrinter->AbortJob(); - Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter ); - mpPrinter = NULL; - EndPrint(); - } - else - { - mpQPrinter->AbortQueuePrint(); - mpQPrinter->Destroy(); - mpQPrinter = NULL; - if ( mpQMtf ) - { - mpQMtf->Clear(); - delete mpQMtf; - mpQMtf = NULL; - } - EndPrint(); - } + ImplReleaseGraphics(); + mbDevOutput = FALSE; + mpPrinter->AbortJob(); + Application::PostUserEvent( LINK( this, Printer, ImplDestroyPrinterAsync ), mpPrinter ); + mpPrinter = NULL; return TRUE; } @@ -1532,88 +1397,49 @@ BOOL Printer::AbortJob() // ----------------------------------------------------------------------- -BOOL Printer::StartPage() +void Printer::ImplStartPage() { if ( !IsJobActive() ) - return FALSE; + return; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { - if ( mpPrinter ) - { - SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup ); - if ( pGraphics ) - { - ImplReleaseGraphics(); - mpJobGraphics = pGraphics; - } - mbDevOutput = TRUE; - } - else + SalGraphics* pGraphics = mpPrinter->StartPage( maJobSetup.ImplGetConstData(), mbNewJobSetup ); + if ( pGraphics ) { - ImplGetGraphics(); - mpJobGraphics = mpGraphics; + ImplReleaseGraphics(); + mpJobGraphics = pGraphics; } + mbDevOutput = TRUE; // PrintJob not aborted ??? if ( IsJobActive() ) { mbInPrintPage = TRUE; mnCurPage++; - if ( mpQPrinter ) - { - mpQPrinter->SetPrinterOptions( *mpPrinterOptions ); - mpQMtf = new GDIMetaFile; - mpQMtf->Record( this ); - mpQMtf->SaveStatus(); - } - else - { - mnCurPrintPage++; - PrintPage(); - } + mnCurPrintPage++; } - - return TRUE; } - - return FALSE; } // ----------------------------------------------------------------------- -BOOL Printer::EndPage() +void Printer::ImplEndPage() { if ( !IsJobActive() ) - return FALSE; + return; mbInPrintPage = FALSE; - if ( mpPrinter || mpQPrinter ) + if ( mpPrinter ) { - if ( mpPrinter ) - { - mpPrinter->EndPage(); - ImplReleaseGraphics(); - mbDevOutput = FALSE; - } - else if ( mpQPrinter ) - { - // Eigentuemeruebergang an QPrinter - mpQMtf->Stop(); - mpQMtf->WindStart(); - GDIMetaFile* pPage = mpQMtf; - mpQMtf = NULL; - mpQPrinter->AddQueuePage( pPage, mnCurPage, mbNewJobSetup ); - } + mpPrinter->EndPage(); + ImplReleaseGraphics(); + mbDevOutput = FALSE; mpJobGraphics = NULL; mbNewJobSetup = FALSE; - - return TRUE; } - - return FALSE; } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx index 685f68fe7af3..9d435af5f4b1 100644 --- a/vcl/source/gdi/print2.cxx +++ b/vcl/source/gdi/print2.cxx @@ -31,8 +31,6 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#define _SPOOLPRINTER_EXT - #include <functional> #include <algorithm> #include <utility> @@ -648,7 +646,9 @@ static bool ImplIsActionHandlingTransparency( const MetaAction& rAct ) bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf, long nMaxBmpDPIX, long nMaxBmpDPIY, bool bReduceTransparency, bool bTransparencyAutoMode, - bool bDownsampleBitmaps ) + bool bDownsampleBitmaps, + const Color& rBackground + ) { MetaAction* pCurrAct; bool bTransparent( false ); @@ -737,6 +737,20 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, bool bStillBackground=true; // true until first non-bg action nActionNum=0; nLastBgAction=-1; pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(); + if( rBackground != Color( COL_TRANSPARENT ) ) + { + aBackgroundComponent.aBgColor = rBackground; + if( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pThis = dynamic_cast<Printer*>(this); + Point aPageOffset = pThis->GetPageOffsetPixel(); + aPageOffset = Point( 0, 0 ) - aPageOffset; + Size aSize = pThis->GetPaperSizePixel(); + aBackgroundComponent.aBounds = Rectangle( aPageOffset, aSize ); + } + else + aBackgroundComponent.aBounds = Rectangle( Point( 0, 0 ), GetOutputSizePixel() ); + } while( pCurrAct && bStillBackground ) { switch( pCurrAct->GetType() ) @@ -880,7 +894,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // // if aBBCurrAct is empty, it will intersect with no - // aCCList member. Thus, we can safe us the check. + // aCCList member. Thus, we can save the check. // Furthermore, this ensures that non-output-generating // actions get their own aCCList entry, which is necessary // when copying them to the output metafile (see stage 4 @@ -1110,7 +1124,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // ==================================================== // - Point aTmpPoint; + Point aPageOffset; Size aTmpSize( GetOutputSizePixel() ); if( mpPDFWriter ) { @@ -1120,7 +1134,14 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // also add error code to PDFWriter mpPDFWriter->insertError( vcl::PDFWriter::Warning_Transparency_Converted ); } - const Rectangle aOutputRect( aTmpPoint, aTmpSize ); + else if( meOutDevType == OUTDEV_PRINTER ) + { + Printer* pThis = dynamic_cast<Printer*>(this); + aPageOffset = pThis->GetPageOffsetPixel(); + aPageOffset = Point( 0, 0 ) - aPageOffset; + aTmpSize = pThis->GetPaperSizePixel(); + } + const Rectangle aOutputRect( aPageOffset, aTmpSize ); bool bTiling = dynamic_cast<Printer*>(this) != NULL; // iterate over all aCCList members and generate bitmaps for the special ones @@ -1228,7 +1249,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, pCurrAct->Execute( &aPaintVDev ); } - if( !( nActionNum % 4 ) ) + if( !( nActionNum % 8 ) ) Application::Reschedule(); } diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx new file mode 100644 index 000000000000..6778cfbc867e --- /dev/null +++ b/vcl/source/gdi/print3.cxx @@ -0,0 +1,1765 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: print3.cxx,v $ + * $Revision: 1.1.2.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/print.hxx" +#include "vcl/prndlg.hxx" +#include "vcl/svapp.hxx" +#include "vcl/svdata.hxx" +#include "vcl/salinst.hxx" +#include "vcl/salprn.hxx" +#include "vcl/svids.hrc" +#include "vcl/metaact.hxx" +#include "vcl/msgbox.hxx" + +#include "tools/urlobj.hxx" + +#include "com/sun/star/ui/dialogs/XFilePicker.hpp" +#include "com/sun/star/ui/dialogs/XFilterManager.hpp" +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" +#include "com/sun/star/view/DuplexMode.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/awt/Size.hpp" +#include "comphelper/processfactory.hxx" + +#include <hash_map> +#include <hash_set> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace vcl; + +class ImplPageCache +{ + struct CacheEntry + { + GDIMetaFile aPage; + PrinterController::PageSize aSize; + }; + + std::vector< CacheEntry > maPages; + std::vector< sal_Int32 > maPageNumbers; + std::vector< sal_Int32 > maCacheRanking; + + static const sal_Int32 nCacheSize = 6; + + void updateRanking( sal_Int32 nLastHit ) + { + if( maCacheRanking[0] != nLastHit ) + { + bool bMove = false; + for( sal_Int32 i = nCacheSize-1; i > 0; i-- ) + { + if( maCacheRanking[i] == nLastHit ) + bMove = true; + maCacheRanking[i] = maCacheRanking[i-1]; + } + maCacheRanking[0] = nLastHit; + } + } + +public: + ImplPageCache() + : maPages( nCacheSize ) + , maPageNumbers( nCacheSize, -1 ) + , maCacheRanking( nCacheSize ) + { + for( sal_Int32 i = 0; i < nCacheSize; i++ ) + maCacheRanking[i] = nCacheSize - i - 1; + } + + // caution: does not ensure uniqueness + void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize ) + { + sal_Int32 nReplacePage = maCacheRanking.back(); + maPages[ nReplacePage ].aPage = i_rPage; + maPages[ nReplacePage ].aSize = i_rSize; + maPageNumbers[ nReplacePage ] = i_nPageNo; + // cache insertion means in our case, the page was just queried + // so update the ranking + updateRanking( nReplacePage ); + } + + // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6 + // this needs to be urgently rewritten. However do NOT increase the cache size lightly, + // whole pages can be rather memory intensive + bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize ) + { + for( sal_Int32 i = 0; i < nCacheSize; ++i ) + { + if( maPageNumbers[i] == i_nPageNo ) + { + updateRanking( i ); + o_rPageFile = maPages[i].aPage; + o_rSize = maPages[i].aSize; + return true; + } + } + return false; + } + + void invalidate() + { + for( sal_Int32 i = 0; i < nCacheSize; ++i ) + { + maPageNumbers[i] = -1; + maPages[i].aPage.Clear(); + maCacheRanking[i] = nCacheSize - i - 1; + } + } +}; + +class vcl::ImplPrinterControllerData +{ +public: + struct ControlDependency + { + rtl::OUString maDependsOnName; + sal_Int32 mnDependsOnEntry; + + ControlDependency() : mnDependsOnEntry( -1 ) {} + }; + + typedef std::hash_map< rtl::OUString, size_t, rtl::OUStringHash > PropertyToIndexMap; + typedef std::hash_map< rtl::OUString, ControlDependency, rtl::OUStringHash > ControlDependencyMap; + + boost::shared_ptr<Printer> mpPrinter; + Sequence< PropertyValue > maUIOptions; + std::vector< PropertyValue > maUIProperties; + std::vector< bool > maUIPropertyEnabled; + PropertyToIndexMap maPropertyToIndex; + Link maOptionChangeHdl; + ControlDependencyMap maControlDependencies; + sal_Bool mbFirstPage; + sal_Bool mbLastPage; + sal_Bool mbReversePageOrder; + view::PrintableState meJobState; + + vcl::PrinterController::MultiPageSetup maMultiPage; + + vcl::PrintProgressDialog* mpProgress; + + ImplPageCache maPageCache; + + // set by user through printer config dialog + // if set, pages are centered and trimmed onto the fixed page + Size maFixedPageSize; + + ImplPrinterControllerData() : + mbFirstPage( sal_True ), + mbLastPage( sal_False ), + mbReversePageOrder( sal_False ), + meJobState( view::PrintableState_JOB_STARTED ), + mpProgress( NULL ) + {} + ~ImplPrinterControllerData() { delete mpProgress; } + + Size getRealPaperSize( const Size& i_rPageSize ) const + { + if( maFixedPageSize.Width() > 0 && maFixedPageSize.Height() > 0 ) + return maFixedPageSize; + if( maMultiPage.nRows * maMultiPage.nColumns > 1 ) + return maMultiPage.aPaperSize; + return i_rPageSize; + } + bool isFixedPageSize() const + { return maFixedPageSize.Width() != 0 && maFixedPageSize.Height() != 0; } + PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps ); +}; + +PrinterController::PrinterController() + : mpImplData( new ImplPrinterControllerData ) +{ +} + +PrinterController::PrinterController( const boost::shared_ptr<Printer>& i_pPrinter ) + : mpImplData( new ImplPrinterControllerData ) +{ + mpImplData->mpPrinter = i_pPrinter; +} + +static rtl::OUString queryFile( Printer* pPrinter ) +{ + rtl::OUString aResult; + + uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() ); + if( xFactory.is() ) + { + uno::Sequence< uno::Any > aTempl( 1 ); + aTempl.getArray()[0] <<= ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION; + uno::Reference< ui::dialogs::XFilePicker > xFilePicker( + xFactory->createInstanceWithArguments( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ), + aTempl ), uno::UNO_QUERY ); + DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" ); + + uno::Reference< ui::dialogs::XFilterManager > xFilterMgr( xFilePicker, uno::UNO_QUERY ); + if( xFilePicker.is() && xFilterMgr.is() ) + { + try + { +#ifdef UNX + // add PostScript and PDF + bool bPS = true, bPDF = true; + if( pPrinter ) + { + if( pPrinter->GetCapabilities( PRINTER_CAPABILITIES_PDF ) ) + bPS = false; + else + bPDF = false; + } + if( bPS ) + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PostScript" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.ps" ) ) ); + if( bPDF ) + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Portable Document Format" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.pdf" ) ) ); +#elif defined WNT + (void)pPrinter; + xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.PRN" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.prn" ) ) ); +#endif + // add arbitrary files + xFilterMgr->appendFilter( String( VclResId( SV_STDTEXT_ALLFILETYPES ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.*" ) ) ); + } + catch( lang::IllegalArgumentException rExc ) + { + DBG_ERRORFILE( "caught IllegalArgumentException when registering filter\n" ); + } + + if( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK ) + { + uno::Sequence< ::rtl::OUString > aPathSeq( xFilePicker->getFiles() ); + INetURLObject aObj( aPathSeq[0] ); + aResult = aObj.PathToFileName(); + } + } + } + return aResult; +} + +struct PrintJobAsync +{ + boost::shared_ptr<PrinterController> mpController; + JobSetup maInitSetup; + + PrintJobAsync( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) + : mpController( i_pController ), maInitSetup( i_rInitSetup ) + {} + + DECL_LINK( ExecJob, void* ); +}; + +IMPL_LINK( PrintJobAsync, ExecJob, void*, EMPTYARG ) +{ + Printer::ImplPrintJob( mpController, maInitSetup ); + + // clean up, do not access members after this + delete this; + + return 0; +} + +void Printer::PrintJob( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) +{ + sal_Bool bSynchronous = sal_False; + beans::PropertyValue* pVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wait" ) ) ); + if( pVal ) + pVal->Value >>= bSynchronous; + + if( bSynchronous ) + ImplPrintJob( i_pController, i_rInitSetup ); + else + { + PrintJobAsync* pAsync = new PrintJobAsync( i_pController, i_rInitSetup ); + Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) ); + } +} + +void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pController, + const JobSetup& i_rInitSetup + ) +{ + boost::shared_ptr<PrinterController> pController( i_pController ); + + // check if there is a default printer; if not, show an error box (if appropriate) + if( GetDefaultPrinterName().Len() == 0 ) + { + if( pController->isShowDialogs() + // && ! pController->isDirectPrint() + ) + { + ErrorBox aBox( NULL, VclResId( SV_PRINT_NOPRINTERWARNING ) ); + aBox.Execute(); + } + pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), + makeAny( sal_False ) ); + } + + // setup printer + + // if no specific printer is already set, create one + if( ! pController->getPrinter() ) + { + boost::shared_ptr<Printer> pPrinter( new Printer( i_rInitSetup.GetPrinterName() ) ); + pController->setPrinter( pPrinter ); + } + + // reset last page property + i_pController->setLastPage( sal_False ); + + // update "PageRange" property inferring from other properties: + // case 1: "Pages" set from UNO API -> + // setup "Print Selection" and insert "PageRange" attribute + // case 2: "All pages" is selected + // update "Page range" attribute to have a sensible default, + // but leave "All" as selected + + // "Pages" attribute from API is now equivalent to "PageRange" + // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1 + // Argh ! That sure needs cleaning up + beans::PropertyValue* pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ) ); + if( ! pContentVal ) + pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ) ); + + // case 1: UNO API has set "Pages" + beans::PropertyValue* pPagesVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pages" ) ) ); + if( pPagesVal ) + { + rtl::OUString aPagesVal; + pPagesVal->Value >>= aPagesVal; + if( aPagesVal.getLength() ) + { + // "Pages" attribute from API is now equivalent to "PageRange" + // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1 + // Argh ! That sure needs cleaning up + if( pContentVal ) + { + pContentVal->Value = makeAny( sal_Int32( 1 ) ); + i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), pPagesVal->Value ); + } + } + } + // case 2: is "All" selected ? + else if( pContentVal ) + { + sal_Int32 nContent = -1; + if( pContentVal->Value >>= nContent ) + { + if( nContent == 0 ) + { + sal_Int32 nPages = i_pController->getPageCount(); + if( nPages > 0 ) + { + rtl::OUStringBuffer aBuf( 32 ); + aBuf.appendAscii( "1" ); + if( nPages > 1 ) + { + aBuf.appendAscii( "-" ); + aBuf.append( nPages ); + } + i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), makeAny( aBuf.makeStringAndClear() ) ); + } + } + } + } + + beans::PropertyValue* pReverseVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ) ); + if( pReverseVal ) + { + sal_Bool bReverse = sal_False; + pReverseVal->Value >>= bReverse; + pController->setReversePrint( bReverse ); + } + + // in direct print case check whether there is anything to print. + // if not, show an errorbox (if appropriate) + if( pController->isShowDialogs() && pController->isDirectPrint() ) + { + if( pController->getFilteredPageCount() == 0 ) + { + ErrorBox aBox( NULL, VclResId( SV_PRINT_NOCONTENT ) ); + aBox.Execute(); + return; + } + } + + // check if the printer brings up its own dialog + // in that case leave the work to that dialog + if( ! pController->getPrinter()->GetCapabilities( PRINTER_CAPABILITIES_EXTERNALDIALOG ) && + ! pController->isDirectPrint() && + pController->isShowDialogs() + ) + { + try + { + PrintDialog aDlg( NULL, i_pController ); + if( ! aDlg.Execute() ) + { + GDIMetaFile aPageFile; + i_pController->setLastPage( sal_True ); + i_pController->getFilteredPageFile( 0, aPageFile ); + return; + } + if( aDlg.isPrintToFile() ) + { + rtl::OUString aFile = queryFile( pController->getPrinter().get() ); + if( ! aFile.getLength() ) + { + GDIMetaFile aPageFile; + i_pController->setLastPage( sal_True ); + i_pController->getFilteredPageFile( 0, aPageFile ); + return; + } + pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ), + makeAny( aFile ) ); + } + } + catch( std::bad_alloc& ) + { + } + } + + pController->pushPropertiesToPrinter(); + + rtl::OUString aJobName; + beans::PropertyValue* pJobNameVal = pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "JobName" ) ) ); + if( pJobNameVal ) + pJobNameVal->Value >>= aJobName; + + pController->getPrinter()->StartJob( String( aJobName ), pController ); + + pController->jobFinished( pController->getJobState() ); +} + +bool Printer::StartJob( const rtl::OUString& i_rJobName, boost::shared_ptr<vcl::PrinterController>& i_pController ) +{ + mnError = PRINTER_OK; + + if ( IsDisplayPrinter() ) + return FALSE; + + if ( IsJobActive() || IsPrinting() ) + return FALSE; + + ULONG nCopies = mnCopyCount; + bool bCollateCopy = mbCollateCopy; + bool bUserCopy = FALSE; + + if ( nCopies > 1 ) + { + ULONG nDevCopy; + + if ( bCollateCopy ) + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES ); + else + nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES ); + + // need to do copies by hand ? + if ( nCopies > nDevCopy ) + { + bUserCopy = TRUE; + nCopies = 1; + bCollateCopy = FALSE; + } + } + else + bCollateCopy = FALSE; + + + ImplSVData* pSVData = ImplGetSVData(); + mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter ); + + if ( !mpPrinter ) + return FALSE; + + // remark: currently it is still possible to use EnablePrintFile and + // SetPrintFileName to redirect printout into file + // it can be argued that those methods should be removed in favor + // of only using the LocalFileName property + beans::PropertyValue* pFileValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ) ); + if( pFileValue ) + { + rtl::OUString aFile; + pFileValue->Value >>= aFile; + if( aFile.getLength() ) + { + mbPrintFile = TRUE; + maPrintFile = aFile; + } + } + + XubString* pPrintFile = NULL; + if ( mbPrintFile ) + pPrintFile = &maPrintFile; + + maJobName = i_rJobName; + mnCurPage = 1; + mnCurPrintPage = 1; + mbPrinting = TRUE; + if( ImplGetSVData()->maGDIData.mbPrinterPullModel ) + { + mbJobActive = TRUE; + // sallayer does all necessary page printing + // and also handles showing a dialog + // that also means it must call jobStarted when the dialog is finished + // it also must set the JobState of the Controller + if( mpPrinter->StartJob( pPrintFile, + i_rJobName, + Application::GetDisplayName(), + maJobSetup.ImplGetConstData(), + *i_pController ) ) + { + EndJob(); + } + else + { + mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); + if ( !mnError ) + mnError = PRINTER_GENERALERROR; + pSVData->mpDefInst->DestroyPrinter( mpPrinter ); + mnCurPage = 0; + mnCurPrintPage = 0; + mbPrinting = FALSE; + mpPrinter = NULL; + + return false; + } + } + else + { + // possibly a dialog has been shown + // now the real job starts + i_pController->setJobState( view::PrintableState_JOB_STARTED ); + i_pController->jobStarted(); + + if( mpPrinter->StartJob( pPrintFile, + i_rJobName, + Application::GetDisplayName(), + nCopies, + bCollateCopy, + i_pController->isDirectPrint(), + maJobSetup.ImplGetConstData() ) ) + { + mbJobActive = TRUE; + i_pController->createProgressDialog(); + int nPages = i_pController->getFilteredPageCount(); + int nRepeatCount = bUserCopy ? mnCopyCount : 1; + for( int nIteration = 0; nIteration < nRepeatCount; nIteration++ ) + { + for( int nPage = 0; nPage < nPages; nPage++ ) + { + if( nPage == nPages-1 && nIteration == nRepeatCount-1 ) + i_pController->setLastPage( sal_True ); + i_pController->printFilteredPage( nPage ); + } + // FIXME: duplex ? + } + EndJob(); + + if( i_pController->getJobState() == view::PrintableState_JOB_STARTED ) + i_pController->setJobState( view::PrintableState_JOB_SPOOLED ); + } + else + { + mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() ); + if ( !mnError ) + mnError = PRINTER_GENERALERROR; + i_pController->setJobState( mnError == PRINTER_ABORT + ? view::PrintableState_JOB_ABORTED + : view::PrintableState_JOB_FAILED ); + pSVData->mpDefInst->DestroyPrinter( mpPrinter ); + mnCurPage = 0; + mnCurPrintPage = 0; + mbPrinting = FALSE; + mpPrinter = NULL; + + return false; + } + } + + return true; +} + +PrinterController::~PrinterController() +{ + delete mpImplData; +} + +view::PrintableState PrinterController::getJobState() const +{ + return mpImplData->meJobState; +} + +void PrinterController::setJobState( view::PrintableState i_eState ) +{ + mpImplData->meJobState = i_eState; +} + +const boost::shared_ptr<Printer>& PrinterController::getPrinter() const +{ + return mpImplData->mpPrinter; +} + +void PrinterController::setPrinter( const boost::shared_ptr<Printer>& i_rPrinter ) +{ + mpImplData->mpPrinter = i_rPrinter; + setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) ), + makeAny( rtl::OUString( i_rPrinter->GetName() ) ) ); +} + +bool PrinterController::setupPrinter( Window* i_pParent ) +{ + bool bRet = false; + if( mpImplData->mpPrinter.get() ) + { + Size aPaperSize( mpImplData->mpPrinter->PixelToLogic( + mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + bRet = mpImplData->mpPrinter->Setup( i_pParent ); + if( bRet ) + { + // was the papersize overridden ? if so we need to take action + Size aNewPaperSize( mpImplData->mpPrinter->PixelToLogic( + mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + if( aNewPaperSize != aPaperSize ) + { + mpImplData->maFixedPageSize = aNewPaperSize; + mpImplData->maPageCache.invalidate(); + awt::Size aOverrideSize; + aOverrideSize.Width = aNewPaperSize.Width(); + aOverrideSize.Height = aNewPaperSize.Height(); + setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OverridePageSize" ) ), + makeAny( aOverrideSize ) ); + } + } + } + return bRet; +} + +PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps ) +{ + PrinterController::PageSize aPageSize; + aPageSize.aSize = mpPrinter->GetPaperSize(); + for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty ) + { + if( i_rProps[ nProperty ].Name.equalsAscii( "PageSize" ) ) + { + awt::Size aSize; + i_rProps[ nProperty].Value >>= aSize; + aPageSize.aSize.Width() = aSize.Width; + aPageSize.aSize.Height() = aSize.Height; + + Size aCurSize( mpPrinter->GetPaperSize() ); + Size aRealPaperSize( getRealPaperSize( aPageSize.aSize ) ); + if( aRealPaperSize != aCurSize ) + mpPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() ); + } + if( i_rProps[ nProperty ].Name.equalsAscii( "PageIncludesNonprintableArea" ) ) + { + sal_Bool bVal = sal_False; + i_rProps[ nProperty].Value >>= bVal; + aPageSize.bFullPaper = static_cast<bool>(bVal); + } + } + return aPageSize; +} + +int PrinterController::getPageCountProtected() const +{ + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + int nPages = getPageCount(); + mpImplData->mpPrinter->Pop(); + return nPages; +} + +Sequence< beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const +{ + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + Sequence< beans::PropertyValue > aResult( getPageParameters( i_nPage ) ); + mpImplData->mpPrinter->Pop(); + return aResult; +} + +PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) +{ + // update progress if necessary + if( mpImplData->mpProgress ) + { + // do nothing if printing is canceled + if( mpImplData->mpProgress->isCanceled() ) + return PrinterController::PageSize(); + mpImplData->mpProgress->tick(); + Application::Reschedule( true ); + } + + if( i_bMayUseCache ) + { + PrinterController::PageSize aPageSize; + if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) ) + { + return aPageSize; + } + } + else + mpImplData->maPageCache.invalidate(); + + o_rMtf.Clear(); + + // get page parameters + Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) ); + const MapMode aMapMode( MAP_100TH_MM ); + + mpImplData->mpPrinter->Push(); + mpImplData->mpPrinter->SetMapMode( aMapMode ); + + // modify job setup if necessary + PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm ); + + o_rMtf.SetPrefSize( aPageSize.aSize ); + o_rMtf.SetPrefMapMode( aMapMode ); + + mpImplData->mpPrinter->EnableOutput( FALSE ); + + o_rMtf.Record( mpImplData->mpPrinter.get() ); + + printPage( i_nUnfilteredPage ); + + o_rMtf.Stop(); + o_rMtf.WindStart(); + mpImplData->mpPrinter->Pop(); + + if( i_bMayUseCache ) + mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize ); + + // reset "FirstPage" property to false now we've gotten at least our first one + mpImplData->mbFirstPage = sal_False; + + return aPageSize; +} + +static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder ) +{ + // intersect all clipregion actions with our clip rect + io_rSubPage.WindStart(); + io_rSubPage.Clip( i_rClipRect ); + + // save gstate + o_rMtf.AddAction( new MetaPushAction( PUSH_ALL ) ); + + // clip to page rect + o_rMtf.AddAction( new MetaClipRegionAction( Region( i_rClipRect ), TRUE ) ); + + // append the subpage + io_rSubPage.WindStart(); + io_rSubPage.Play( o_rMtf ); + + // restore gstate + o_rMtf.AddAction( new MetaPopAction() ); + + // draw a border + if( i_bDrawBorder ) + { + // save gstate + o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_CLIPREGION | PUSH_MAPMODE ) ); + o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); + + Rectangle aBorderRect( i_rClipRect ); + o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), TRUE ) ); + o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), FALSE ) ); + o_rMtf.AddAction( new MetaRectAction( aBorderRect ) ); + + // restore gstate + o_rMtf.AddAction( new MetaPopAction() ); + } +} + +PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache ) +{ + const MultiPageSetup& rMPS( mpImplData->maMultiPage ); + int nSubPages = rMPS.nRows * rMPS.nColumns; + if( nSubPages < 1 ) + nSubPages = 1; + + // reverse sheet order + if( mpImplData->mbReversePageOrder ) + { + int nDocPages = getFilteredPageCount(); + i_nFilteredPage = nDocPages - 1 - i_nFilteredPage; + } + + // there is no filtering to be done (and possibly the page size of the + // original page is to be set), when N-Up is "neutral" that is there is + // only one subpage and the margins are 0 + if( nSubPages == 1 && + rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 && + rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 ) + { + PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache ); + Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize ); + mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); + mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); + if( aPaperSize != aPageSize.aSize ) + { + // user overridden page size, center Metafile + o_rMtf.WindStart(); + long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2; + long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2; + o_rMtf.Move( nDX, nDY ); + o_rMtf.WindStart(); + o_rMtf.SetPrefSize( aPaperSize ); + aPageSize.aSize = aPaperSize; + } + return aPageSize; + } + + // set last page property really only on the very last page to be rendered + // that is on the last subpage of a NUp run + sal_Bool bIsLastPage = mpImplData->mbLastPage; + mpImplData->mbLastPage = sal_False; + + Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize ) ); + + // multi page area: page size minus margins + one time spacing right and down + // the added spacing is so each subpage can be calculated including its spacing + Size aMPArea( aPaperSize ); + aMPArea.Width() -= rMPS.nLeftMargin + rMPS.nRightMargin; + aMPArea.Width() += rMPS.nHorizontalSpacing; + aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin; + aMPArea.Height() += rMPS.nVerticalSpacing; + + // determine offsets + long nAdvX = aMPArea.Width() / rMPS.nColumns; + long nAdvY = aMPArea.Height() / rMPS.nRows; + + // determine size of a "cell" subpage, leave a little space around pages + Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing ); + + o_rMtf.Clear(); + o_rMtf.SetPrefSize( aPaperSize ); + o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); + o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) ); + + int nDocPages = getPageCountProtected(); + for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ ) + { + // map current sub page to real page + int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat; + if( nSubPage == nSubPages-1 || + nPage == nDocPages-1 ) + { + mpImplData->mbLastPage = bIsLastPage; + } + if( nPage >= 0 && nPage < nDocPages ) + { + GDIMetaFile aPageFile; + PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache ); + if( aPageSize.aSize.Width() && aPageSize.aSize.Height() ) + { + long nCellX = 0, nCellY = 0; + switch( rMPS.nOrder ) + { + case PrinterController::LRTB: + nCellX = (nSubPage % rMPS.nColumns); + nCellY = (nSubPage / rMPS.nColumns); + break; + case PrinterController::TBLR: + nCellX = (nSubPage / rMPS.nRows); + nCellY = (nSubPage % rMPS.nRows); + break; + } + // scale the metafile down to a sub page size + double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width()); + double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height()); + double fScale = std::min( fScaleX, fScaleY ); + aPageFile.Scale( fScale, fScale ); + aPageFile.WindStart(); + + // move the subpage so it is centered in its "cell" + long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2; + long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2; + long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX; + long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY; + aPageFile.Move( nX, nY ); + aPageFile.WindStart(); + // calculate border rectangle + Rectangle aSubPageRect( Point( nX, nY ), + Size( long(double(aPageSize.aSize.Width())*fScale), + long(double(aPageSize.aSize.Height())*fScale) ) ); + + // append subpage to page + appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder ); + } + } + } + o_rMtf.WindStart(); + + // subsequent getPageFile calls have changed the paper, reset it to current value + mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); + mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() ); + + return PrinterController::PageSize( aPaperSize, true ); +} + +int PrinterController::getFilteredPageCount() +{ + int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns; + if( nDiv < 1 ) + nDiv = 1; + return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv; +} + +ULONG PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut ) +{ + ULONG nRestoreDrawMode = mpImplData->mpPrinter->GetDrawMode(); + sal_Int32 nMaxBmpDPIX = mpImplData->mpPrinter->ImplGetDPIX(); + sal_Int32 nMaxBmpDPIY = mpImplData->mpPrinter->ImplGetDPIY(); + + const PrinterOptions& rPrinterOptions = mpImplData->mpPrinter->GetPrinterOptions(); + + static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300; + static const sal_Int32 NORMAL_BMP_RESOLUTION = 200; + + + if( rPrinterOptions.IsReduceBitmaps() ) + { + // calculate maximum resolution for bitmap graphics + if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() ) + { + nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY ); + } + else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() ) + { + nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY ); + } + else + { + nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX ); + nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY ); + } + } + + // convert to greysacles + if( rPrinterOptions.IsConvertToGreyscales() ) + { + mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | + ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | + DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); + } + + // disable transparency output + if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) ) + { + mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | DRAWMODE_NOTRANSPARENCY ); + } + + Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic + if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 ) + { + // in N-Up printing we have no "page" background operation + // we also have no way to determine the paper color + // so let's go for white, which will kill 99.9% of the real cases + aBg = Color( COL_WHITE ); + } + mpImplData->mpPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY, + rPrinterOptions.IsReduceTransparency(), + rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO, + rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(), + aBg + ); + return nRestoreDrawMode; +} + +void PrinterController::printFilteredPage( int i_nPage ) +{ + if( mpImplData->meJobState != view::PrintableState_JOB_STARTED ) + return; + + GDIMetaFile aPageFile; + PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile ); + + if( mpImplData->mpProgress ) + { + // do nothing if printing is canceled + if( mpImplData->mpProgress->isCanceled() ) + { + setJobState( view::PrintableState_JOB_ABORTED ); + return; + } + } + + // in N-Up printing set the correct page size + mpImplData->mpPrinter->SetMapMode( MAP_100TH_MM ); + // aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile() + mpImplData->mpPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() ); + + // if full paper are is meant, move the output to accomodate for pageoffset + if( aPageSize.bFullPaper ) + { + Point aPageOffset( mpImplData->mpPrinter->GetPageOffset() ); + aPageFile.WindStart(); + aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y() ); + } + + GDIMetaFile aCleanedFile; + ULONG nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile ); + + mpImplData->mpPrinter->EnableOutput( TRUE ); + + // actually print the page + mpImplData->mpPrinter->ImplStartPage(); + + mpImplData->mpPrinter->Push(); + aCleanedFile.WindStart(); + aCleanedFile.Play( mpImplData->mpPrinter.get() ); + mpImplData->mpPrinter->Pop(); + + mpImplData->mpPrinter->ImplEndPage(); + + mpImplData->mpPrinter->SetDrawMode( nRestoreDrawMode ); +} + +void PrinterController::jobStarted() +{ +} + +void PrinterController::jobFinished( view::PrintableState ) +{ +} + +void PrinterController::abortJob() +{ + setJobState( view::PrintableState_JOB_ABORTED ); +} + +void PrinterController::setLastPage( sal_Bool i_bLastPage ) +{ + mpImplData->mbLastPage = i_bLastPage; +} + +void PrinterController::setReversePrint( sal_Bool i_bReverse ) +{ + mpImplData->mbReversePageOrder = i_bReverse; +} + +bool PrinterController::getReversePrint() const +{ + return mpImplData->mbReversePageOrder; +} + +Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const +{ + std::hash_set< rtl::OUString, rtl::OUStringHash > aMergeSet; + size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3; + for( int i = 0; i < i_rMergeList.getLength(); i++ ) + aMergeSet.insert( i_rMergeList[i].Name ); + + Sequence< PropertyValue > aResult( nResultLen ); + for( int i = 0; i < i_rMergeList.getLength(); i++ ) + aResult[i] = i_rMergeList[i]; + int nCur = i_rMergeList.getLength(); + for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ ) + { + if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() ) + aResult[nCur++] = mpImplData->maUIProperties[i]; + } + // append IsFirstPage + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ); + aVal.Value <<= mpImplData->mbFirstPage; + aResult[nCur++] = aVal; + } + // append IsLastPage + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ); + aVal.Value <<= mpImplData->mbLastPage; + aResult[nCur++] = aVal; + } + // append IsPrinter + if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ) ) == aMergeSet.end() ) + { + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ); + aVal.Value <<= sal_True; + aResult[nCur++] = aVal; + } + aResult.realloc( nCur ); + return aResult; +} + +const Sequence< beans::PropertyValue >& PrinterController::getUIOptions() const +{ + return mpImplData->maUIOptions; +} + +beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; +} + +const beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) const +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL; +} + +Sequence< beans::PropertyValue > PrinterController::getValues( const Sequence< rtl::OUString >& i_rNames ) const +{ + Sequence< beans::PropertyValue > aRet( i_rNames.getLength() ); + sal_Int32 nFound = 0; + for( sal_Int32 i = 0; i < i_rNames.getLength(); i++ ) + { + const beans::PropertyValue* pVal = getValue( i_rNames[i] ); + if( pVal ) + aRet[ nFound++ ] = *pVal; + } + aRet.realloc( nFound ); + return aRet; +} + +void PrinterController::setValue( const rtl::OUString& i_rName, const Any& i_rValue ) +{ + beans::PropertyValue aVal; + aVal.Name = i_rName; + aVal.Value = i_rValue; + + setValue( aVal ); +} + +void PrinterController::setValue( const beans::PropertyValue& i_rValue ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rValue.Name ); + if( it != mpImplData->maPropertyToIndex.end() ) + mpImplData->maUIProperties[ it->second ] = i_rValue; + else + { + // insert correct index into property map + mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size(); + mpImplData->maUIProperties.push_back( i_rValue ); + mpImplData->maUIPropertyEnabled.push_back( true ); + } +} + +void PrinterController::setUIOptions( const Sequence< beans::PropertyValue >& i_rOptions ) +{ + DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" ); + + mpImplData->maUIOptions = i_rOptions; + + for( int i = 0; i < i_rOptions.getLength(); i++ ) + { + Sequence< beans::PropertyValue > aOptProp; + i_rOptions[i].Value >>= aOptProp; + bool bIsEnabled = true; + bool bHaveProperty = false; + rtl::OUString aPropName; + vcl::ImplPrinterControllerData::ControlDependency aDep; + for( int n = 0; n < aOptProp.getLength(); n++ ) + { + const beans::PropertyValue& rEntry( aOptProp[ n ] ); + if( rEntry.Name.equalsAscii( "Property" ) ) + { + PropertyValue aVal; + rEntry.Value >>= aVal; + DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name ) + == mpImplData->maPropertyToIndex.end(), "duplicate property entry" ); + setValue( aVal ); + aPropName = aVal.Name; + bHaveProperty = true; + } + else if( rEntry.Name.equalsAscii( "Enabled" ) ) + { + sal_Bool bValue = sal_True; + rEntry.Value >>= bValue; + bIsEnabled = bValue; + } + else if( rEntry.Name.equalsAscii( "DependsOnName" ) ) + { + rEntry.Value >>= aDep.maDependsOnName; + } + else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) ) + { + rEntry.Value >>= aDep.mnDependsOnEntry; + } + } + if( bHaveProperty ) + { + vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it = + mpImplData->maPropertyToIndex.find( aPropName ); + // sanity check + if( it != mpImplData->maPropertyToIndex.end() ) + { + mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled; + } + if( aDep.maDependsOnName.getLength() > 0 ) + mpImplData->maControlDependencies[ aPropName ] = aDep; + } + } +} + +void PrinterController::enableUIOption( const rtl::OUString& i_rProperty, bool i_bEnable ) +{ + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + if( it != mpImplData->maPropertyToIndex.end() ) + { + // call handler only for actual changes + if( ( mpImplData->maUIPropertyEnabled[ it->second ] && ! i_bEnable ) || + ( ! mpImplData->maUIPropertyEnabled[ it->second ] && i_bEnable ) ) + { + mpImplData->maUIPropertyEnabled[ it->second ] = i_bEnable; + rtl::OUString aPropName( i_rProperty ); + mpImplData->maOptionChangeHdl.Call( &aPropName ); + } + } +} + +bool PrinterController::isUIOptionEnabled( const rtl::OUString& i_rProperty ) const +{ + bool bEnabled = false; + std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator prop_it = + mpImplData->maPropertyToIndex.find( i_rProperty ); + if( prop_it != mpImplData->maPropertyToIndex.end() ) + { + bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second]; + + if( bEnabled ) + { + // check control dependencies + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + { + // check if the dependency is enabled + // if the dependency is disabled, we are too + bEnabled = isUIOptionEnabled( it->second.maDependsOnName ); + + if( bEnabled ) + { + // does the dependency have the correct value ? + const com::sun::star::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName ); + OSL_ENSURE( pVal, "unknown property in dependency" ); + if( pVal ) + { + sal_Int32 nDepVal = 0; + sal_Bool bDepVal = sal_False; + if( pVal->Value >>= nDepVal ) + { + bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1); + } + else if( pVal->Value >>= bDepVal ) + { + // could be a dependency on a checked boolean + // in this case the dependency is on a non zero for checked value + bEnabled = ( bDepVal && it->second.mnDependsOnEntry != 0) || + ( ! bDepVal && it->second.mnDependsOnEntry == 0); + } + else + { + // if the type does not match something is awry + OSL_ENSURE( 0, "strange type in control dependency" ); + bEnabled = false; + } + } + } + } + } + } + return bEnabled; +} + +rtl::OUString PrinterController::getDependency( const rtl::OUString& i_rProperty ) const +{ + rtl::OUString aDependency; + + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + aDependency = it->second.maDependsOnName; + + return aDependency; +} + +rtl::OUString PrinterController::makeEnabled( const rtl::OUString& i_rProperty ) +{ + rtl::OUString aDependency; + + vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it = + mpImplData->maControlDependencies.find( i_rProperty ); + if( it != mpImplData->maControlDependencies.end() ) + { + if( isUIOptionEnabled( it->second.maDependsOnName ) ) + { + aDependency = it->second.maDependsOnName; + const com::sun::star::beans::PropertyValue* pVal = getValue( aDependency ); + OSL_ENSURE( pVal, "unknown property in dependency" ); + if( pVal ) + { + sal_Int32 nDepVal = 0; + sal_Bool bDepVal = sal_False; + if( pVal->Value >>= nDepVal ) + { + if( it->second.mnDependsOnEntry != -1 ) + { + setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) ); + } + } + else if( pVal->Value >>= bDepVal ) + { + setValue( aDependency, makeAny( sal_Bool( it->second.mnDependsOnEntry != 0 ) ) ); + } + else + { + // if the type does not match something is awry + OSL_ENSURE( 0, "strange type in control dependency" ); + } + } + } + } + + return aDependency; +} + +void PrinterController::setOptionChangeHdl( const Link& i_rHdl ) +{ + mpImplData->maOptionChangeHdl = i_rHdl; +} + +void PrinterController::createProgressDialog() +{ + if( ! mpImplData->mpProgress ) + { + sal_Bool bShow = sal_True; + beans::PropertyValue* pMonitor = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) ); + if( pMonitor ) + pMonitor->Value >>= bShow; + else + { + const com::sun::star::beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ) ); + if( pVal ) + { + sal_Bool bApi = sal_False; + pVal->Value >>= bApi; + bShow = ! bApi; + } + } + + if( bShow && ! Application::IsHeadlessModeEnabled() ) + { + mpImplData->mpProgress = new PrintProgressDialog( NULL, getPageCountProtected() ); + mpImplData->mpProgress->Show(); + } + } +} + +void PrinterController::setMultipage( const MultiPageSetup& i_rMPS ) +{ + mpImplData->maMultiPage = i_rMPS; +} + +const PrinterController::MultiPageSetup& PrinterController::getMultipage() const +{ + return mpImplData->maMultiPage; +} + +void PrinterController::pushPropertiesToPrinter() +{ + sal_Int32 nCopyCount = 1; + // set copycount and collate + const beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) ); + if( pVal ) + pVal->Value >>= nCopyCount; + sal_Bool bCollate = sal_False; + pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); + if( pVal ) + pVal->Value >>= bCollate; + mpImplData->mpPrinter->SetCopyCount( static_cast<USHORT>(nCopyCount), bCollate ); + + // duplex mode + pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexMode" ) ) ); + if( pVal ) + { + sal_Int16 nDuplex = view::DuplexMode::UNKNOWN; + pVal->Value >>= nDuplex; + switch( nDuplex ) + { + case view::DuplexMode::OFF: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_OFF ); break; + case view::DuplexMode::LONGEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break; + case view::DuplexMode::SHORTEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break; + } + } +} + +bool PrinterController::isShowDialogs() const +{ + sal_Bool bApi = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ), sal_False ); + return ! bApi && ! Application::IsHeadlessModeEnabled(); +} + +bool PrinterController::isDirectPrint() const +{ + sal_Bool bDirect = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), sal_False ); + return bDirect == sal_True; +} + +sal_Bool PrinterController::getBoolProperty( const rtl::OUString& i_rProperty, sal_Bool i_bFallback ) const +{ + sal_Bool bRet = i_bFallback; + const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty ); + if( pVal ) + pVal->Value >>= bRet; + return bRet; +} + +/* + * PrinterOptionsHelper +**/ +Any PrinterOptionsHelper::getValue( const rtl::OUString& i_rPropertyName ) const +{ + Any aRet; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = + m_aPropertyMap.find( i_rPropertyName ); + if( it != m_aPropertyMap.end() ) + aRet = it->second; + return aRet; +} + +void PrinterOptionsHelper::setValue( const rtl::OUString& i_rPropertyName, const Any& i_rValue ) +{ + m_aPropertyMap[ i_rPropertyName ] = i_rValue; +} + +bool PrinterOptionsHelper::hasProperty( const rtl::OUString& i_rPropertyName ) const +{ + Any aRet; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it = + m_aPropertyMap.find( i_rPropertyName ); + return it != m_aPropertyMap.end(); +} + +sal_Bool PrinterOptionsHelper::getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault ) const +{ + sal_Bool bRet = sal_False; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= bRet) ? bRet : i_bDefault; +} + +sal_Int64 PrinterOptionsHelper::getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault ) const +{ + sal_Int64 nRet = 0; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= nRet) ? nRet : i_nDefault; +} + +rtl::OUString PrinterOptionsHelper::getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault ) const +{ + rtl::OUString aRet; + Any aVal( getValue( i_rPropertyName ) ); + return (aVal >>= aRet) ? aRet : i_rDefault; +} + +bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp, + std::set< rtl::OUString >* o_pChangeProp ) +{ + bool bChanged = false; + + // clear the changed set + if( o_pChangeProp ) + o_pChangeProp->clear(); + + sal_Int32 nElements = i_rNewProp.getLength(); + const PropertyValue* pVals = i_rNewProp.getConstArray(); + for( sal_Int32 i = 0; i < nElements; i++ ) + { + bool bElementChanged = false; + std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::iterator it = + m_aPropertyMap.find( pVals[ i ].Name ); + if( it != m_aPropertyMap.end() ) + { + if( it->second != pVals[ i ].Value ) + bElementChanged = true; + } + else + bElementChanged = true; + + if( bElementChanged ) + { + if( o_pChangeProp ) + o_pChangeProp->insert( pVals[ i ].Name ); + m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value; + bChanged = true; + } + } + return bChanged; +} + +void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< beans::PropertyValue >& io_rProps ) const +{ + if( m_aUIProperties.getLength() > 0 ) + { + sal_Int32 nIndex = io_rProps.getLength(); + io_rProps.realloc( nIndex+1 ); + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExtraPrintUIOptions" ) ); + aVal.Value = makeAny( m_aUIProperties ); + io_rProps[ nIndex ] = aVal; + } +} + +Any PrinterOptionsHelper::getUIControlOpt( const rtl::OUString& i_rTitle, + const Sequence< rtl::OUString >& i_rHelpTexts, + const rtl::OUString& i_rType, + const PropertyValue* i_pVal, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + sal_Int32 nElements = + 1 // ControlType + + (i_rTitle.getLength() ? 1 : 0) // Text + + (i_rHelpTexts.getLength() ? 1 : 0) // HelpText + + (i_pVal ? 1 : 0) // Property + + i_rControlOptions.maAddProps.getLength() // additional props + + (i_rControlOptions.maGroupHint.getLength() ? 1 : 0) // grouping + + (i_rControlOptions.mbInternalOnly ? 1 : 0) // internal hint + + (i_rControlOptions.mbEnabled ? 0 : 1) // enabled + ; + if( i_rControlOptions.maDependsOnName.getLength() ) + { + nElements += 1; + if( i_rControlOptions.mnDependsOnEntry != -1 ) + nElements += 1; + if( i_rControlOptions.mbAttachToDependency ) + nElements += 1; + } + + Sequence< PropertyValue > aCtrl( nElements ); + sal_Int32 nUsed = 0; + if( i_rTitle.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); + aCtrl[nUsed++].Value = makeAny( i_rTitle ); + } + if( i_rHelpTexts.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpText" ) ); + aCtrl[nUsed++].Value = makeAny( i_rHelpTexts ); + } + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlType" ) ); + aCtrl[nUsed++].Value = makeAny( i_rType ); + if( i_pVal ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property" ) ); + aCtrl[nUsed++].Value = makeAny( *i_pVal ); + } + if( i_rControlOptions.maDependsOnName.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnName" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName ); + if( i_rControlOptions.mnDependsOnEntry != -1 ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnEntry" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry ); + } + if( i_rControlOptions.mbAttachToDependency ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AttachToDependency" ) ); + aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency ); + } + } + if( i_rControlOptions.maGroupHint.getLength() ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GroupingHint" ) ); + aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint; + } + if( i_rControlOptions.mbInternalOnly ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InternalUIOnly" ) ); + aCtrl[nUsed++].Value <<= sal_True; + } + if( ! i_rControlOptions.mbEnabled ) + { + aCtrl[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); + aCtrl[nUsed++].Value <<= sal_False; + } + + sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength(); + for( sal_Int32 i = 0; i < nAddProps; i++ ) + aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i]; + + DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" ); + + return makeAny( aCtrl ); +} + +Any PrinterOptionsHelper::getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpText ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Group" ) ) ); +} + +Any PrinterOptionsHelper::getSubgroupControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Subgroup" ) ), + NULL, i_rControlOptions ); +} + +Any PrinterOptionsHelper::getBoolControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Bool i_bValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_bValue ); + return getUIControlOpt( i_rTitle, aHelpText, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bool" ) ), &aVal, i_rControlOptions ); +} + +Any PrinterOptionsHelper::getChoiceControlOpt( const rtl::OUString& i_rTitle, + const Sequence< rtl::OUString >& i_rHelpText, + const rtl::OUString& i_rProperty, + const Sequence< rtl::OUString >& i_rChoices, + sal_Int32 i_nValue, + const rtl::OUString& i_rType, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + UIControlOptions aOpt( i_rControlOptions ); + sal_Int32 nUsed = aOpt.maAddProps.getLength(); + aOpt.maAddProps.realloc( nUsed + 1 ); + aOpt.maAddProps[nUsed].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Choices" ) ); + aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices ); + + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_nValue ); + return getUIControlOpt( i_rTitle, i_rHelpText, i_rType, &aVal, aOpt ); +} + +Any PrinterOptionsHelper::getRangeControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + sal_Int32 i_nValue, + sal_Int32 i_nMinValue, + sal_Int32 i_nMaxValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + UIControlOptions aOpt( i_rControlOptions ); + if( i_nMaxValue >= i_nMinValue ) + { + sal_Int32 nUsed = aOpt.maAddProps.getLength(); + aOpt.maAddProps.realloc( nUsed + 2 ); + aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MinValue" ) ); + aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue ); + aOpt.maAddProps[nUsed ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxValue" ) ); + aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue ); + } + + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_nValue ); + return getUIControlOpt( i_rTitle, + aHelpText, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Range" ) ), + &aVal, + aOpt + ); +} + +Any PrinterOptionsHelper::getEditControlOpt( const rtl::OUString& i_rTitle, + const rtl::OUString& i_rHelpText, + const rtl::OUString& i_rProperty, + const rtl::OUString& i_rValue, + const PrinterOptionsHelper::UIControlOptions& i_rControlOptions + ) +{ + Sequence< rtl::OUString > aHelpText; + if( i_rHelpText.getLength() > 0 ) + { + aHelpText.realloc( 1 ); + *aHelpText.getArray() = i_rHelpText; + } + PropertyValue aVal; + aVal.Name = i_rProperty; + aVal.Value = makeAny( i_rValue ); + return getUIControlOpt( i_rTitle, + aHelpText, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Edit" ) ), + &aVal, + i_rControlOptions + ); +} diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx index f1c532a9295f..a13e272e368b 100644 --- a/vcl/source/gdi/virdev.cxx +++ b/vcl/source/gdi/virdev.cxx @@ -359,27 +359,40 @@ BOOL VirtualDevice::SetOutputSizePixel( const Size& rNewSize, BOOL bErase ) // ----------------------------------------------------------------------- -void VirtualDevice::SetReferenceDevice( RefDevMode eRefDevMode ) +void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode ) { - switch( eRefDevMode ) + sal_Int32 nDPIX = 600, nDPIY = 600; + switch( i_eRefDevMode ) { case REFDEV_NONE: default: DBG_ASSERT( FALSE, "VDev::SetRefDev illegal argument!" ); - // fall through + break; case REFDEV_MODE06: - mnDPIX = mnDPIY = 600; + nDPIX = nDPIY = 600; break; case REFDEV_MODE48: - mnDPIX = mnDPIY = 4800; + nDPIX = nDPIY = 4800; break; case REFDEV_MODE_MSO1: - mnDPIX = mnDPIY = 6*1440; + nDPIX = nDPIY = 6*1440; break; case REFDEV_MODE_PDF1: - mnDPIX = mnDPIY = 720; + nDPIX = nDPIY = 720; break; } + ImplSetReferenceDevice( i_eRefDevMode, nDPIX, nDPIY ); +} + +void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ) +{ + ImplSetReferenceDevice( REFDEV_CUSTOM, i_nDPIX, i_nDPIY ); +} + +void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ) +{ + mnDPIX = i_nDPIX; + mnDPIY = i_nDPIY; EnableOutput( FALSE ); // prevent output on reference device mbScreenComp = FALSE; @@ -391,7 +404,7 @@ void VirtualDevice::SetReferenceDevice( RefDevMode eRefDevMode ) // avoid adjusting font lists when already in refdev mode BYTE nOldRefDevMode = meRefDevMode; BYTE nOldCompatFlag = (BYTE)meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD; - meRefDevMode = (BYTE)(eRefDevMode | nOldCompatFlag); + meRefDevMode = (BYTE)(i_eRefDevMode | nOldCompatFlag); if( (nOldRefDevMode ^ nOldCompatFlag) != REFDEV_NONE ) return; |