1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salprn.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
36 #include "aquaprintview.h"
38 #include "saldata.hxx"
39 #include "vcl/jobset.h"
40 #include "vcl/salptype.hxx"
41 #include "vcl/impprn.hxx"
42 #include "vcl/print.hxx"
43 #include "vcl/unohelp.hxx"
45 #include <boost/bind.hpp>
47 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
48 #include "com/sun/star/container/XNameAccess.hpp"
49 #include "com/sun/star/beans/PropertyValue.hpp"
55 using namespace com::sun::star::uno
;
56 using namespace com::sun::star::lang
;
57 using namespace com::sun::star::beans
;
58 using namespace com::sun::star::container
;
60 // =======================================================================
62 AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo
& i_rQueue
) :
68 mePageOrientation( ORIENTATION_PORTRAIT
),
69 mnStartPageOffsetX( 0 ),
70 mnStartPageOffsetY( 0 )
72 NSString
* pStr
= CreateNSString( i_rQueue
.maPrinterName
);
73 mpPrinter
= [NSPrinter printerWithName
: pStr
];
76 NSPrintInfo
* pShared
= [NSPrintInfo sharedPrintInfo
];
79 mpPrintInfo
= [pShared copy
];
80 [mpPrintInfo setPrinter
: mpPrinter
];
81 mePageOrientation
= ([mpPrintInfo orientation
] == NSLandscapeOrientation
) ? ORIENTATION_LANDSCAPE
: ORIENTATION_PORTRAIT
;
82 [mpPrintInfo setOrientation
: NSPortraitOrientation
];
85 mpGraphics
= new AquaSalGraphics();
87 const int nWidth
= 100, nHeight
= 100;
88 maContextMemory
.reset( reinterpret_cast<sal_uInt8
*>( rtl_allocateMemory( nWidth
* 4 * nHeight
) ),
89 boost::bind( rtl_freeMemory
, _1
) );
92 mrContext
= CGBitmapContextCreate( maContextMemory
.get(), nWidth
, nHeight
, 8, nWidth
* 4, GetSalData()->mxRGBSpace
, kCGImageAlphaNoneSkipFirst
);
94 SetupPrinterGraphics( mrContext
);
98 // -----------------------------------------------------------------------
100 AquaSalInfoPrinter::~AquaSalInfoPrinter()
104 [mpPrintInfo release
];
106 // FIXME: verify that NSPrintInfo releases the printer
107 // else we have a leak here
112 CFRelease( mrContext
);
115 // -----------------------------------------------------------------------
117 void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext
) const
123 // FIXME: get printer resolution
124 long nDPIX
= 720, nDPIY
= 720;
125 NSSize aPaperSize
= [mpPrintInfo paperSize
];
127 NSRect aImageRect
= [mpPrintInfo imageablePageBounds
];
128 if( mePageOrientation
== ORIENTATION_PORTRAIT
)
130 // move mirrored CTM back into paper
131 double dX
= 0, dY
= aPaperSize
.height
;
132 // move CTM to reflect imageable area
133 dX
+= aImageRect
.origin
.x
;
134 dY
-= aPaperSize
.height
- aImageRect
.size
.height
- aImageRect
.origin
.y
;
135 CGContextTranslateCTM( i_rContext
, dX
+ mnStartPageOffsetX
, dY
- mnStartPageOffsetY
);
136 // scale to be top/down and reflect our "virtual" DPI
137 CGContextScaleCTM( i_rContext
, 0.1, -0.1 );
141 // move CTM to reflect imageable area
142 double dX
= aImageRect
.origin
.x
, dY
= aPaperSize
.height
- aImageRect
.size
.height
- aImageRect
.origin
.y
;
143 CGContextTranslateCTM( i_rContext
, -dX
, -dY
);
145 CGContextRotateCTM( i_rContext
, M_PI
/2 );
146 // move turned CTM back into paper
147 dX
= aPaperSize
.height
;
148 dY
= -aPaperSize
.width
;
149 CGContextTranslateCTM( i_rContext
, dX
+ mnStartPageOffsetY
, dY
- mnStartPageOffsetX
);
150 // scale to be top/down and reflect our "virtual" DPI
151 CGContextScaleCTM( i_rContext
, -0.1, 0.1 );
153 mpGraphics
->SetPrinterGraphics( i_rContext
, nDPIX
, nDPIY
, 1.0 );
156 DBG_ERROR( "no print info in SetupPrinterGraphics" );
160 // -----------------------------------------------------------------------
162 SalGraphics
* AquaSalInfoPrinter::GetGraphics()
164 SalGraphics
* pGraphics
= mbGraphics
? NULL
: mpGraphics
;
169 // -----------------------------------------------------------------------
171 void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics
* )
176 // -----------------------------------------------------------------------
178 BOOL
AquaSalInfoPrinter::Setup( SalFrame
* i_pFrame
, ImplJobSetup
* i_pSetupData
)
183 // -----------------------------------------------------------------------
185 static struct PaperSizeEntry
192 { 842, 1191, PAPER_A3
},
193 { 595, 842, PAPER_A4
},
194 { 420, 595, PAPER_A5
},
195 { 612, 792, PAPER_LETTER
},
196 { 612, 1008, PAPER_LEGAL
},
197 { 728, 1032, PAPER_B4_JIS
},
198 { 516, 729, PAPER_B5_JIS
},
199 { 792, 1224, PAPER_TABLOID
}
202 static bool getPaperSize( double& o_fWidth
, double& o_fHeight
, const Paper i_ePaper
)
204 for(unsigned int i
= 0; i
< sizeof(aPaperSizes
)/sizeof(aPaperSizes
[0]); i
++ )
206 if( aPaperSizes
[i
].nPaper
== i_ePaper
)
208 o_fWidth
= aPaperSizes
[i
].fWidth
;
209 o_fHeight
= aPaperSizes
[i
].fHeight
;
216 static Paper
recognizePaper( double i_fWidth
, double i_fHeight
)
218 Paper aPaper
= PAPER_USER
;
219 sal_uInt64 nPaperDesc
= 1000000*sal_uInt64(i_fWidth
) + sal_uInt64(i_fHeight
);
222 case 842001191: aPaper
= PAPER_A3
; break;
223 case 595000842: aPaper
= PAPER_A4
; break;
224 case 420000595: aPaper
= PAPER_A5
; break;
225 case 612000792: aPaper
= PAPER_LETTER
; break;
226 case 728001032: aPaper
= PAPER_B4_JIS
; break;
227 case 516000729: aPaper
= PAPER_B5_JIS
; break;
228 case 612001008: aPaper
= PAPER_LEGAL
; break;
229 case 792001224: aPaper
= PAPER_TABLOID
; break;
235 if( aPaper
== PAPER_USER
)
237 // search with fuzz factor
238 for( unsigned int i
= 0; i
< sizeof(aPaperSizes
)/sizeof(aPaperSizes
[0]); i
++ )
240 double w
= (i_fWidth
> aPaperSizes
[i
].fWidth
) ? i_fWidth
- aPaperSizes
[i
].fWidth
: aPaperSizes
[i
].fWidth
- i_fWidth
;
241 double h
= (i_fHeight
> aPaperSizes
[i
].fHeight
) ? i_fHeight
- aPaperSizes
[i
].fHeight
: aPaperSizes
[i
].fHeight
- i_fHeight
;
244 aPaper
= aPaperSizes
[i
].nPaper
;
253 BOOL
AquaSalInfoPrinter::SetPrinterData( ImplJobSetup
* io_pSetupData
)
255 // FIXME: implement driver data
256 if( io_pSetupData
&& io_pSetupData
->mpDriverData
)
257 return SetData( ~0, io_pSetupData
);
260 BOOL bSuccess
= TRUE
;
263 io_pSetupData
->mnSystem
= JOBSETUP_SYSTEM_MAC
;
268 NSSize aPaperSize
= [mpPrintInfo paperSize
];
269 double width
= aPaperSize
.width
, height
= aPaperSize
.height
;
271 io_pSetupData
->mePaperFormat
= recognizePaper( width
, height
);
272 if( io_pSetupData
->mePaperFormat
== PAPER_USER
)
274 io_pSetupData
->mnPaperWidth
= PtTo10Mu( width
);
275 io_pSetupData
->mnPaperHeight
= PtTo10Mu( height
);
279 io_pSetupData
->mnPaperWidth
= 0;
280 io_pSetupData
->mnPaperHeight
= 0;
284 io_pSetupData
->meOrientation
= mePageOrientation
;
286 io_pSetupData
->mnPaperBin
= 0;
287 io_pSetupData
->mpDriverData
= reinterpret_cast<BYTE
*>(rtl_allocateMemory( 4 ));
288 io_pSetupData
->mnDriverDataLen
= 4;
297 // -----------------------------------------------------------------------
299 BOOL
AquaSalInfoPrinter::SetData( ULONG i_nFlags
, ImplJobSetup
* io_pSetupData
)
301 if( ! io_pSetupData
|| io_pSetupData
->mnSystem
!= JOBSETUP_SYSTEM_MAC
)
307 if( (i_nFlags
& SAL_JOBSET_PAPERSIZE
) != 0)
310 double width
= 0, height
= 0;
311 if( io_pSetupData
->mePaperFormat
== PAPER_USER
)
313 // #i101108# sanity check
314 if( io_pSetupData
->mnPaperWidth
&& io_pSetupData
->mnPaperHeight
)
316 width
= TenMuToPt( io_pSetupData
->mnPaperWidth
);
317 height
= TenMuToPt( io_pSetupData
->mnPaperHeight
);
321 getPaperSize( width
, height
, io_pSetupData
->mePaperFormat
);
323 if( width
> 0 && height
> 0 )
325 NSSize aPaperSize
= { width
, height
};
326 [mpPrintInfo setPaperSize
: aPaperSize
];
330 if( (i_nFlags
& SAL_JOBSET_ORIENTATION
) != 0 )
331 mePageOrientation
= io_pSetupData
->meOrientation
;
334 return mpPrintInfo
!= nil
;
337 // -----------------------------------------------------------------------
339 ULONG
AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup
* i_pSetupData
)
344 // -----------------------------------------------------------------------
346 XubString
AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup
* i_pSetupData
, ULONG i_nPaperBin
)
351 // -----------------------------------------------------------------------
353 static bool getUseNativeDialog()
358 // get service provider
359 Reference
< XMultiServiceFactory
> xSMgr( unohelper::GetMultiServiceFactory() );
360 // create configuration hierachical access name
365 Reference
< XMultiServiceFactory
> xConfigProvider(
366 Reference
< XMultiServiceFactory
>(
367 xSMgr
->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
368 "com.sun.star.configuration.ConfigurationProvider" ))),
371 if( xConfigProvider
.is() )
373 Sequence
< Any
> aArgs(1);
375 aVal
.Name
= OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
376 aVal
.Value
<<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
377 aArgs
.getArray()[0] <<= aVal
;
378 Reference
< XNameAccess
> xConfigAccess(
379 Reference
< XNameAccess
>(
380 xConfigProvider
->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
381 "com.sun.star.configuration.ConfigurationAccess" )),
385 if( xConfigAccess
.is() )
389 sal_Bool bValue
= sal_False
;
390 Any aAny
= xConfigAccess
->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseSystemPrintDialog" ) ) );
391 if( aAny
>>= bValue
)
394 catch( NoSuchElementException
& )
397 catch( WrappedTargetException
& )
408 catch( WrappedTargetException
& )
415 ULONG
AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup
* i_pSetupData
, USHORT i_nType
)
419 case PRINTER_CAPABILITIES_SUPPORTDIALOG
:
421 case PRINTER_CAPABILITIES_COPIES
:
423 case PRINTER_CAPABILITIES_COLLATECOPIES
:
425 case PRINTER_CAPABILITIES_SETORIENTATION
:
427 case PRINTER_CAPABILITIES_SETPAPERBIN
:
429 case PRINTER_CAPABILITIES_SETPAPERSIZE
:
431 case PRINTER_CAPABILITIES_SETPAPER
:
433 case PRINTER_CAPABILITIES_EXTERNALDIALOG
:
434 return getUseNativeDialog() ? 1 : 0;
440 // -----------------------------------------------------------------------
442 void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup
*,
443 long& o_rOutWidth
, long& o_rOutHeight
,
444 long& o_rPageOffX
, long& o_rPageOffY
,
445 long& o_rPageWidth
, long& o_rPageHeight
)
449 long nDPIX
= 72, nDPIY
= 72;
450 mpGraphics
->GetResolution( nDPIX
, nDPIY
);
451 const double fXScaling
= static_cast<double>(nDPIX
)/72.0,
452 fYScaling
= static_cast<double>(nDPIY
)/72.0;
454 NSSize aPaperSize
= [mpPrintInfo paperSize
];
455 o_rPageWidth
= static_cast<long>( double(aPaperSize
.width
) * fXScaling
);
456 o_rPageHeight
= static_cast<long>( double(aPaperSize
.height
) * fYScaling
);
458 NSRect aImageRect
= [mpPrintInfo imageablePageBounds
];
459 o_rPageOffX
= static_cast<long>( aImageRect
.origin
.x
* fXScaling
);
460 o_rPageOffY
= static_cast<long>( (aPaperSize
.height
- aImageRect
.size
.height
- aImageRect
.origin
.y
) * fYScaling
);
461 o_rOutWidth
= static_cast<long>( aImageRect
.size
.width
* fXScaling
);
462 o_rOutHeight
= static_cast<long>( aImageRect
.size
.height
* fYScaling
);
464 if( mePageOrientation
== ORIENTATION_LANDSCAPE
)
466 std::swap( o_rOutWidth
, o_rOutHeight
);
467 std::swap( o_rPageWidth
, o_rPageHeight
);
468 std::swap( o_rPageOffX
, o_rPageOffY
);
473 BOOL
AquaSalInfoPrinter::StartJob( const String
* pFileName
,
474 const String
& rAppName
,
475 ImplJobSetup
* pSetupData
,
476 ImplQPrinter
* pQPrinter
,
482 BOOL bSuccess
= FALSE
;
483 std::vector
<ULONG
> aPaperRanges
;
484 if( ! pQPrinter
->GetPaperRanges( aPaperRanges
, true ) )
487 size_t nRanges
= aPaperRanges
.size();
488 AquaSalInstance
* pInst
= GetSalData()->mpFirstInstance
;
490 for( ULONG nCurRange
= 0; nCurRange
< nRanges
-1; nCurRange
++ )
492 mnStartPageOffsetX
= mnStartPageOffsetY
= 0;
495 ImplJobSetup
* pSetup
= pQPrinter
->GetPageSetup( aPaperRanges
[ nCurRange
] );
497 SetData( ~0, pSetup
);
498 DBG_ASSERT( pSetup
, "no job setup for range" );
500 mnCurPageRangeStart
= aPaperRanges
[nCurRange
];
501 mnCurPageRangeCount
= aPaperRanges
[nCurRange
+1] - aPaperRanges
[nCurRange
];
503 NSView
* pPrintView
= [[AquaPrintView alloc
] initWithQPrinter
: pQPrinter withInfoPrinter
: this];
505 NSMutableDictionary
* pPrintDict
= [mpPrintInfo dictionary
];
510 [mpPrintInfo setJobDisposition
: NSPrintSaveJob
];
511 NSString
* pPath
= CreateNSString( *pFileName
);
512 [pPrintDict setObject
: pPath forKey
: NSPrintSavePath
];
515 // in this case we can only deliver the print job in one file
516 mnCurPageRangeStart
= 0;
517 mnCurPageRangeCount
= aPaperRanges
.back();
521 [pPrintDict setObject
: [[NSNumber numberWithInt
: (int)pQPrinter
->GetCopyCount()] autorelease
] forKey
: NSPrintCopies
];
522 [pPrintDict setObject
: [[NSNumber numberWithBool
: YES
] autorelease
] forKey
: NSPrintDetailedErrorReporting
];
523 [pPrintDict setObject
: [[NSNumber numberWithInt
: 1] autorelease
] forKey
: NSPrintFirstPage
];
524 [pPrintDict setObject
: [[NSNumber numberWithInt
: (int)mnCurPageRangeCount
] autorelease
] forKey
: NSPrintLastPage
];
527 // create print operation
528 NSPrintOperation
* pPrintOperation
= [NSPrintOperation printOperationWithView
: pPrintView printInfo
: mpPrintInfo
];
530 if( pPrintOperation
)
532 bool bShowPanel
= (! bIsQuickJob
&& getUseNativeDialog() );
533 [pPrintOperation setShowsPrintPanel
: bShowPanel
? YES
: NO
];
534 // [pPrintOperation setShowsProgressPanel: NO];
537 pInst
->startedPrintJob();
538 [pPrintOperation runOperation
];
539 pInst
->endedPrintJob();
547 // -----------------------------------------------------------------------
549 BOOL
AquaSalInfoPrinter::EndJob()
551 mnStartPageOffsetX
= mnStartPageOffsetY
= 0;
556 // -----------------------------------------------------------------------
558 BOOL
AquaSalInfoPrinter::AbortJob()
562 // FIXME: implementation
566 // -----------------------------------------------------------------------
568 SalGraphics
* AquaSalInfoPrinter::StartPage( ImplJobSetup
* i_pSetupData
, BOOL i_bNewJobData
)
570 if( i_bNewJobData
&& i_pSetupData
)
571 SetPrinterData( i_pSetupData
);
573 CGContextRef rContext
= reinterpret_cast<CGContextRef
>([[NSGraphicsContext currentContext
] graphicsPort
]);
575 SetupPrinterGraphics( rContext
);
580 // -----------------------------------------------------------------------
582 BOOL
AquaSalInfoPrinter::EndPage()
587 // -----------------------------------------------------------------------
589 ULONG
AquaSalInfoPrinter::GetErrorCode() const
594 // =======================================================================
596 AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter
* i_pInfoPrinter
) :
597 mpInfoPrinter( i_pInfoPrinter
)
601 // -----------------------------------------------------------------------
603 AquaSalPrinter::~AquaSalPrinter()
607 // -----------------------------------------------------------------------
609 BOOL
AquaSalPrinter::StartJob( const String
* pFileName
,
610 const String
& rAppName
,
611 ImplJobSetup
* pSetupData
,
612 ImplQPrinter
* pQPrinter
)
614 bool bIsQuickJob
= false;
615 std::hash_map
< rtl::OUString
, rtl::OUString
, rtl::OUStringHash
>::const_iterator quick_it
=
616 pSetupData
->maValueMap
.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ) );
618 if( quick_it
!= pSetupData
->maValueMap
.end() )
620 if( quick_it
->second
.equalsIgnoreAsciiCaseAscii( "true" ) )
624 return mpInfoPrinter
->StartJob( pFileName
, rAppName
, pSetupData
, pQPrinter
, bIsQuickJob
);
627 // -----------------------------------------------------------------------
629 BOOL
AquaSalPrinter::StartJob( const XubString
* i_pFileName
,
630 const XubString
& i_rJobName
,
631 const XubString
& i_rAppName
,
632 ULONG i_nCopies
, BOOL i_bCollate
,
633 ImplJobSetup
* i_pSetupData
)
635 DBG_ERROR( "should never be called" );
639 // -----------------------------------------------------------------------
641 BOOL
AquaSalPrinter::EndJob()
643 return mpInfoPrinter
->EndJob();
646 // -----------------------------------------------------------------------
648 BOOL
AquaSalPrinter::AbortJob()
650 return mpInfoPrinter
->AbortJob();
653 // -----------------------------------------------------------------------
655 SalGraphics
* AquaSalPrinter::StartPage( ImplJobSetup
* i_pSetupData
, BOOL i_bNewJobData
)
657 return mpInfoPrinter
->StartPage( i_pSetupData
, i_bNewJobData
);
660 // -----------------------------------------------------------------------
662 BOOL
AquaSalPrinter::EndPage()
664 return mpInfoPrinter
->EndPage();
667 // -----------------------------------------------------------------------
669 ULONG
AquaSalPrinter::GetErrorCode()
671 return mpInfoPrinter
->GetErrorCode();
674 ////////////////////////////
675 ////// IMPLEMENT US /////
676 ////////////////////////////
678 DuplexMode
AquaSalInfoPrinter::GetDuplexMode( const ImplJobSetup
* i_pSetupData
)
680 return DUPLEX_UNKNOWN
;
683 void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup
* i_pSetupData
)
687 int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup
* i_pSetupData
)