xref: /aoo41x/main/vcl/source/gdi/print3.cxx (revision 79aad27f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_vcl.hxx"
25 
26 #include "vcl/print.hxx"
27 #include "vcl/svapp.hxx"
28 #include "vcl/metaact.hxx"
29 #include "vcl/msgbox.hxx"
30 #include "vcl/configsettings.hxx"
31 
32 #include "printdlg.hxx"
33 #include "svdata.hxx"
34 #include "salinst.hxx"
35 #include "salprn.hxx"
36 #include "svids.hrc"
37 
38 #include "tools/urlobj.hxx"
39 
40 #include "com/sun/star/ui/dialogs/XFilePicker.hpp"
41 #include "com/sun/star/ui/dialogs/XFilterManager.hpp"
42 #include "com/sun/star/ui/dialogs/TemplateDescription.hpp"
43 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
44 #include "com/sun/star/view/DuplexMode.hpp"
45 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
46 #include "com/sun/star/awt/Size.hpp"
47 #include "comphelper/processfactory.hxx"
48 
49 #include <hash_map>
50 #include <hash_set>
51 
52 using namespace com::sun::star;
53 using namespace com::sun::star::uno;
54 using namespace com::sun::star::beans;
55 using namespace vcl;
56 
57 class ImplPageCache
58 {
59     struct CacheEntry
60     {
61         GDIMetaFile                 aPage;
62         PrinterController::PageSize aSize;
63     };
64 
65     std::vector< CacheEntry >  maPages;
66     std::vector< sal_Int32 >    maPageNumbers;
67     std::vector< sal_Int32 >    maCacheRanking;
68 
69     static const sal_Int32 nCacheSize = 6;
70 
71     void updateRanking( sal_Int32 nLastHit )
72     {
73         if( maCacheRanking[0] != nLastHit )
74         {
75             bool bMove = false;
76             for( sal_Int32 i = nCacheSize-1; i > 0; i-- )
77             {
78                 if( maCacheRanking[i] == nLastHit )
79                     bMove = true;
80                 maCacheRanking[i] = maCacheRanking[i-1];
81             }
82             maCacheRanking[0] = nLastHit;
83         }
84     }
85 
86 public:
87     ImplPageCache()
88     : maPages( nCacheSize )
89     , maPageNumbers( nCacheSize, -1 )
90     , maCacheRanking( nCacheSize )
91     {
92         for( sal_Int32 i = 0; i < nCacheSize; i++ )
93             maCacheRanking[i] = nCacheSize - i - 1;
94     }
95 
96     // caution: does not ensure uniqueness
97     void insert( sal_Int32 i_nPageNo, const GDIMetaFile& i_rPage, const PrinterController::PageSize& i_rSize )
98     {
99         sal_Int32 nReplacePage = maCacheRanking.back();
100         maPages[ nReplacePage ].aPage = i_rPage;
101         maPages[ nReplacePage ].aSize = i_rSize;
102         maPageNumbers[ nReplacePage ] = i_nPageNo;
103         // cache insertion means in our case, the page was just queried
104         // so update the ranking
105         updateRanking( nReplacePage );
106     }
107 
108     // caution: bad algorithm; should there ever be reason to increase the cache size beyond 6
109     // this needs to be urgently rewritten. However do NOT increase the cache size lightly,
110     // whole pages can be rather memory intensive
111     bool get( sal_Int32 i_nPageNo, GDIMetaFile& o_rPageFile, PrinterController::PageSize& o_rSize )
112     {
113         for( sal_Int32 i = 0; i < nCacheSize; ++i )
114         {
115             if( maPageNumbers[i] == i_nPageNo )
116             {
117                 updateRanking( i );
118                 o_rPageFile = maPages[i].aPage;
119                 o_rSize = maPages[i].aSize;
120                 return true;
121             }
122         }
123         return false;
124     }
125 
126     void invalidate()
127     {
128         for( sal_Int32 i = 0; i < nCacheSize; ++i )
129         {
130             maPageNumbers[i] = -1;
131             maPages[i].aPage.Clear();
132             maCacheRanking[i] = nCacheSize - i - 1;
133         }
134     }
135 };
136 
137 class vcl::ImplPrinterControllerData
138 {
139 public:
140     struct ControlDependency
141     {
142         rtl::OUString       maDependsOnName;
143         sal_Int32           mnDependsOnEntry;
144 
145         ControlDependency() : mnDependsOnEntry( -1 ) {}
146     };
147 
148     typedef std::hash_map< rtl::OUString, size_t, rtl::OUStringHash > PropertyToIndexMap;
149     typedef std::hash_map< rtl::OUString, ControlDependency, rtl::OUStringHash > ControlDependencyMap;
150     typedef std::hash_map< rtl::OUString, Sequence< sal_Bool >, rtl::OUStringHash > ChoiceDisableMap;
151 
152     boost::shared_ptr<Printer>                                  mpPrinter;
153     Sequence< PropertyValue >                                   maUIOptions;
154     std::vector< PropertyValue >                                maUIProperties;
155     std::vector< bool >                                         maUIPropertyEnabled;
156     PropertyToIndexMap                                          maPropertyToIndex;
157     Link                                                        maOptionChangeHdl;
158     ControlDependencyMap                                        maControlDependencies;
159     ChoiceDisableMap                                            maChoiceDisableMap;
160     sal_Bool                                                    mbFirstPage;
161     sal_Bool                                                    mbLastPage;
162     sal_Bool                                                    mbReversePageOrder;
163     view::PrintableState                                        meJobState;
164 
165     vcl::PrinterController::MultiPageSetup                      maMultiPage;
166 
167     vcl::PrintProgressDialog*                                   mpProgress;
168 
169     ImplPageCache                                               maPageCache;
170 
171     // set by user through printer config dialog
172     // if set, pages are centered and trimmed onto the fixed page
173     Size                                                        maFixedPageSize;
174     sal_Int32                                                   mnDefaultPaperBin;
175     sal_Int32                                                   mnFixedPaperBin;
176 
177     ImplPrinterControllerData() :
178         mbFirstPage( sal_True ),
179         mbLastPage( sal_False ),
180         mbReversePageOrder( sal_False ),
181         meJobState( view::PrintableState_JOB_STARTED ),
182         mpProgress( NULL ),
183         mnDefaultPaperBin( -1 ),
184         mnFixedPaperBin( -1 )
185     {}
186     ~ImplPrinterControllerData() { delete mpProgress; }
187 
188     Size getRealPaperSize( const Size& i_rPageSize, bool bNoNUP ) const
189     {
190         if( maFixedPageSize.Width() > 0 && maFixedPageSize.Height() > 0 )
191             return maFixedPageSize;
192         if( maMultiPage.nRows * maMultiPage.nColumns > 1 && ! bNoNUP )
193             return maMultiPage.aPaperSize;
194         return i_rPageSize;
195     }
196     bool isFixedPageSize() const
197     { return maFixedPageSize.Width() != 0 && maFixedPageSize.Height() != 0; }
198     PrinterController::PageSize modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP );
199 };
200 
201 PrinterController::PrinterController()
202     : mpImplData( new ImplPrinterControllerData )
203 {
204 }
205 
206 PrinterController::PrinterController( const boost::shared_ptr<Printer>& i_pPrinter )
207     : mpImplData( new ImplPrinterControllerData )
208 {
209     mpImplData->mpPrinter = i_pPrinter;
210 }
211 
212 static rtl::OUString queryFile( Printer* pPrinter )
213 {
214     rtl::OUString aResult;
215 
216     uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
217     if( xFactory.is() )
218     {
219         uno::Sequence< uno::Any > aTempl( 1 );
220         aTempl.getArray()[0] <<= ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION;
221         uno::Reference< ui::dialogs::XFilePicker > xFilePicker(
222             xFactory->createInstanceWithArguments(
223                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ),
224                 aTempl ), uno::UNO_QUERY );
225         DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" );
226 
227         uno::Reference< ui::dialogs::XFilterManager > xFilterMgr( xFilePicker, uno::UNO_QUERY );
228         if( xFilePicker.is() && xFilterMgr.is() )
229         {
230             try
231             {
232 #ifdef UNX
233                 // add PostScript and PDF
234                 bool bPS = true, bPDF = true;
235                 if( pPrinter )
236                 {
237                     if( pPrinter->GetCapabilities( PRINTER_CAPABILITIES_PDF ) )
238                         bPS = false;
239                     else
240                         bPDF = false;
241                 }
242                 if( bPS )
243                     xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PostScript" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.ps" ) ) );
244                 if( bPDF )
245                     xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Portable Document Format" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.pdf" ) ) );
246 #elif defined WNT
247 		(void)pPrinter;
248                 xFilterMgr->appendFilter( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.PRN" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.prn" ) ) );
249 #endif
250                 // add arbitrary files
251                 xFilterMgr->appendFilter( String( VclResId( SV_STDTEXT_ALLFILETYPES ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.*" ) ) );
252             }
253             catch( lang::IllegalArgumentException&)
254             {
255                 DBG_ERRORFILE( "caught IllegalArgumentException when registering filter\n" );
256             }
257 
258             if( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK )
259             {
260                 uno::Sequence< ::rtl::OUString > aPathSeq( xFilePicker->getFiles() );
261 				INetURLObject aObj( aPathSeq[0] );
262 				aResult = aObj.PathToFileName();
263             }
264         }
265     }
266     return aResult;
267 }
268 
269 struct PrintJobAsync
270 {
271     boost::shared_ptr<PrinterController>  mpController;
272     JobSetup                            maInitSetup;
273 
274     PrintJobAsync( const boost::shared_ptr<PrinterController>& i_pController,
275                    const JobSetup& i_rInitSetup
276                    )
277     : mpController( i_pController ), maInitSetup( i_rInitSetup )
278     {}
279 
280     DECL_LINK( ExecJob, void* );
281 };
282 
283 IMPL_LINK( PrintJobAsync, ExecJob, void*, EMPTYARG )
284 {
285     Printer::ImplPrintJob( mpController, maInitSetup );
286 
287     // clean up, do not access members after this
288     delete this;
289 
290     return 0;
291 }
292 
293 void Printer::PrintJob( const boost::shared_ptr<PrinterController>& i_pController,
294                         const JobSetup& i_rInitSetup
295                         )
296 {
297     sal_Bool bSynchronous = sal_False;
298     beans::PropertyValue* pVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wait" ) ) );
299     if( pVal )
300         pVal->Value >>= bSynchronous;
301 
302     if( bSynchronous )
303         ImplPrintJob( i_pController, i_rInitSetup );
304     else
305     {
306         PrintJobAsync* pAsync = new PrintJobAsync( i_pController, i_rInitSetup );
307         Application::PostUserEvent( LINK( pAsync, PrintJobAsync, ExecJob ) );
308     }
309 }
310 
311 void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pController,
312                             const JobSetup& i_rInitSetup
313                             )
314 {
315     boost::shared_ptr<PrinterController> pController( i_pController );
316 
317     // check if there is a default printer; if not, show an error box (if appropriate)
318     if( GetDefaultPrinterName().Len() == 0  )
319     {
320         if(  pController->isShowDialogs()
321              // && ! pController->isDirectPrint()
322            )
323         {
324             ErrorBox aBox( NULL, VclResId( SV_PRINT_NOPRINTERWARNING ) );
325             aBox.Execute();
326         }
327         pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ),
328                                makeAny( sal_False ) );
329     }
330 
331     // setup printer
332 
333     // #i114306# changed behavior back from persistence
334     // if no specific printer is already set, create the default printer
335     if( ! pController->getPrinter() )
336     {
337         rtl::OUString aPrinterName( i_rInitSetup.GetPrinterName() );
338         boost::shared_ptr<Printer> pPrinter( new Printer( aPrinterName ) );
339         pPrinter->SetJobSetup( i_rInitSetup );
340         pController->setPrinter( pPrinter );
341     }
342 
343     // reset last page property
344     i_pController->setLastPage( sal_False );
345 
346     // update "PageRange" property inferring from other properties:
347     // case 1: "Pages" set from UNO API ->
348     //         setup "Print Selection" and insert "PageRange" attribute
349     // case 2: "All pages" is selected
350     //         update "Page range" attribute to have a sensible default,
351     //         but leave "All" as selected
352 
353     // "Pages" attribute from API is now equivalent to "PageRange"
354     // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
355     // Argh ! That sure needs cleaning up
356     beans::PropertyValue* pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ) );
357     if( ! pContentVal )
358         pContentVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ) );
359 
360     // case 1: UNO API has set "Pages"
361     beans::PropertyValue* pPagesVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Pages" ) ) );
362     if( pPagesVal )
363     {
364         rtl::OUString aPagesVal;
365         pPagesVal->Value >>= aPagesVal;
366         if( aPagesVal.getLength() )
367         {
368             // "Pages" attribute from API is now equivalent to "PageRange"
369             // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
370             // Argh ! That sure needs cleaning up
371             if( pContentVal )
372             {
373                 pContentVal->Value = makeAny( sal_Int32( 1 ) );
374                 i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), pPagesVal->Value );
375             }
376         }
377     }
378     // case 2: is "All" selected ?
379     else if( pContentVal )
380     {
381         sal_Int32 nContent = -1;
382         if( pContentVal->Value >>= nContent )
383         {
384             if( nContent == 0 )
385             {
386                 // do not overwrite PageRange if it is already set
387                 beans::PropertyValue* pRangeVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ) );
388                 rtl::OUString aRange;
389                 if( pRangeVal )
390                     pRangeVal->Value >>= aRange;
391                 if( aRange.getLength() == 0 )
392                 {
393                     sal_Int32 nPages = i_pController->getPageCount();
394                     if( nPages > 0 )
395                     {
396                         rtl::OUStringBuffer aBuf( 32 );
397                         aBuf.appendAscii( "1" );
398                         if( nPages > 1 )
399                         {
400                             aBuf.appendAscii( "-" );
401                             aBuf.append( nPages );
402                         }
403                         i_pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), makeAny( aBuf.makeStringAndClear() ) );
404                     }
405                 }
406             }
407         }
408     }
409 
410     beans::PropertyValue* pReverseVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ) );
411     if( pReverseVal )
412     {
413         sal_Bool bReverse = sal_False;
414         pReverseVal->Value >>= bReverse;
415         pController->setReversePrint( bReverse );
416     }
417 
418     // setup NUp printing from properties
419     sal_Int32 nRows = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpRows" ) ), 1 );
420     sal_Int32 nCols = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpColumns" ) ), 1 );
421     if( nRows > 1 || nCols > 1 )
422     {
423         PrinterController::MultiPageSetup aMPS;
424         aMPS.nRows         = nRows > 1 ? nRows : 1;
425         aMPS.nColumns      = nCols > 1 ? nCols : 1;
426         sal_Int32 nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpPageMarginLeft" ) ), aMPS.nLeftMargin );
427         if( nValue >= 0 )
428             aMPS.nLeftMargin = nValue;
429         nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpPageMarginRight" ) ), aMPS.nRightMargin );
430         if( nValue >= 0 )
431             aMPS.nRightMargin = nValue;
432         nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpPageMarginTop" ) ), aMPS.nTopMargin );
433         if( nValue >= 0 )
434             aMPS.nTopMargin = nValue;
435         nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpPageMarginBottom" ) ), aMPS.nBottomMargin );
436         if( nValue >= 0 )
437             aMPS.nBottomMargin = nValue;
438         nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpHorizontalSpacing" ) ), aMPS.nHorizontalSpacing );
439         if( nValue >= 0 )
440             aMPS.nHorizontalSpacing = nValue;
441         nValue = i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpVerticalSpacing" ) ), aMPS.nVerticalSpacing );
442         if( nValue >= 0 )
443             aMPS.nVerticalSpacing = nValue;
444         aMPS.bDrawBorder = i_pController->getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpDrawBorder" ) ), aMPS.bDrawBorder );
445         aMPS.nOrder = static_cast<PrinterController::NupOrderType>(i_pController->getIntProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpSubPageOrder" ) ), aMPS.nOrder ));
446         aMPS.aPaperSize = i_pController->getPrinter()->PixelToLogic( i_pController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
447         beans::PropertyValue* pPgSizeVal = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NUpPaperSize" ) ) );
448         awt::Size aSizeVal;
449         if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
450         {
451             aMPS.aPaperSize.Width() = aSizeVal.Width;
452             aMPS.aPaperSize.Height() = aSizeVal.Height;
453         }
454 
455         i_pController->setMultipage( aMPS );
456     }
457 
458     // in direct print case check whether there is anything to print.
459     // if not, show an errorbox (if appropriate)
460     if( pController->isShowDialogs() && pController->isDirectPrint() )
461     {
462         if( pController->getFilteredPageCount() == 0 )
463         {
464             ErrorBox aBox( NULL, VclResId( SV_PRINT_NOCONTENT ) );
465             aBox.Execute();
466             return;
467         }
468     }
469 
470     // check if the printer brings up its own dialog
471     // in that case leave the work to that dialog
472     if( ! pController->getPrinter()->GetCapabilities( PRINTER_CAPABILITIES_EXTERNALDIALOG ) &&
473         ! pController->isDirectPrint() &&
474         pController->isShowDialogs()
475         )
476     {
477         try
478         {
479             PrintDialog aDlg( NULL, i_pController );
480             if( ! aDlg.Execute() )
481             {
482                 GDIMetaFile aPageFile;
483                 i_pController->abortJob();
484                 return;
485             }
486             if( aDlg.isPrintToFile() )
487             {
488                 rtl::OUString aFile = queryFile( pController->getPrinter().get() );
489                 if( ! aFile.getLength() )
490                 {
491                     i_pController->abortJob();
492                     return;
493                 }
494                 pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ),
495                                        makeAny( aFile ) );
496             }
497             else if( aDlg.isSingleJobs() )
498             {
499                 pController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ),
500                                        makeAny( sal_True ) );
501             }
502         }
503         catch( std::bad_alloc& )
504         {
505         }
506     }
507 
508     pController->pushPropertiesToPrinter();
509 
510     rtl::OUString aJobName;
511     beans::PropertyValue* pJobNameVal = pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "JobName" ) ) );
512     if( pJobNameVal )
513         pJobNameVal->Value >>= aJobName;
514 
515     pController->getPrinter()->StartJob( String( aJobName ), pController );
516 
517     pController->jobFinished( pController->getJobState() );
518 }
519 
520 bool Printer::StartJob( const rtl::OUString& i_rJobName, boost::shared_ptr<vcl::PrinterController>& i_pController )
521 {
522 	mnError = PRINTER_OK;
523 
524 	if ( IsDisplayPrinter() )
525 		return sal_False;
526 
527 	if ( IsJobActive() || IsPrinting() )
528 		return sal_False;
529 
530 	sal_uLong   nCopies = mnCopyCount;
531 	bool    bCollateCopy = mbCollateCopy;
532 	bool    bUserCopy = sal_False;
533 
534     if ( nCopies > 1 )
535     {
536         sal_uLong nDevCopy;
537 
538         if ( bCollateCopy )
539             nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COLLATECOPIES );
540         else
541             nDevCopy = GetCapabilities( PRINTER_CAPABILITIES_COPIES );
542 
543         // need to do copies by hand ?
544         if ( nCopies > nDevCopy )
545         {
546             bUserCopy = sal_True;
547             nCopies = 1;
548             bCollateCopy = sal_False;
549         }
550     }
551     else
552         bCollateCopy = sal_False;
553 
554 
555     ImplSVData* pSVData = ImplGetSVData();
556     mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
557 
558     if ( !mpPrinter )
559         return sal_False;
560 
561     sal_Bool bSinglePrintJobs = sal_False;
562     beans::PropertyValue* pSingleValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
563     if( pSingleValue )
564     {
565         pSingleValue->Value >>= bSinglePrintJobs;
566     }
567 
568     beans::PropertyValue* pFileValue = i_pController->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LocalFileName" ) ) );
569     if( pFileValue )
570     {
571         rtl::OUString aFile;
572         pFileValue->Value >>= aFile;
573         if( aFile.getLength() )
574         {
575             mbPrintFile = sal_True;
576             maPrintFile = aFile;
577             bSinglePrintJobs = sal_False;
578         }
579     }
580 
581     XubString* pPrintFile = NULL;
582     if ( mbPrintFile )
583         pPrintFile = &maPrintFile;
584     mpPrinterOptions->ReadFromConfig( mbPrintFile );
585 
586     maJobName		        = i_rJobName;
587     mnCurPage		        = 1;
588     mnCurPrintPage	        = 1;
589     mbPrinting		        = sal_True;
590     if( GetCapabilities( PRINTER_CAPABILITIES_USEPULLMODEL ) )
591     {
592         mbJobActive             = sal_True;
593         // sallayer does all necessary page printing
594         // and also handles showing a dialog
595         // that also means it must call jobStarted when the dialog is finished
596         // it also must set the JobState of the Controller
597         if( mpPrinter->StartJob( pPrintFile,
598                                  i_rJobName,
599                                  Application::GetDisplayName(),
600                                  maJobSetup.ImplGetConstData(),
601                                  *i_pController ) )
602         {
603             EndJob();
604         }
605         else
606         {
607             mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() );
608             if ( !mnError )
609                 mnError = PRINTER_GENERALERROR;
610             pSVData->mpDefInst->DestroyPrinter( mpPrinter );
611             mnCurPage		    = 0;
612             mnCurPrintPage	    = 0;
613             mbPrinting		    = sal_False;
614             mpPrinter = NULL;
615 
616             return false;
617         }
618     }
619     else
620     {
621         // possibly a dialog has been shown
622         // now the real job starts
623         i_pController->setJobState( view::PrintableState_JOB_STARTED );
624         i_pController->jobStarted();
625 
626         int nJobs = 1;
627         int nOuterRepeatCount = 1;
628         int nInnerRepeatCount = 1;
629         if( bUserCopy )
630         {
631             if( mbCollateCopy )
632                 nOuterRepeatCount = mnCopyCount;
633             else
634                 nInnerRepeatCount = mnCopyCount;
635         }
636         if( bSinglePrintJobs )
637         {
638             nJobs = mnCopyCount;
639             nCopies = 1;
640             nOuterRepeatCount = nInnerRepeatCount = 1;
641         }
642 
643         for( int nJobIteration = 0; nJobIteration < nJobs; nJobIteration++ )
644         {
645             bool bError = false, bAborted = false;
646             if( mpPrinter->StartJob( pPrintFile,
647                                      i_rJobName,
648                                      Application::GetDisplayName(),
649                                      nCopies,
650                                      bCollateCopy,
651                                      i_pController->isDirectPrint(),
652                                      maJobSetup.ImplGetConstData() ) )
653             {
654                 mbJobActive             = sal_True;
655                 i_pController->createProgressDialog();
656                 int nPages = i_pController->getFilteredPageCount();
657                 for( int nOuterIteration = 0; nOuterIteration < nOuterRepeatCount && ! bAborted; nOuterIteration++ )
658                 {
659                     for( int nPage = 0; nPage < nPages && ! bAborted; nPage++ )
660                     {
661                         for( int nInnerIteration = 0; nInnerIteration < nInnerRepeatCount && ! bAborted; nInnerIteration++ )
662                         {
663                             if( nPage == nPages-1 &&
664                                 nOuterIteration == nOuterRepeatCount-1 &&
665                                 nInnerIteration == nInnerRepeatCount-1 &&
666                                 nJobIteration == nJobs-1 )
667                             {
668                                 i_pController->setLastPage( sal_True );
669                             }
670                             i_pController->printFilteredPage( nPage );
671                             if( i_pController->isProgressCanceled() )
672                             {
673                                 i_pController->abortJob();
674                                 bAborted = true;
675                             }
676                         }
677                     }
678                     // FIXME: duplex ?
679                 }
680                 EndJob();
681 
682                 if( nJobIteration < nJobs-1 )
683                 {
684                     mpPrinter = pSVData->mpDefInst->CreatePrinter( mpInfoPrinter );
685 
686                     if ( mpPrinter )
687                     {
688                         maJobName		        = i_rJobName;
689                         mnCurPage		        = 1;
690                         mnCurPrintPage	        = 1;
691                         mbPrinting		        = sal_True;
692                     }
693                     else
694                         bError = true;
695                 }
696             }
697             else
698                 bError = true;
699 
700             if( bError )
701             {
702                 mnError = ImplSalPrinterErrorCodeToVCL( mpPrinter->GetErrorCode() );
703                 if ( !mnError )
704                     mnError = PRINTER_GENERALERROR;
705                 i_pController->setJobState( mnError == PRINTER_ABORT
706                                             ? view::PrintableState_JOB_ABORTED
707                                             : view::PrintableState_JOB_FAILED );
708                 if( mpPrinter )
709                     pSVData->mpDefInst->DestroyPrinter( mpPrinter );
710                 mnCurPage		    = 0;
711                 mnCurPrintPage	    = 0;
712                 mbPrinting		    = sal_False;
713                 mpPrinter = NULL;
714 
715                 return false;
716             }
717         }
718 
719         if( i_pController->getJobState() == view::PrintableState_JOB_STARTED )
720             i_pController->setJobState( view::PrintableState_JOB_SPOOLED );
721     }
722 
723     // make last used printer persistent for UI jobs
724     if( i_pController->isShowDialogs() && ! i_pController->isDirectPrint() )
725     {
726         SettingsConfigItem* pItem = SettingsConfigItem::get();
727         pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ),
728                          rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinterUsed" ) ),
729                          GetName()
730                          );
731     }
732 
733 	return true;
734 }
735 
736 PrinterController::~PrinterController()
737 {
738     delete mpImplData;
739 }
740 
741 view::PrintableState PrinterController::getJobState() const
742 {
743     return mpImplData->meJobState;
744 }
745 
746 void PrinterController::setJobState( view::PrintableState i_eState )
747 {
748     mpImplData->meJobState = i_eState;
749 }
750 
751 const boost::shared_ptr<Printer>& PrinterController::getPrinter() const
752 {
753     return mpImplData->mpPrinter;
754 }
755 
756 void PrinterController::setPrinter( const boost::shared_ptr<Printer>& i_rPrinter )
757 {
758     mpImplData->mpPrinter = i_rPrinter;
759     setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Name" ) ),
760               makeAny( rtl::OUString( i_rPrinter->GetName() ) ) );
761     mpImplData->mnDefaultPaperBin = mpImplData->mpPrinter->GetPaperBin();
762     mpImplData->mnFixedPaperBin = -1;
763 }
764 
765 void PrinterController:: resetPrinterOptions( bool i_bFileOutput )
766 {
767     PrinterOptions aOpt;
768     aOpt.ReadFromConfig( i_bFileOutput );
769     mpImplData->mpPrinter->SetPrinterOptions( aOpt );
770 }
771 
772 bool PrinterController::setupPrinter( Window* i_pParent )
773 {
774     bool bRet = false;
775     if( mpImplData->mpPrinter.get() )
776     {
777         // get old data
778         Size aPaperSize( mpImplData->mpPrinter->PixelToLogic(
779             mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
780         sal_uInt16 nPaperBin = mpImplData->mpPrinter->GetPaperBin();
781 
782         // call driver setup
783         bRet = mpImplData->mpPrinter->Setup( i_pParent );
784         if( bRet )
785         {
786             // was papersize or bin  overridden ? if so we need to take action
787             Size aNewPaperSize( mpImplData->mpPrinter->PixelToLogic(
788                 mpImplData->mpPrinter->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) );
789             sal_uInt16 nNewPaperBin = mpImplData->mpPrinter->GetPaperBin();
790             if( aNewPaperSize != aPaperSize || nNewPaperBin != nPaperBin )
791             {
792                 mpImplData->maFixedPageSize = aNewPaperSize;
793                 mpImplData->maPageCache.invalidate();
794                 awt::Size aOverrideSize;
795                 aOverrideSize.Width = aNewPaperSize.Width();
796                 aOverrideSize.Height = aNewPaperSize.Height();
797                 setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OverridePageSize" ) ),
798                           makeAny( aOverrideSize ) );
799                 mpImplData->mnFixedPaperBin = nNewPaperBin;
800             }
801         }
802     }
803     return bRet;
804 }
805 
806 PrinterController::PageSize vcl::ImplPrinterControllerData::modifyJobSetup( const Sequence< PropertyValue >& i_rProps, bool bNoNUP )
807 {
808     PrinterController::PageSize aPageSize;
809     aPageSize.aSize = mpPrinter->GetPaperSize();
810     awt::Size aSetSize, aIsSize;
811     sal_Int32 nPaperBin = mnDefaultPaperBin;
812     for( sal_Int32 nProperty = 0, nPropertyCount = i_rProps.getLength(); nProperty < nPropertyCount; ++nProperty )
813     {
814         if( i_rProps[ nProperty ].Name.equalsAscii( "PreferredPageSize" ) )
815         {
816             i_rProps[ nProperty ].Value >>= aSetSize;
817         }
818         else if( i_rProps[ nProperty ].Name.equalsAscii( "PageSize" ) )
819         {
820             i_rProps[ nProperty ].Value >>= aIsSize;
821         }
822         else if( i_rProps[ nProperty ].Name.equalsAscii( "PageIncludesNonprintableArea" ) )
823         {
824             sal_Bool bVal = sal_False;
825             i_rProps[ nProperty ].Value >>= bVal;
826             aPageSize.bFullPaper = static_cast<bool>(bVal);
827         }
828         else if( i_rProps[ nProperty ].Name.equalsAscii( "PrinterPaperTray" ) )
829         {
830             sal_Int32 nBin = -1;
831             i_rProps[ nProperty ].Value >>= nBin;
832             if( nBin >= 0 && nBin < mpPrinter->GetPaperBinCount() )
833                 nPaperBin = nBin;
834         }
835     }
836 
837     Size aCurSize( mpPrinter->GetPaperSize() );
838     if( aSetSize.Width && aSetSize.Height )
839     {
840         Size aSetPaperSize( aSetSize.Width, aSetSize.Height );
841         Size aRealPaperSize( getRealPaperSize( aSetPaperSize, bNoNUP ) );
842         if( aRealPaperSize != aCurSize )
843             aIsSize = aSetSize;
844     }
845 
846     if( aIsSize.Width && aIsSize.Height )
847     {
848         aPageSize.aSize.Width() = aIsSize.Width;
849         aPageSize.aSize.Height() = aIsSize.Height;
850 
851         Size aRealPaperSize( getRealPaperSize( aPageSize.aSize, bNoNUP ) );
852         if( aRealPaperSize != aCurSize )
853             mpPrinter->SetPaperSizeUser( aRealPaperSize, ! isFixedPageSize() );
854     }
855 
856     if( nPaperBin != -1 && nPaperBin != mpPrinter->GetPaperBin() )
857         mpPrinter->SetPaperBin( nPaperBin );
858 
859     return aPageSize;
860 }
861 
862 int PrinterController::getPageCountProtected() const
863 {
864     const MapMode aMapMode( MAP_100TH_MM );
865 
866     mpImplData->mpPrinter->Push();
867     mpImplData->mpPrinter->SetMapMode( aMapMode );
868     int nPages = getPageCount();
869     mpImplData->mpPrinter->Pop();
870     return nPages;
871 }
872 
873 Sequence< beans::PropertyValue > PrinterController::getPageParametersProtected( int i_nPage ) const
874 {
875     const MapMode aMapMode( MAP_100TH_MM );
876 
877     mpImplData->mpPrinter->Push();
878     mpImplData->mpPrinter->SetMapMode( aMapMode );
879     Sequence< beans::PropertyValue > aResult( getPageParameters( i_nPage ) );
880     mpImplData->mpPrinter->Pop();
881     return aResult;
882 }
883 
884 PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
885 {
886     // update progress if necessary
887     if( mpImplData->mpProgress )
888     {
889         // do nothing if printing is canceled
890         if( mpImplData->mpProgress->isCanceled() )
891             return PrinterController::PageSize();
892         mpImplData->mpProgress->tick();
893         Application::Reschedule( true );
894     }
895 
896     if( i_bMayUseCache )
897     {
898         PrinterController::PageSize aPageSize;
899         if( mpImplData->maPageCache.get( i_nUnfilteredPage, o_rMtf, aPageSize ) )
900         {
901             return aPageSize;
902         }
903     }
904     else
905         mpImplData->maPageCache.invalidate();
906 
907     o_rMtf.Clear();
908 
909     // get page parameters
910     Sequence< PropertyValue > aPageParm( getPageParametersProtected( i_nUnfilteredPage ) );
911     const MapMode aMapMode( MAP_100TH_MM );
912 
913     mpImplData->mpPrinter->Push();
914     mpImplData->mpPrinter->SetMapMode( aMapMode );
915 
916     // modify job setup if necessary
917     PrinterController::PageSize aPageSize = mpImplData->modifyJobSetup( aPageParm, true );
918 
919     o_rMtf.SetPrefSize( aPageSize.aSize );
920     o_rMtf.SetPrefMapMode( aMapMode );
921 
922     mpImplData->mpPrinter->EnableOutput( sal_False );
923 
924     o_rMtf.Record( mpImplData->mpPrinter.get() );
925 
926     printPage( i_nUnfilteredPage );
927 
928     o_rMtf.Stop();
929     o_rMtf.WindStart();
930     mpImplData->mpPrinter->Pop();
931 
932     if( i_bMayUseCache )
933         mpImplData->maPageCache.insert( i_nUnfilteredPage, o_rMtf, aPageSize );
934 
935     // reset "FirstPage" property to false now we've gotten at least our first one
936     mpImplData->mbFirstPage = sal_False;
937 
938     return aPageSize;
939 }
940 
941 static void appendSubPage( GDIMetaFile& o_rMtf, const Rectangle& i_rClipRect, GDIMetaFile& io_rSubPage, bool i_bDrawBorder )
942 {
943     // intersect all clipregion actions with our clip rect
944     io_rSubPage.WindStart();
945     io_rSubPage.Clip( i_rClipRect );
946 
947     // save gstate
948     o_rMtf.AddAction( new MetaPushAction( PUSH_ALL ) );
949 
950     // clip to page rect
951     o_rMtf.AddAction( new MetaClipRegionAction( Region( i_rClipRect ), sal_True ) );
952 
953     // append the subpage
954     io_rSubPage.WindStart();
955     io_rSubPage.Play( o_rMtf );
956 
957     // restore gstate
958     o_rMtf.AddAction( new MetaPopAction() );
959 
960     // draw a border
961     if( i_bDrawBorder )
962     {
963         // save gstate
964         o_rMtf.AddAction( new MetaPushAction( PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_CLIPREGION | PUSH_MAPMODE ) );
965         o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
966 
967         Rectangle aBorderRect( i_rClipRect );
968         o_rMtf.AddAction( new MetaLineColorAction( Color( COL_BLACK ), sal_True ) );
969         o_rMtf.AddAction( new MetaFillColorAction( Color( COL_TRANSPARENT ), sal_False ) );
970         o_rMtf.AddAction( new MetaRectAction( aBorderRect ) );
971 
972         // restore gstate
973         o_rMtf.AddAction( new MetaPopAction() );
974     }
975 }
976 
977 PrinterController::PageSize PrinterController::getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache )
978 {
979     const MultiPageSetup& rMPS( mpImplData->maMultiPage );
980     int nSubPages = rMPS.nRows * rMPS.nColumns;
981     if( nSubPages < 1 )
982         nSubPages = 1;
983 
984     // reverse sheet order
985     if( mpImplData->mbReversePageOrder )
986     {
987         int nDocPages = getFilteredPageCount();
988         i_nFilteredPage = nDocPages - 1 - i_nFilteredPage;
989     }
990 
991     // there is no filtering to be done (and possibly the page size of the
992     // original page is to be set), when N-Up is "neutral" that is there is
993     // only one subpage and the margins are 0
994     if( nSubPages == 1 &&
995         rMPS.nLeftMargin == 0 && rMPS.nRightMargin == 0 &&
996         rMPS.nTopMargin == 0 && rMPS.nBottomMargin == 0 )
997     {
998         PrinterController::PageSize aPageSize = getPageFile( i_nFilteredPage, o_rMtf, i_bMayUseCache );
999         Size aPaperSize = mpImplData->getRealPaperSize( aPageSize.aSize, true );
1000         mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1001         mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1002         if( aPaperSize != aPageSize.aSize )
1003         {
1004             // user overridden page size, center Metafile
1005             o_rMtf.WindStart();
1006             long nDX = (aPaperSize.Width() - aPageSize.aSize.Width()) / 2;
1007             long nDY = (aPaperSize.Height() - aPageSize.aSize.Height()) / 2;
1008             o_rMtf.Move( nDX, nDY, mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() );
1009             o_rMtf.WindStart();
1010             o_rMtf.SetPrefSize( aPaperSize );
1011             aPageSize.aSize = aPaperSize;
1012         }
1013         return aPageSize;
1014     }
1015 
1016     // set last page property really only on the very last page to be rendered
1017     // that is on the last subpage of a NUp run
1018     sal_Bool bIsLastPage = mpImplData->mbLastPage;
1019     mpImplData->mbLastPage = sal_False;
1020 
1021     Size aPaperSize( mpImplData->getRealPaperSize( mpImplData->maMultiPage.aPaperSize, false ) );
1022 
1023     // multi page area: page size minus margins + one time spacing right and down
1024     // the added spacing is so each subpage can be calculated including its spacing
1025     Size aMPArea( aPaperSize );
1026     aMPArea.Width()  -= rMPS.nLeftMargin + rMPS.nRightMargin;
1027     aMPArea.Width()  += rMPS.nHorizontalSpacing;
1028     aMPArea.Height() -= rMPS.nTopMargin + rMPS.nBottomMargin;
1029     aMPArea.Height() += rMPS.nVerticalSpacing;
1030 
1031     // determine offsets
1032     long nAdvX = aMPArea.Width() / rMPS.nColumns;
1033     long nAdvY = aMPArea.Height() / rMPS.nRows;
1034 
1035     // determine size of a "cell" subpage, leave a little space around pages
1036     Size aSubPageSize( nAdvX - rMPS.nHorizontalSpacing, nAdvY - rMPS.nVerticalSpacing );
1037 
1038     o_rMtf.Clear();
1039     o_rMtf.SetPrefSize( aPaperSize );
1040     o_rMtf.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
1041     o_rMtf.AddAction( new MetaMapModeAction( MapMode( MAP_100TH_MM ) ) );
1042 
1043     int nDocPages = getPageCountProtected();
1044     for( int nSubPage = 0; nSubPage < nSubPages; nSubPage++ )
1045     {
1046         // map current sub page to real page
1047         int nPage = (i_nFilteredPage * nSubPages + nSubPage) / rMPS.nRepeat;
1048         if( nSubPage == nSubPages-1 ||
1049             nPage == nDocPages-1 )
1050         {
1051             mpImplData->mbLastPage = bIsLastPage;
1052         }
1053         if( nPage >= 0 && nPage < nDocPages )
1054         {
1055             GDIMetaFile aPageFile;
1056             PrinterController::PageSize aPageSize = getPageFile( nPage, aPageFile, i_bMayUseCache );
1057             if( aPageSize.aSize.Width() && aPageSize.aSize.Height() )
1058             {
1059                 long nCellX = 0, nCellY = 0;
1060                 switch( rMPS.nOrder )
1061                 {
1062                 case PrinterController::LRTB:
1063                     nCellX = (nSubPage % rMPS.nColumns);
1064                     nCellY = (nSubPage / rMPS.nColumns);
1065                     break;
1066                 case PrinterController::TBLR:
1067                     nCellX = (nSubPage / rMPS.nRows);
1068                     nCellY = (nSubPage % rMPS.nRows);
1069                     break;
1070                 case PrinterController::RLTB:
1071                     nCellX = rMPS.nColumns - 1 - (nSubPage % rMPS.nColumns);
1072                     nCellY = (nSubPage / rMPS.nColumns);
1073                     break;
1074                 case PrinterController::TBRL:
1075                     nCellX = rMPS.nColumns - 1 - (nSubPage / rMPS.nRows);
1076                     nCellY = (nSubPage % rMPS.nRows);
1077                     break;
1078                 }
1079                 // scale the metafile down to a sub page size
1080                 double fScaleX = double(aSubPageSize.Width())/double(aPageSize.aSize.Width());
1081                 double fScaleY = double(aSubPageSize.Height())/double(aPageSize.aSize.Height());
1082                 double fScale  = std::min( fScaleX, fScaleY );
1083                 aPageFile.Scale( fScale, fScale );
1084                 aPageFile.WindStart();
1085 
1086                 // move the subpage so it is centered in its "cell"
1087                 long nOffX = (aSubPageSize.Width() - long(double(aPageSize.aSize.Width()) * fScale)) / 2;
1088                 long nOffY = (aSubPageSize.Height() - long(double(aPageSize.aSize.Height()) * fScale)) / 2;
1089                 long nX = rMPS.nLeftMargin + nOffX + nAdvX * nCellX;
1090                 long nY = rMPS.nTopMargin + nOffY + nAdvY * nCellY;
1091                 aPageFile.Move( nX, nY, mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() );
1092                 aPageFile.WindStart();
1093                 // calculate border rectangle
1094                 Rectangle aSubPageRect( Point( nX, nY ),
1095                                         Size( long(double(aPageSize.aSize.Width())*fScale),
1096                                               long(double(aPageSize.aSize.Height())*fScale) ) );
1097 
1098                 // append subpage to page
1099                 appendSubPage( o_rMtf, aSubPageRect, aPageFile, rMPS.bDrawBorder );
1100             }
1101         }
1102     }
1103     o_rMtf.WindStart();
1104 
1105     // subsequent getPageFile calls have changed the paper, reset it to current value
1106     mpImplData->mpPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1107     mpImplData->mpPrinter->SetPaperSizeUser( aPaperSize, ! mpImplData->isFixedPageSize() );
1108 
1109     return PrinterController::PageSize( aPaperSize, true );
1110 }
1111 
1112 int PrinterController::getFilteredPageCount()
1113 {
1114     int nDiv = mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns;
1115     if( nDiv < 1 )
1116         nDiv = 1;
1117     return (getPageCountProtected() * mpImplData->maMultiPage.nRepeat + (nDiv-1)) / nDiv;
1118 }
1119 
1120 sal_uLong PrinterController::removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut )
1121 {
1122     sal_uLong nRestoreDrawMode = mpImplData->mpPrinter->GetDrawMode();
1123     sal_Int32 nMaxBmpDPIX = mpImplData->mpPrinter->ImplGetDPIX();
1124     sal_Int32 nMaxBmpDPIY = mpImplData->mpPrinter->ImplGetDPIY();
1125 
1126     const PrinterOptions&   rPrinterOptions = mpImplData->mpPrinter->GetPrinterOptions();
1127 
1128     static const sal_Int32 OPTIMAL_BMP_RESOLUTION = 300;
1129     static const sal_Int32 NORMAL_BMP_RESOLUTION  = 200;
1130 
1131 
1132     if( rPrinterOptions.IsReduceBitmaps() )
1133     {
1134         // calculate maximum resolution for bitmap graphics
1135         if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() )
1136         {
1137             nMaxBmpDPIX = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1138             nMaxBmpDPIY = std::min( sal_Int32(OPTIMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1139         }
1140         else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() )
1141         {
1142             nMaxBmpDPIX = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIX );
1143             nMaxBmpDPIY = std::min( sal_Int32(NORMAL_BMP_RESOLUTION), nMaxBmpDPIY );
1144         }
1145         else
1146         {
1147             nMaxBmpDPIX = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIX );
1148             nMaxBmpDPIY = std::min( sal_Int32(rPrinterOptions.GetReducedBitmapResolution()), nMaxBmpDPIY );
1149         }
1150     }
1151 
1152     // convert to greysacles
1153     if( rPrinterOptions.IsConvertToGreyscales() )
1154     {
1155         mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() |
1156                                             ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
1157                                               DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
1158     }
1159 
1160     // disable transparency output
1161     if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
1162     {
1163         mpImplData->mpPrinter->SetDrawMode( mpImplData->mpPrinter->GetDrawMode() | DRAWMODE_NOTRANSPARENCY );
1164     }
1165 
1166     Color aBg( COL_TRANSPARENT ); // default: let RemoveTransparenciesFromMetaFile do its own background logic
1167     if( mpImplData->maMultiPage.nRows * mpImplData->maMultiPage.nColumns > 1 )
1168     {
1169         // in N-Up printing we have no "page" background operation
1170         // we also have no way to determine the paper color
1171         // so let's go for white, which will kill 99.9% of the real cases
1172         aBg = Color( COL_WHITE );
1173     }
1174     mpImplData->mpPrinter->RemoveTransparenciesFromMetaFile( i_rIn, o_rOut, nMaxBmpDPIX, nMaxBmpDPIY,
1175                                                              rPrinterOptions.IsReduceTransparency(),
1176                                                              rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO,
1177                                                              rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency(),
1178                                                              aBg
1179                                                              );
1180     return nRestoreDrawMode;
1181 }
1182 
1183 void PrinterController::printFilteredPage( int i_nPage )
1184 {
1185     if( mpImplData->meJobState != view::PrintableState_JOB_STARTED )
1186         return;
1187 
1188     GDIMetaFile aPageFile;
1189     PrinterController::PageSize aPageSize = getFilteredPageFile( i_nPage, aPageFile );
1190 
1191     if( mpImplData->mpProgress )
1192     {
1193         // do nothing if printing is canceled
1194         if( mpImplData->mpProgress->isCanceled() )
1195         {
1196             setJobState( view::PrintableState_JOB_ABORTED );
1197             return;
1198         }
1199     }
1200 
1201     // in N-Up printing set the correct page size
1202     mpImplData->mpPrinter->SetMapMode( MAP_100TH_MM );
1203 	// aPageSize was filtered through mpImplData->getRealPaperSize already by getFilteredPageFile()
1204     mpImplData->mpPrinter->SetPaperSizeUser( aPageSize.aSize, ! mpImplData->isFixedPageSize() );
1205     if( mpImplData->mnFixedPaperBin != -1 &&
1206         mpImplData->mpPrinter->GetPaperBin() != mpImplData->mnFixedPaperBin )
1207     {
1208         mpImplData->mpPrinter->SetPaperBin( mpImplData->mnFixedPaperBin );
1209     }
1210 
1211     // if full paper is meant to be used, move the output to accomodate for pageoffset
1212     if( aPageSize.bFullPaper )
1213     {
1214         Point aPageOffset( mpImplData->mpPrinter->GetPageOffset() );
1215         aPageFile.WindStart();
1216         aPageFile.Move( -aPageOffset.X(), -aPageOffset.Y(), mpImplData->mpPrinter->ImplGetDPIX(), mpImplData->mpPrinter->ImplGetDPIY() );
1217     }
1218 
1219     GDIMetaFile aCleanedFile;
1220     sal_uLong nRestoreDrawMode = removeTransparencies( aPageFile, aCleanedFile );
1221 
1222     mpImplData->mpPrinter->EnableOutput( sal_True );
1223 
1224     // actually print the page
1225     mpImplData->mpPrinter->ImplStartPage();
1226 
1227     mpImplData->mpPrinter->Push();
1228     aCleanedFile.WindStart();
1229     aCleanedFile.Play( mpImplData->mpPrinter.get() );
1230     mpImplData->mpPrinter->Pop();
1231 
1232     mpImplData->mpPrinter->ImplEndPage();
1233 
1234     mpImplData->mpPrinter->SetDrawMode( nRestoreDrawMode );
1235 }
1236 
1237 void PrinterController::jobStarted()
1238 {
1239 }
1240 
1241 void PrinterController::jobFinished( view::PrintableState )
1242 {
1243 }
1244 
1245 void PrinterController::abortJob()
1246 {
1247     setJobState( view::PrintableState_JOB_ABORTED );
1248     // applications (well, sw) depend on a page request with "IsLastPage" = true
1249     // to free resources, else they (well, sw) will crash eventually
1250     setLastPage( sal_True );
1251     delete mpImplData->mpProgress;
1252     mpImplData->mpProgress = NULL;
1253     GDIMetaFile aMtf;
1254     getPageFile( 0, aMtf, false );
1255 }
1256 
1257 void PrinterController::setLastPage( sal_Bool i_bLastPage )
1258 {
1259     mpImplData->mbLastPage = i_bLastPage;
1260 }
1261 
1262 void PrinterController::setReversePrint( sal_Bool i_bReverse )
1263 {
1264     mpImplData->mbReversePageOrder = i_bReverse;
1265 }
1266 
1267 bool PrinterController::getReversePrint() const
1268 {
1269     return mpImplData->mbReversePageOrder;
1270 }
1271 
1272 Sequence< PropertyValue > PrinterController::getJobProperties( const Sequence< PropertyValue >& i_rMergeList ) const
1273 {
1274     std::hash_set< rtl::OUString, rtl::OUStringHash > aMergeSet;
1275     size_t nResultLen = size_t(i_rMergeList.getLength()) + mpImplData->maUIProperties.size() + 3;
1276     for( int i = 0; i < i_rMergeList.getLength(); i++ )
1277         aMergeSet.insert( i_rMergeList[i].Name );
1278 
1279     Sequence< PropertyValue > aResult( nResultLen );
1280     for( int i = 0; i < i_rMergeList.getLength(); i++ )
1281         aResult[i] = i_rMergeList[i];
1282     int nCur = i_rMergeList.getLength();
1283     for( size_t i = 0; i < mpImplData->maUIProperties.size(); i++ )
1284     {
1285         if( aMergeSet.find( mpImplData->maUIProperties[i].Name ) == aMergeSet.end() )
1286             aResult[nCur++] = mpImplData->maUIProperties[i];
1287     }
1288     // append IsFirstPage
1289     if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) ) == aMergeSet.end() )
1290     {
1291         PropertyValue aVal;
1292         aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) );
1293         aVal.Value <<= mpImplData->mbFirstPage;
1294         aResult[nCur++] = aVal;
1295     }
1296     // append IsLastPage
1297     if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) ) == aMergeSet.end() )
1298     {
1299         PropertyValue aVal;
1300         aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) );
1301         aVal.Value <<= mpImplData->mbLastPage;
1302         aResult[nCur++] = aVal;
1303     }
1304     // append IsPrinter
1305     if( aMergeSet.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) ) ) == aMergeSet.end() )
1306     {
1307         PropertyValue aVal;
1308         aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsPrinter" ) );
1309         aVal.Value <<= sal_True;
1310         aResult[nCur++] = aVal;
1311     }
1312     aResult.realloc( nCur );
1313     return aResult;
1314 }
1315 
1316 const Sequence< beans::PropertyValue >& PrinterController::getUIOptions() const
1317 {
1318     return mpImplData->maUIOptions;
1319 }
1320 
1321 beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty )
1322 {
1323     std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
1324         mpImplData->maPropertyToIndex.find( i_rProperty );
1325     return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
1326 }
1327 
1328 const beans::PropertyValue* PrinterController::getValue( const rtl::OUString& i_rProperty ) const
1329 {
1330     std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
1331         mpImplData->maPropertyToIndex.find( i_rProperty );
1332     return it != mpImplData->maPropertyToIndex.end() ? &mpImplData->maUIProperties[it->second] : NULL;
1333 }
1334 
1335 Sequence< beans::PropertyValue > PrinterController::getValues( const Sequence< rtl::OUString >& i_rNames ) const
1336 {
1337     Sequence< beans::PropertyValue > aRet( i_rNames.getLength() );
1338     sal_Int32 nFound = 0;
1339     for( sal_Int32 i = 0; i < i_rNames.getLength(); i++ )
1340     {
1341         const beans::PropertyValue* pVal = getValue( i_rNames[i] );
1342         if( pVal )
1343             aRet[ nFound++ ] = *pVal;
1344     }
1345     aRet.realloc( nFound );
1346     return aRet;
1347 }
1348 
1349 void PrinterController::setValue( const rtl::OUString& i_rName, const Any& i_rValue )
1350 {
1351     beans::PropertyValue aVal;
1352     aVal.Name = i_rName;
1353     aVal.Value = i_rValue;
1354 
1355     setValue( aVal );
1356 }
1357 
1358 void PrinterController::setValue( const beans::PropertyValue& i_rValue )
1359 {
1360     std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
1361         mpImplData->maPropertyToIndex.find( i_rValue.Name );
1362     if( it != mpImplData->maPropertyToIndex.end() )
1363         mpImplData->maUIProperties[ it->second ] = i_rValue;
1364     else
1365     {
1366         // insert correct index into property map
1367         mpImplData->maPropertyToIndex[ i_rValue.Name ] = mpImplData->maUIProperties.size();
1368         mpImplData->maUIProperties.push_back( i_rValue );
1369         mpImplData->maUIPropertyEnabled.push_back( true );
1370     }
1371 }
1372 
1373 void PrinterController::setUIOptions( const Sequence< beans::PropertyValue >& i_rOptions )
1374 {
1375     DBG_ASSERT( mpImplData->maUIOptions.getLength() == 0, "setUIOptions called twice !" );
1376 
1377     mpImplData->maUIOptions = i_rOptions;
1378 
1379     for( int i = 0; i < i_rOptions.getLength(); i++ )
1380     {
1381         Sequence< beans::PropertyValue > aOptProp;
1382         i_rOptions[i].Value >>= aOptProp;
1383         bool bIsEnabled = true;
1384         bool bHaveProperty = false;
1385         rtl::OUString aPropName;
1386         vcl::ImplPrinterControllerData::ControlDependency aDep;
1387         Sequence< sal_Bool > aChoicesDisabled;
1388         for( int n = 0; n < aOptProp.getLength(); n++ )
1389         {
1390             const beans::PropertyValue& rEntry( aOptProp[ n ] );
1391             if( rEntry.Name.equalsAscii( "Property" ) )
1392             {
1393                 PropertyValue aVal;
1394                 rEntry.Value >>= aVal;
1395                 DBG_ASSERT( mpImplData->maPropertyToIndex.find( aVal.Name )
1396                             == mpImplData->maPropertyToIndex.end(), "duplicate property entry" );
1397                 setValue( aVal );
1398                 aPropName = aVal.Name;
1399                 bHaveProperty = true;
1400             }
1401             else if( rEntry.Name.equalsAscii( "Enabled" ) )
1402             {
1403                 sal_Bool bValue = sal_True;
1404                 rEntry.Value >>= bValue;
1405                 bIsEnabled = bValue;
1406             }
1407             else if( rEntry.Name.equalsAscii( "DependsOnName" ) )
1408             {
1409                 rEntry.Value >>= aDep.maDependsOnName;
1410             }
1411             else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) )
1412             {
1413                 rEntry.Value >>= aDep.mnDependsOnEntry;
1414             }
1415             else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) )
1416             {
1417                 rEntry.Value >>= aChoicesDisabled;
1418             }
1419         }
1420         if( bHaveProperty )
1421         {
1422             vcl::ImplPrinterControllerData::PropertyToIndexMap::const_iterator it =
1423                 mpImplData->maPropertyToIndex.find( aPropName );
1424             // sanity check
1425             if( it != mpImplData->maPropertyToIndex.end() )
1426             {
1427                 mpImplData->maUIPropertyEnabled[ it->second ] = bIsEnabled;
1428             }
1429             if( aDep.maDependsOnName.getLength() > 0 )
1430                 mpImplData->maControlDependencies[ aPropName ] = aDep;
1431             if( aChoicesDisabled.getLength() > 0 )
1432                 mpImplData->maChoiceDisableMap[ aPropName ] = aChoicesDisabled;
1433         }
1434     }
1435 }
1436 
1437 void PrinterController::enableUIOption( const rtl::OUString& i_rProperty, bool i_bEnable )
1438 {
1439     std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator it =
1440         mpImplData->maPropertyToIndex.find( i_rProperty );
1441     if( it != mpImplData->maPropertyToIndex.end() )
1442     {
1443         // call handler only for actual changes
1444         if( ( mpImplData->maUIPropertyEnabled[ it->second ] && ! i_bEnable ) ||
1445             ( ! mpImplData->maUIPropertyEnabled[ it->second ] && i_bEnable ) )
1446         {
1447             mpImplData->maUIPropertyEnabled[ it->second ] = i_bEnable;
1448             rtl::OUString aPropName( i_rProperty );
1449             mpImplData->maOptionChangeHdl.Call( &aPropName );
1450         }
1451     }
1452 }
1453 
1454 bool PrinterController::isUIOptionEnabled( const rtl::OUString& i_rProperty ) const
1455 {
1456     bool bEnabled = false;
1457     std::hash_map< rtl::OUString, size_t, rtl::OUStringHash >::const_iterator prop_it =
1458         mpImplData->maPropertyToIndex.find( i_rProperty );
1459     if( prop_it != mpImplData->maPropertyToIndex.end() )
1460     {
1461         bEnabled = mpImplData->maUIPropertyEnabled[prop_it->second];
1462 
1463         if( bEnabled )
1464         {
1465             // check control dependencies
1466             vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1467                 mpImplData->maControlDependencies.find( i_rProperty );
1468             if( it != mpImplData->maControlDependencies.end() )
1469             {
1470                 // check if the dependency is enabled
1471                 // if the dependency is disabled, we are too
1472                 bEnabled = isUIOptionEnabled( it->second.maDependsOnName );
1473 
1474                 if( bEnabled )
1475                 {
1476                     // does the dependency have the correct value ?
1477                     const com::sun::star::beans::PropertyValue* pVal = getValue( it->second.maDependsOnName );
1478                     OSL_ENSURE( pVal, "unknown property in dependency" );
1479                     if( pVal )
1480                     {
1481                         sal_Int32 nDepVal = 0;
1482                         sal_Bool bDepVal = sal_False;
1483                         if( pVal->Value >>= nDepVal )
1484                         {
1485                             bEnabled = (nDepVal == it->second.mnDependsOnEntry) || (it->second.mnDependsOnEntry == -1);
1486                         }
1487                         else if( pVal->Value >>= bDepVal )
1488                         {
1489                             // could be a dependency on a checked boolean
1490                             // in this case the dependency is on a non zero for checked value
1491                             bEnabled = (   bDepVal && it->second.mnDependsOnEntry != 0) ||
1492                                        ( ! bDepVal && it->second.mnDependsOnEntry == 0);
1493                         }
1494                         else
1495                         {
1496                             // if the type does not match something is awry
1497                             OSL_ENSURE( 0, "strange type in control dependency" );
1498                             bEnabled = false;
1499                         }
1500                     }
1501                 }
1502             }
1503         }
1504     }
1505     return bEnabled;
1506 }
1507 
1508 bool PrinterController::isUIChoiceEnabled( const rtl::OUString& i_rProperty, sal_Int32 i_nValue ) const
1509 {
1510     bool bEnabled = true;
1511     ImplPrinterControllerData::ChoiceDisableMap::const_iterator it =
1512         mpImplData->maChoiceDisableMap.find( i_rProperty );
1513     if(it != mpImplData->maChoiceDisableMap.end() )
1514     {
1515         const Sequence< sal_Bool >& rDisabled( it->second );
1516         if( i_nValue >= 0 && i_nValue < rDisabled.getLength() )
1517             bEnabled = ! rDisabled[i_nValue];
1518     }
1519     return bEnabled;
1520 }
1521 
1522 rtl::OUString PrinterController::getDependency( const rtl::OUString& i_rProperty ) const
1523 {
1524     rtl::OUString aDependency;
1525 
1526     vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1527         mpImplData->maControlDependencies.find( i_rProperty );
1528     if( it != mpImplData->maControlDependencies.end() )
1529         aDependency = it->second.maDependsOnName;
1530 
1531     return aDependency;
1532 }
1533 
1534 rtl::OUString PrinterController::makeEnabled( const rtl::OUString& i_rProperty )
1535 {
1536     rtl::OUString aDependency;
1537 
1538     vcl::ImplPrinterControllerData::ControlDependencyMap::const_iterator it =
1539         mpImplData->maControlDependencies.find( i_rProperty );
1540     if( it != mpImplData->maControlDependencies.end() )
1541     {
1542         if( isUIOptionEnabled( it->second.maDependsOnName ) )
1543         {
1544            aDependency = it->second.maDependsOnName;
1545            const com::sun::star::beans::PropertyValue* pVal = getValue( aDependency );
1546            OSL_ENSURE( pVal, "unknown property in dependency" );
1547            if( pVal )
1548            {
1549                sal_Int32 nDepVal = 0;
1550                sal_Bool bDepVal = sal_False;
1551                if( pVal->Value >>= nDepVal )
1552                {
1553                    if( it->second.mnDependsOnEntry != -1 )
1554                    {
1555                        setValue( aDependency, makeAny( sal_Int32( it->second.mnDependsOnEntry ) ) );
1556                    }
1557                }
1558                else if( pVal->Value >>= bDepVal )
1559                {
1560                    setValue( aDependency, makeAny( sal_Bool( it->second.mnDependsOnEntry != 0 ) ) );
1561                }
1562                else
1563                {
1564                    // if the type does not match something is awry
1565                    OSL_ENSURE( 0, "strange type in control dependency" );
1566                }
1567            }
1568         }
1569     }
1570 
1571     return aDependency;
1572 }
1573 
1574 void PrinterController::setOptionChangeHdl( const Link& i_rHdl )
1575 {
1576     mpImplData->maOptionChangeHdl = i_rHdl;
1577 }
1578 
1579 void PrinterController::createProgressDialog()
1580 {
1581     if( ! mpImplData->mpProgress )
1582     {
1583         sal_Bool bShow = sal_True;
1584         beans::PropertyValue* pMonitor = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
1585         if( pMonitor )
1586             pMonitor->Value >>= bShow;
1587         else
1588         {
1589             const com::sun::star::beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ) );
1590             if( pVal )
1591             {
1592                 sal_Bool bApi = sal_False;
1593                 pVal->Value >>= bApi;
1594                 bShow = ! bApi;
1595             }
1596         }
1597 
1598         if( bShow && ! Application::IsHeadlessModeEnabled() )
1599         {
1600             mpImplData->mpProgress = new PrintProgressDialog( NULL, getPageCountProtected() );
1601             mpImplData->mpProgress->Show();
1602         }
1603     }
1604     else
1605         mpImplData->mpProgress->reset();
1606 }
1607 
1608 bool PrinterController::isProgressCanceled() const
1609 {
1610     return mpImplData->mpProgress && mpImplData->mpProgress->isCanceled();
1611 }
1612 
1613 void PrinterController::setMultipage( const MultiPageSetup& i_rMPS )
1614 {
1615     mpImplData->maMultiPage = i_rMPS;
1616 }
1617 
1618 const PrinterController::MultiPageSetup& PrinterController::getMultipage() const
1619 {
1620     return mpImplData->maMultiPage;
1621 }
1622 
1623 void PrinterController::pushPropertiesToPrinter()
1624 {
1625     sal_Int32 nCopyCount = 1;
1626     // set copycount and collate
1627     const beans::PropertyValue* pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) );
1628     if( pVal )
1629         pVal->Value >>= nCopyCount;
1630     sal_Bool bCollate = sal_False;
1631     pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) );
1632     if( pVal )
1633         pVal->Value >>= bCollate;
1634     mpImplData->mpPrinter->SetCopyCount( static_cast<sal_uInt16>(nCopyCount), bCollate );
1635 
1636     // duplex mode
1637     pVal = getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DuplexMode" ) ) );
1638     if( pVal )
1639     {
1640         sal_Int16 nDuplex = view::DuplexMode::UNKNOWN;
1641         pVal->Value >>= nDuplex;
1642         switch( nDuplex )
1643         {
1644         case view::DuplexMode::OFF: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_OFF ); break;
1645         case view::DuplexMode::LONGEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_LONGEDGE ); break;
1646         case view::DuplexMode::SHORTEDGE: mpImplData->mpPrinter->SetDuplexMode( DUPLEX_SHORTEDGE ); break;
1647         }
1648     }
1649 }
1650 
1651 bool PrinterController::isShowDialogs() const
1652 {
1653     sal_Bool bApi = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsApi" ) ), sal_False );
1654     return ! bApi && ! Application::IsHeadlessModeEnabled();
1655 }
1656 
1657 bool PrinterController::isDirectPrint() const
1658 {
1659     sal_Bool bDirect = getBoolProperty( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDirect" ) ), sal_False );
1660     return bDirect == sal_True;
1661 }
1662 
1663 sal_Bool PrinterController::getBoolProperty( const rtl::OUString& i_rProperty, sal_Bool i_bFallback ) const
1664 {
1665     sal_Bool bRet = i_bFallback;
1666     const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty );
1667     if( pVal )
1668         pVal->Value >>= bRet;
1669     return bRet;
1670 }
1671 
1672 sal_Int32 PrinterController::getIntProperty( const rtl::OUString& i_rProperty, sal_Int32 i_nFallback ) const
1673 {
1674     sal_Int32 nRet = i_nFallback;
1675     const com::sun::star::beans::PropertyValue* pVal = getValue( i_rProperty );
1676     if( pVal )
1677         pVal->Value >>= nRet;
1678     return nRet;
1679 }
1680 
1681 /*
1682  * PrinterOptionsHelper
1683 **/
1684 Any PrinterOptionsHelper::getValue( const rtl::OUString& i_rPropertyName ) const
1685 {
1686     Any aRet;
1687     std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it =
1688         m_aPropertyMap.find( i_rPropertyName );
1689     if( it != m_aPropertyMap.end() )
1690         aRet = it->second;
1691     return aRet;
1692 }
1693 
1694 void PrinterOptionsHelper::setValue( const rtl::OUString& i_rPropertyName, const Any& i_rValue )
1695 {
1696     m_aPropertyMap[ i_rPropertyName ] = i_rValue;
1697 }
1698 
1699 bool PrinterOptionsHelper::hasProperty( const rtl::OUString& i_rPropertyName ) const
1700 {
1701     Any aRet;
1702     std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::const_iterator it =
1703         m_aPropertyMap.find( i_rPropertyName );
1704     return it != m_aPropertyMap.end();
1705 }
1706 
1707 sal_Bool PrinterOptionsHelper::getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault ) const
1708 {
1709     sal_Bool bRet = sal_False;
1710     Any aVal( getValue( i_rPropertyName ) );
1711     return (aVal >>= bRet) ? bRet : i_bDefault;
1712 }
1713 
1714 sal_Int64 PrinterOptionsHelper::getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault ) const
1715 {
1716     sal_Int64 nRet = 0;
1717     Any aVal( getValue( i_rPropertyName ) );
1718     return (aVal >>= nRet) ? nRet : i_nDefault;
1719 }
1720 
1721 rtl::OUString PrinterOptionsHelper::getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault ) const
1722 {
1723     rtl::OUString aRet;
1724     Any aVal( getValue( i_rPropertyName ) );
1725     return (aVal >>= aRet) ? aRet : i_rDefault;
1726 }
1727 
1728 bool PrinterOptionsHelper::processProperties( const Sequence< PropertyValue >& i_rNewProp,
1729                                               std::set< rtl::OUString >* o_pChangeProp )
1730 {
1731     bool bChanged = false;
1732 
1733     // clear the changed set
1734     if( o_pChangeProp )
1735         o_pChangeProp->clear();
1736 
1737     sal_Int32 nElements = i_rNewProp.getLength();
1738     const PropertyValue* pVals = i_rNewProp.getConstArray();
1739     for( sal_Int32 i = 0; i < nElements; i++ )
1740     {
1741         bool bElementChanged = false;
1742         std::hash_map< rtl::OUString, Any, rtl::OUStringHash >::iterator it =
1743             m_aPropertyMap.find( pVals[ i ].Name );
1744         if( it != m_aPropertyMap.end() )
1745         {
1746             if( it->second != pVals[ i ].Value )
1747                 bElementChanged = true;
1748         }
1749         else
1750             bElementChanged = true;
1751 
1752         if( bElementChanged )
1753         {
1754             if( o_pChangeProp )
1755                 o_pChangeProp->insert( pVals[ i ].Name );
1756             m_aPropertyMap[ pVals[i].Name ] = pVals[i].Value;
1757             bChanged = true;
1758         }
1759     }
1760     return bChanged;
1761 }
1762 
1763 void PrinterOptionsHelper::appendPrintUIOptions( uno::Sequence< beans::PropertyValue >& io_rProps ) const
1764 {
1765     if( m_aUIProperties.getLength() > 0 )
1766     {
1767         sal_Int32 nIndex = io_rProps.getLength();
1768         io_rProps.realloc( nIndex+1 );
1769         PropertyValue aVal;
1770         aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExtraPrintUIOptions" ) );
1771         aVal.Value = makeAny( m_aUIProperties );
1772         io_rProps[ nIndex ] = aVal;
1773     }
1774 }
1775 
1776 Any PrinterOptionsHelper::getUIControlOpt( const rtl::OUString& i_rTitle,
1777                                            const Sequence< rtl::OUString >& i_rHelpIds,
1778                                            const rtl::OUString& i_rType,
1779                                            const PropertyValue* i_pVal,
1780                                            const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1781                                            )
1782 {
1783     sal_Int32 nElements =
1784         1                                                               // ControlType
1785         + (i_rTitle.getLength() ? 1 : 0)                                // Text
1786         + (i_rHelpIds.getLength() ? 1 : 0)                              // HelpId
1787         + (i_pVal ? 1 : 0)                                              // Property
1788         + i_rControlOptions.maAddProps.getLength()                      // additional props
1789         + (i_rControlOptions.maGroupHint.getLength() ? 1 : 0)           // grouping
1790         + (i_rControlOptions.mbInternalOnly ? 1 : 0)                    // internal hint
1791         + (i_rControlOptions.mbEnabled ? 0 : 1)                         // enabled
1792         ;
1793     if( i_rControlOptions.maDependsOnName.getLength() )
1794     {
1795         nElements += 1;
1796         if( i_rControlOptions.mnDependsOnEntry != -1 )
1797             nElements += 1;
1798         if( i_rControlOptions.mbAttachToDependency )
1799             nElements += 1;
1800     }
1801 
1802     Sequence< PropertyValue > aCtrl( nElements );
1803     sal_Int32 nUsed = 0;
1804     if( i_rTitle.getLength() )
1805     {
1806         aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) );
1807         aCtrl[nUsed++].Value = makeAny( i_rTitle );
1808     }
1809     if( i_rHelpIds.getLength() )
1810     {
1811         aCtrl[nUsed  ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpId" ) );
1812         aCtrl[nUsed++].Value = makeAny( i_rHelpIds );
1813     }
1814     aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlType" ) );
1815     aCtrl[nUsed++].Value = makeAny( i_rType );
1816     if( i_pVal )
1817     {
1818         aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Property" ) );
1819         aCtrl[nUsed++].Value = makeAny( *i_pVal );
1820     }
1821     if( i_rControlOptions.maDependsOnName.getLength() )
1822     {
1823         aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnName" ) );
1824         aCtrl[nUsed++].Value = makeAny( i_rControlOptions.maDependsOnName );
1825         if( i_rControlOptions.mnDependsOnEntry != -1 )
1826         {
1827             aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DependsOnEntry" ) );
1828             aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mnDependsOnEntry );
1829         }
1830         if( i_rControlOptions.mbAttachToDependency )
1831         {
1832             aCtrl[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AttachToDependency" ) );
1833             aCtrl[nUsed++].Value = makeAny( i_rControlOptions.mbAttachToDependency );
1834         }
1835     }
1836     if( i_rControlOptions.maGroupHint.getLength() )
1837     {
1838         aCtrl[nUsed  ].Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GroupingHint" ) );
1839         aCtrl[nUsed++].Value <<= i_rControlOptions.maGroupHint;
1840     }
1841     if( i_rControlOptions.mbInternalOnly )
1842     {
1843         aCtrl[nUsed  ].Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InternalUIOnly" ) );
1844         aCtrl[nUsed++].Value <<= sal_True;
1845     }
1846     if( ! i_rControlOptions.mbEnabled )
1847     {
1848         aCtrl[nUsed  ].Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) );
1849         aCtrl[nUsed++].Value <<= sal_False;
1850     }
1851 
1852     sal_Int32 nAddProps = i_rControlOptions.maAddProps.getLength();
1853     for( sal_Int32 i = 0; i < nAddProps; i++ )
1854         aCtrl[ nUsed++ ] = i_rControlOptions.maAddProps[i];
1855 
1856     DBG_ASSERT( nUsed == nElements, "nUsed != nElements, probable heap corruption" );
1857 
1858     return makeAny( aCtrl );
1859 }
1860 
1861 Any PrinterOptionsHelper::getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpId )
1862 {
1863     Sequence< rtl::OUString > aHelpId;
1864     if( i_rHelpId.getLength() > 0 )
1865     {
1866         aHelpId.realloc( 1 );
1867         *aHelpId.getArray() = i_rHelpId;
1868     }
1869     return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Group" ) ) );
1870 }
1871 
1872 Any PrinterOptionsHelper::getSubgroupControlOpt( const rtl::OUString& i_rTitle,
1873                                                  const rtl::OUString& i_rHelpId,
1874                                                  const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1875                                                  )
1876 {
1877     Sequence< rtl::OUString > aHelpId;
1878     if( i_rHelpId.getLength() > 0 )
1879     {
1880         aHelpId.realloc( 1 );
1881         *aHelpId.getArray() = i_rHelpId;
1882     }
1883     return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Subgroup" ) ),
1884                             NULL, i_rControlOptions );
1885 }
1886 
1887 Any PrinterOptionsHelper::getBoolControlOpt( const rtl::OUString& i_rTitle,
1888                                              const rtl::OUString& i_rHelpId,
1889                                              const rtl::OUString& i_rProperty,
1890                                              sal_Bool i_bValue,
1891                                              const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1892                                              )
1893 {
1894     Sequence< rtl::OUString > aHelpId;
1895     if( i_rHelpId.getLength() > 0 )
1896     {
1897         aHelpId.realloc( 1 );
1898         *aHelpId.getArray() = i_rHelpId;
1899     }
1900     PropertyValue aVal;
1901     aVal.Name = i_rProperty;
1902     aVal.Value = makeAny( i_bValue );
1903     return getUIControlOpt( i_rTitle, aHelpId, rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bool" ) ), &aVal, i_rControlOptions );
1904 }
1905 
1906 Any PrinterOptionsHelper::getChoiceControlOpt( const rtl::OUString& i_rTitle,
1907                                                const Sequence< rtl::OUString >& i_rHelpId,
1908                                                const rtl::OUString& i_rProperty,
1909                                                const Sequence< rtl::OUString >& i_rChoices,
1910                                                sal_Int32 i_nValue,
1911                                                const rtl::OUString& i_rType,
1912                                                const Sequence< sal_Bool >& i_rDisabledChoices,
1913                                                const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1914                                                )
1915 {
1916     UIControlOptions aOpt( i_rControlOptions );
1917     sal_Int32 nUsed = aOpt.maAddProps.getLength();
1918     aOpt.maAddProps.realloc( nUsed + 1 + (i_rDisabledChoices.getLength() ? 1 : 0) );
1919     aOpt.maAddProps[nUsed].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Choices" ) );
1920     aOpt.maAddProps[nUsed].Value = makeAny( i_rChoices );
1921     if( i_rDisabledChoices.getLength() )
1922     {
1923         aOpt.maAddProps[nUsed+1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChoicesDisabled" ) );
1924         aOpt.maAddProps[nUsed+1].Value = makeAny( i_rDisabledChoices );
1925     }
1926 
1927     PropertyValue aVal;
1928     aVal.Name = i_rProperty;
1929     aVal.Value = makeAny( i_nValue );
1930     return getUIControlOpt( i_rTitle, i_rHelpId, i_rType, &aVal, aOpt );
1931 }
1932 
1933 Any PrinterOptionsHelper::getRangeControlOpt( const rtl::OUString& i_rTitle,
1934                                               const rtl::OUString& i_rHelpId,
1935                                               const rtl::OUString& i_rProperty,
1936                                               sal_Int32 i_nValue,
1937                                               sal_Int32 i_nMinValue,
1938                                               sal_Int32 i_nMaxValue,
1939                                               const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1940                                             )
1941 {
1942     UIControlOptions aOpt( i_rControlOptions );
1943     if( i_nMaxValue >= i_nMinValue )
1944     {
1945         sal_Int32 nUsed = aOpt.maAddProps.getLength();
1946         aOpt.maAddProps.realloc( nUsed + 2 );
1947         aOpt.maAddProps[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MinValue" ) );
1948         aOpt.maAddProps[nUsed++].Value = makeAny( i_nMinValue );
1949         aOpt.maAddProps[nUsed  ].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxValue" ) );
1950         aOpt.maAddProps[nUsed++].Value = makeAny( i_nMaxValue );
1951     }
1952 
1953     Sequence< rtl::OUString > aHelpId;
1954     if( i_rHelpId.getLength() > 0 )
1955     {
1956         aHelpId.realloc( 1 );
1957         *aHelpId.getArray() = i_rHelpId;
1958     }
1959     PropertyValue aVal;
1960     aVal.Name = i_rProperty;
1961     aVal.Value = makeAny( i_nValue );
1962     return getUIControlOpt( i_rTitle,
1963                             aHelpId,
1964                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Range" ) ),
1965                             &aVal,
1966                             aOpt
1967                             );
1968 }
1969 
1970 Any PrinterOptionsHelper::getEditControlOpt( const rtl::OUString& i_rTitle,
1971                                              const rtl::OUString& i_rHelpId,
1972                                              const rtl::OUString& i_rProperty,
1973                                              const rtl::OUString& i_rValue,
1974                                              const PrinterOptionsHelper::UIControlOptions& i_rControlOptions
1975                                            )
1976 {
1977     Sequence< rtl::OUString > aHelpId;
1978     if( i_rHelpId.getLength() > 0 )
1979     {
1980         aHelpId.realloc( 1 );
1981         *aHelpId.getArray() = i_rHelpId;
1982     }
1983     PropertyValue aVal;
1984     aVal.Name = i_rProperty;
1985     aVal.Value = makeAny( i_rValue );
1986     return getUIControlOpt( i_rTitle,
1987                             aHelpId,
1988                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Edit" ) ),
1989                             &aVal,
1990                             i_rControlOptions
1991                             );
1992 }
1993