xref: /trunk/main/sfx2/source/doc/printhelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #include "printhelper.hxx"
32 
33 #include <com/sun/star/view/XPrintJob.hpp>
34 #include <com/sun/star/awt/Size.hpp>
35 #include <com/sun/star/lang/IllegalArgumentException.hpp>
36 #include <com/sun/star/view/PaperFormat.hpp>
37 #include <com/sun/star/view/PaperOrientation.hpp>
38 #include <com/sun/star/ucb/NameClash.hpp>
39 #include <com/sun/star/lang/XUnoTunnel.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/lang/EventObject.hpp>
42 #include <com/sun/star/view/DuplexMode.hpp>
43 
44 #include <svl/lstner.hxx>
45 #include <svl/stritem.hxx>
46 #include <svl/intitem.hxx>
47 #include <svl/eitem.hxx>
48 #include <unotools/tempfile.hxx>
49 #include <unotools/localfilehelper.hxx>
50 #include <osl/file.hxx>
51 #include <osl/thread.hxx>
52 #include <tools/urlobj.hxx>
53 #include <ucbhelper/content.hxx>
54 #include <cppuhelper/interfacecontainer.hxx>
55 #include <vos/mutex.hxx>
56 #include <cppuhelper/implbase1.hxx>
57 
58 #include <sfx2/viewfrm.hxx>
59 #include <sfx2/viewsh.hxx>
60 #include <sfx2/dispatch.hxx>
61 #include <sfx2/request.hxx>
62 #include <sfx2/printer.hxx>
63 #include <sfx2/app.hxx>
64 #include <sfx2/objsh.hxx>
65 #include <sfx2/event.hxx>
66 
67 using namespace ::com::sun::star;
68 using namespace ::com::sun::star::uno;
69 
70 struct IMPL_PrintListener_DataContainer : public SfxListener
71 {
72     SfxObjectShellRef                               m_pObjectShell;
73     ::cppu::OMultiTypeInterfaceContainerHelper      m_aInterfaceContainer;
74     uno::Reference< com::sun::star::view::XPrintJob>     m_xPrintJob;
75     ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aPrintOptions;
76 
77     IMPL_PrintListener_DataContainer( ::osl::Mutex& aMutex)
78             :   m_pObjectShell          ( 0 )
79             ,   m_aInterfaceContainer   ( aMutex )
80     {
81     }
82 
83 
84     void Notify(            SfxBroadcaster& aBC     ,
85                     const   SfxHint&        aHint   ) ;
86 };
87 
88 awt::Size impl_Size_Object2Struct( const Size& aSize )
89 {
90     awt::Size aReturnValue;
91     aReturnValue.Width  = aSize.Width()  ;
92     aReturnValue.Height = aSize.Height() ;
93     return aReturnValue ;
94 }
95 
96 Size impl_Size_Struct2Object( const awt::Size& aSize )
97 {
98     Size aReturnValue;
99     aReturnValue.Width()  = aSize.Width  ;
100     aReturnValue.Height() = aSize.Height ;
101     return aReturnValue ;
102 }
103 
104 class SfxPrintJob_Impl : public cppu::WeakImplHelper1
105 <
106     com::sun::star::view::XPrintJob
107 >
108 {
109         IMPL_PrintListener_DataContainer* m_pData;
110 
111 public:
112         SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData );
113         virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrintOptions(  ) throw (RuntimeException);
114         virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrinter(  ) throw (RuntimeException);
115         virtual Reference< ::com::sun::star::view::XPrintable > SAL_CALL getPrintable(  ) throw (RuntimeException);
116         virtual void SAL_CALL cancelJob() throw (RuntimeException);
117 };
118 
119 SfxPrintJob_Impl::SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData )
120     : m_pData( pData )
121 {
122 }
123 
124 Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrintOptions() throw (RuntimeException)
125 {
126     return m_pData->m_aPrintOptions;
127 }
128 
129 Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrinter() throw (RuntimeException)
130 {
131     if( m_pData->m_pObjectShell.Is() )
132     {
133         Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell->GetModel(), UNO_QUERY );
134         if ( xPrintable.is() )
135             return xPrintable->getPrinter();
136     }
137     return Sequence< ::com::sun::star::beans::PropertyValue >();
138 }
139 
140 Reference< ::com::sun::star::view::XPrintable > SAL_CALL SfxPrintJob_Impl::getPrintable() throw (RuntimeException)
141 {
142     Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->GetModel() : NULL, UNO_QUERY );
143     return xPrintable;
144 }
145 
146 void SAL_CALL SfxPrintJob_Impl::cancelJob() throw (RuntimeException)
147 {
148     // FIXME: how to cancel PrintJob via API?!
149     if( m_pData->m_pObjectShell.Is() )
150         m_pData->m_pObjectShell->Broadcast( SfxPrintingHint( -2 ) );
151 }
152 
153 SfxPrintHelper::SfxPrintHelper()
154 {
155     m_pData = new IMPL_PrintListener_DataContainer(m_aMutex);
156 }
157 
158 void SAL_CALL SfxPrintHelper::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
159 {
160     if ( aArguments.getLength() )
161     {
162         com::sun::star::uno::Reference < com::sun::star::frame::XModel > xModel;
163         aArguments[0] >>= xModel;
164         uno::Reference < lang::XUnoTunnel > xObj( xModel, uno::UNO_QUERY );
165         uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
166         sal_Int64 nHandle = xObj->getSomething( aSeq );
167         if ( nHandle )
168         {
169             m_pData->m_pObjectShell = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle ));
170             m_pData->StartListening(*m_pData->m_pObjectShell);
171         }
172     }
173 }
174 
175 SfxPrintHelper::~SfxPrintHelper()
176 {
177     delete m_pData;
178 }
179 
180 namespace
181 {
182     view::PaperFormat convertToPaperFormat(Paper eFormat)
183     {
184         view::PaperFormat eRet;
185         switch (eFormat)
186         {
187             case PAPER_A3:
188                 eRet = view::PaperFormat_A3;
189                 break;
190             case PAPER_A4:
191                 eRet = view::PaperFormat_A4;
192                 break;
193             case PAPER_A5:
194                 eRet = view::PaperFormat_A5;
195                 break;
196             case PAPER_B4_ISO:
197                 eRet = view::PaperFormat_B4;
198                 break;
199             case PAPER_B5_ISO:
200                 eRet = view::PaperFormat_B5;
201                 break;
202             case PAPER_LETTER:
203                 eRet = view::PaperFormat_LETTER;
204                 break;
205             case PAPER_LEGAL:
206                 eRet = view::PaperFormat_LEGAL;
207                 break;
208             case PAPER_TABLOID:
209                 eRet = view::PaperFormat_TABLOID;
210                 break;
211             case PAPER_USER:
212             default:
213                 eRet = view::PaperFormat_USER;
214                 break;
215         }
216         return eRet;
217     }
218 
219     Paper convertToPaper(view::PaperFormat eFormat)
220     {
221         Paper eRet(PAPER_USER);
222         switch (eFormat)
223         {
224             case view::PaperFormat_A3:
225                 eRet = PAPER_A3;
226                 break;
227             case view::PaperFormat_A4:
228                 eRet = PAPER_A4;
229                 break;
230             case view::PaperFormat_A5:
231                 eRet = PAPER_A5;
232                 break;
233             case view::PaperFormat_B4:
234                 eRet = PAPER_B4_ISO;
235                 break;
236             case view::PaperFormat_B5:
237                 eRet = PAPER_B5_ISO;
238                 break;
239             case view::PaperFormat_LETTER:
240                 eRet = PAPER_LETTER;
241                 break;
242             case view::PaperFormat_LEGAL:
243                 eRet = PAPER_LEGAL;
244                 break;
245             case view::PaperFormat_TABLOID:
246                 eRet = PAPER_TABLOID;
247                 break;
248             case view::PaperFormat_USER:
249                 eRet = PAPER_USER;
250                 break;
251             case view::PaperFormat_MAKE_FIXED_SIZE:
252                 break;
253             //deliberate no default to force warn on a new papersize
254         }
255         return eRet;
256     }
257 }
258 
259 //________________________________________________________________________________________________________
260 //  XPrintable
261 //________________________________________________________________________________________________________
262 
263 uno::Sequence< beans::PropertyValue > SAL_CALL SfxPrintHelper::getPrinter() throw(::com::sun::star::uno::RuntimeException)
264 {
265     // object already disposed?
266     ::vos::OGuard aGuard( Application::GetSolarMutex() );
267 
268     // search for any view of this document that is currently printing
269     const Printer *pPrinter = NULL;
270     SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ? SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0;
271     SfxViewFrame* pFirst = pViewFrm;
272     while ( pViewFrm && !pPrinter )
273     {
274         pPrinter = pViewFrm->GetViewShell()->GetActivePrinter();
275         pViewFrm = SfxViewFrame::GetNext( *pViewFrm, m_pData->m_pObjectShell, sal_False );
276     }
277 
278     // if no view is printing currently, use the permanent SfxPrinter instance
279     if ( !pPrinter && pFirst )
280         pPrinter = pFirst->GetViewShell()->GetPrinter(sal_True);
281 
282     if ( !pPrinter )
283         return uno::Sequence< beans::PropertyValue >();
284 
285     uno::Sequence< beans::PropertyValue > aPrinter(8);
286 
287     aPrinter.getArray()[7].Name = DEFINE_CONST_UNICODE( "CanSetPaperSize" );
288     aPrinter.getArray()[7].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPERSIZE ) );
289 
290     aPrinter.getArray()[6].Name = DEFINE_CONST_UNICODE( "CanSetPaperFormat" );
291     aPrinter.getArray()[6].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPER ) );
292 
293     aPrinter.getArray()[5].Name = DEFINE_CONST_UNICODE( "CanSetPaperOrientation" );
294     aPrinter.getArray()[5].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_ORIENTATION ) );
295 
296     aPrinter.getArray()[4].Name = DEFINE_CONST_UNICODE( "IsBusy" );
297     aPrinter.getArray()[4].Value <<= ( pPrinter->IsPrinting() );
298 
299     aPrinter.getArray()[3].Name = DEFINE_CONST_UNICODE( "PaperSize" );
300     awt::Size aSize = impl_Size_Object2Struct(pPrinter->GetPaperSize() );
301     aPrinter.getArray()[3].Value <<= aSize;
302 
303     aPrinter.getArray()[2].Name = DEFINE_CONST_UNICODE( "PaperFormat" );
304     view::PaperFormat eFormat = convertToPaperFormat(pPrinter->GetPaper());
305     aPrinter.getArray()[2].Value <<= eFormat;
306 
307     aPrinter.getArray()[1].Name = DEFINE_CONST_UNICODE( "PaperOrientation" );
308     view::PaperOrientation eOrient = (view::PaperOrientation)pPrinter->GetOrientation();
309     aPrinter.getArray()[1].Value <<= eOrient;
310 
311     aPrinter.getArray()[0].Name = DEFINE_CONST_UNICODE( "Name" );
312     String sStringTemp = pPrinter->GetName() ;
313     aPrinter.getArray()[0].Value <<= ::rtl::OUString( sStringTemp );
314 
315     return aPrinter;
316 }
317 
318 //________________________________________________________________________________________________________
319 //  XPrintable
320 //________________________________________________________________________________________________________
321 
322 void SfxPrintHelper::impl_setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter,SfxPrinter*& pPrinter,sal_uInt16& nChangeFlags,SfxViewShell*& pViewSh)
323 
324 {
325     // alten Printer beschaffen
326     SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ?
327                                 SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0;
328     if ( !pViewFrm )
329         return;
330 
331     pViewSh = pViewFrm->GetViewShell();
332     pPrinter = pViewSh->GetPrinter(sal_True);
333     if ( !pPrinter )
334         return;
335 
336     // new Printer-Name available?
337     nChangeFlags = 0;
338     sal_Int32 lDummy = 0;
339     for ( int n = 0; n < rPrinter.getLength(); ++n )
340     {
341         // get Property-Value from printer description
342         const beans::PropertyValue &rProp = rPrinter.getConstArray()[n];
343 
344         // Name-Property?
345         if ( rProp.Name.compareToAscii( "Name" ) == 0 )
346         {
347             ::rtl::OUString sTemp;
348             if ( ( rProp.Value >>= sTemp ) == sal_False )
349                 throw ::com::sun::star::lang::IllegalArgumentException();
350 
351             String aPrinterName( sTemp ) ;
352             if ( aPrinterName != pPrinter->GetName() )
353             {
354                 pPrinter = new SfxPrinter( pPrinter->GetOptions().Clone(), aPrinterName );
355                 nChangeFlags = SFX_PRINTER_PRINTER;
356             }
357             break;
358         }
359     }
360 
361     Size aSetPaperSize( 0, 0);
362     view::PaperFormat nPaperFormat = view::PaperFormat_USER;
363 
364     // other properties
365     for ( int i = 0; i < rPrinter.getLength(); ++i )
366     {
367         // get Property-Value from printer description
368         const beans::PropertyValue &rProp = rPrinter.getConstArray()[i];
369 
370         // PaperOrientation-Property?
371         if ( rProp.Name.compareToAscii( "PaperOrientation" ) == 0 )
372         {
373             view::PaperOrientation eOrient;
374             if ( ( rProp.Value >>= eOrient ) == sal_False )
375             {
376                 if ( ( rProp.Value >>= lDummy ) == sal_False )
377                     throw ::com::sun::star::lang::IllegalArgumentException();
378                 eOrient = ( view::PaperOrientation) lDummy;
379             }
380 
381             if ( (Orientation) eOrient != pPrinter->GetOrientation() )
382             {
383                 pPrinter->SetOrientation( (Orientation) eOrient );
384                 nChangeFlags |= SFX_PRINTER_CHG_ORIENTATION;
385             }
386         }
387 
388         // PaperFormat-Property?
389         else if ( rProp.Name.compareToAscii( "PaperFormat" ) == 0 )
390         {
391             if ( ( rProp.Value >>= nPaperFormat ) == sal_False )
392             {
393                 if ( ( rProp.Value >>= lDummy ) == sal_False )
394                     throw ::com::sun::star::lang::IllegalArgumentException();
395                 nPaperFormat = ( view::PaperFormat ) lDummy;
396             }
397 
398             if ( convertToPaper(nPaperFormat) != pPrinter->GetPaper() )
399             {
400                 pPrinter->SetPaper( convertToPaper(nPaperFormat) );
401                 nChangeFlags |= SFX_PRINTER_CHG_SIZE;
402             }
403         }
404 
405         // PaperSize-Property?
406         else if ( rProp.Name.compareToAscii( "PaperSize" ) == 0 )
407         {
408             awt::Size aTempSize ;
409             if ( ( rProp.Value >>= aTempSize ) == sal_False )
410             {
411                 throw ::com::sun::star::lang::IllegalArgumentException();
412             }
413             else
414             {
415                 aSetPaperSize = impl_Size_Struct2Object(aTempSize);
416             }
417         }
418 
419         // PrinterTray-Property
420         else if ( rProp.Name.compareToAscii( "PrinterPaperTray" ) == 0 )
421         {
422             rtl::OUString aTmp;
423             if ( ( rProp.Value >>= aTmp ) == sal_False )
424                 throw ::com::sun::star::lang::IllegalArgumentException();
425             sal_uInt16 nCount = pPrinter->GetPaperBinCount();
426             for (sal_uInt16 nBin=0; nBin<nCount; nBin++)
427             {
428                 ::rtl::OUString aName( pPrinter->GetPaperBinName(nBin) );
429                 if ( aName == aTmp )
430                 {
431                     pPrinter->SetPaperBin(nBin);
432                     break;
433                 }
434             }
435         }
436     }
437 
438     //os 12.11.98: die PaperSize darf nur gesetzt werden, wenn tatsaechlich
439     //PAPER_USER gilt, sonst koennte vom Treiber ein falsches Format gewaehlt werden
440     if(nPaperFormat == view::PaperFormat_USER && aSetPaperSize.Width())
441     {
442         //JP 23.09.98 - Bug 56929 - MapMode von 100mm in die am
443         //          Device gesetzten umrechnen. Zusaetzlich nur dann
444         //          setzen, wenn sie wirklich veraendert wurden.
445         aSetPaperSize = pPrinter->LogicToPixel( aSetPaperSize, MAP_100TH_MM );
446         if( aSetPaperSize != pPrinter->GetPaperSizePixel() )
447         {
448             pPrinter->SetPaperSizeUser( pPrinter->PixelToLogic( aSetPaperSize ) );
449             nChangeFlags |= SFX_PRINTER_CHG_SIZE;
450         }
451     }
452 
453     // #96772#: wait until printing is done
454     SfxPrinter* pDocPrinter = pViewSh->GetPrinter();
455     while ( pDocPrinter->IsPrinting() )
456         Application::Yield();
457 }
458 
459 void SAL_CALL SfxPrintHelper::setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter)
460         throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
461 {
462     // object already disposed?
463     ::vos::OGuard aGuard( Application::GetSolarMutex() );
464 
465     SfxViewShell* pViewSh = NULL;
466     SfxPrinter* pPrinter = NULL;
467     sal_uInt16 nChangeFlags = 0;
468     impl_setPrinter(rPrinter,pPrinter,nChangeFlags,pViewSh);
469     // set new printer
470     if ( pViewSh && pPrinter )
471         pViewSh->SetPrinter( pPrinter, nChangeFlags, false );
472 }
473 
474 //________________________________________________________________________________________________________
475 //  ImplPrintWatch thread for asynchronous printing with moving temp. file to ucb location
476 //________________________________________________________________________________________________________
477 
478 /* This implements a thread which will be started to wait for asynchronous
479    print jobs to temp. localy files. If they finish we move the temp. files
480    to her right locations by using the ucb.
481  */
482 class ImplUCBPrintWatcher : public ::osl::Thread
483 {
484     private:
485         /// of course we must know the printer which execute the job
486         SfxPrinter* m_pPrinter;
487         /// this describes the target location for the printed temp file
488         String m_sTargetURL;
489         /// it holds the temp file alive, till the print job will finish and remove it from disk automaticly if the object die
490         ::utl::TempFile* m_pTempFile;
491 
492     public:
493         /* initialize this watcher but don't start it */
494         ImplUCBPrintWatcher( SfxPrinter* pPrinter, ::utl::TempFile* pTempFile, const String& sTargetURL )
495                 : m_pPrinter  ( pPrinter   )
496                 , m_sTargetURL( sTargetURL )
497                 , m_pTempFile ( pTempFile  )
498         {}
499 
500         /* waits for finishing of the print job and moves the temp file afterwards
501            Note: Starting of the job is done outside this thread!
502            But we have to free some of the given ressources on heap!
503          */
504         void SAL_CALL run()
505         {
506             /* SAFE { */
507             {
508                 ::vos::OGuard aGuard( Application::GetSolarMutex() );
509                 while( m_pPrinter->IsPrinting() )
510                     Application::Yield();
511                 m_pPrinter = NULL; // don't delete it! It's borrowed only :-)
512             }
513             /* } SAFE */
514 
515             // lock for further using of our member isn't neccessary - because
516             // we truns alone by defenition. Nobody join for us nor use us ...
517             ImplUCBPrintWatcher::moveAndDeleteTemp(&m_pTempFile,m_sTargetURL);
518 
519             // finishing of this run() method will call onTerminate() automaticly
520             // kill this thread there!
521         }
522 
523         /* nobody wait for this thread. We must kill ourself ...
524          */
525         void SAL_CALL onTerminated()
526         {
527             delete this;
528         }
529 
530         /* static helper to move the temp. file to the target location by using the ucb
531            It's static to be useable from outside too. So it's not realy neccessary to start
532            the thread, if finishing of the job was detected outside this thread.
533            But it must be called without using a corresponding thread for the given parameter!
534          */
535         static void moveAndDeleteTemp( ::utl::TempFile** ppTempFile, const String& sTargetURL )
536         {
537             // move the file
538             try
539             {
540                 INetURLObject aSplitter(sTargetURL);
541                 String        sFileName = aSplitter.getName(
542                                             INetURLObject::LAST_SEGMENT,
543                                             true,
544                                             INetURLObject::DECODE_WITH_CHARSET);
545                 if (aSplitter.removeSegment() && sFileName.Len()>0)
546                 {
547                     ::ucbhelper::Content aSource(
548                             ::rtl::OUString((*ppTempFile)->GetURL()),
549                             ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >());
550 
551                     ::ucbhelper::Content aTarget(
552                             ::rtl::OUString(aSplitter.GetMainURL(INetURLObject::NO_DECODE)),
553                             ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >());
554 
555                     aTarget.transferContent(
556                             aSource,
557                             ::ucbhelper::InsertOperation_COPY,
558                             ::rtl::OUString(sFileName),
559                             ::com::sun::star::ucb::NameClash::OVERWRITE);
560                 }
561             }
562             catch( ::com::sun::star::ucb::ContentCreationException& ) { DBG_ERROR("content create exception"); }
563             catch( ::com::sun::star::ucb::CommandAbortedException&  ) { DBG_ERROR("command abort exception"); }
564             catch( ::com::sun::star::uno::RuntimeException&         ) { DBG_ERROR("runtime exception"); }
565             catch( ::com::sun::star::uno::Exception&                ) { DBG_ERROR("unknown exception"); }
566 
567             // kill the temp file!
568             delete *ppTempFile;
569             *ppTempFile = NULL;
570         }
571 };
572 
573 //------------------------------------------------
574 
575 //________________________________________________________________________________________________________
576 //  XPrintable
577 //________________________________________________________________________________________________________
578 void SAL_CALL SfxPrintHelper::print(const uno::Sequence< beans::PropertyValue >& rOptions)
579         throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
580 {
581     if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
582         return;
583 
584     // object already disposed?
585     // object already disposed?
586     ::vos::OGuard aGuard( Application::GetSolarMutex() );
587 
588     // get view for sfx printing capabilities
589     SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ?
590                                 SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0;
591     if ( !pViewFrm )
592         return;
593     SfxViewShell* pView = pViewFrm->GetViewShell();
594     if ( !pView )
595         return;
596 
597 //  SfxAllItemSet aArgs( pView->GetPool() );
598     sal_Bool bMonitor = sal_False;
599     // We need this information at the end of this method, if we start the vcl printer
600     // by executing the slot. Because if it is a ucb relevant URL we must wait for
601     // finishing the print job and move the temporary local file by using the ucb
602     // to the right location. But in case of no file name is given or it is already
603     // a local one we can supress this special handling. Because then vcl makes all
604     // right for us.
605     String sUcbUrl;
606     ::utl::TempFile* pUCBPrintTempFile = NULL;
607 
608     uno::Sequence < beans::PropertyValue > aCheckedArgs( rOptions.getLength() );
609     sal_Int32 nProps = 0;
610     sal_Bool  bWaitUntilEnd = sal_False;
611     sal_Int16 nDuplexMode = ::com::sun::star::view::DuplexMode::UNKNOWN;
612     for ( int n = 0; n < rOptions.getLength(); ++n )
613     {
614         // get Property-Value from options
615         const beans::PropertyValue &rProp = rOptions.getConstArray()[n];
616 
617         // FileName-Property?
618         if ( rProp.Name.compareToAscii( "FileName" ) == 0 )
619         {
620             // unpack th URL and check for a valid and well known protocol
621             ::rtl::OUString sTemp;
622             if (
623                 ( rProp.Value.getValueType()!=::getCppuType((const ::rtl::OUString*)0))  ||
624                 (!(rProp.Value>>=sTemp))
625                )
626             {
627                 throw ::com::sun::star::lang::IllegalArgumentException();
628             }
629 
630             String        sPath        ;
631             String        sURL  (sTemp);
632             INetURLObject aCheck(sURL );
633             if (aCheck.GetProtocol()==INET_PROT_NOT_VALID)
634             {
635                 // OK - it's not a valid URL. But may it's a simple
636                 // system path directly. It will be supported for historical
637                 // reasons. Otherwhise we break to much external code ...
638                 // We try to convert it to a file URL. If its possible
639                 // we put the system path to the item set and let vcl work with it.
640                 // No ucb or thread will be neccessary then. In case it couldnt be
641                 // converted its not an URL nor a system path. Then we can't accept
642                 // this parameter and have to throw an exception.
643                 ::rtl::OUString sSystemPath(sTemp);
644                 ::rtl::OUString sFileURL;
645                 if (::osl::FileBase::getFileURLFromSystemPath(sSystemPath,sFileURL)!=::osl::FileBase::E_None)
646                     throw ::com::sun::star::lang::IllegalArgumentException();
647                 aCheckedArgs[nProps].Name = rProp.Name;
648                 aCheckedArgs[nProps++].Value <<= sFileURL;
649                 // and append the local filename
650                 aCheckedArgs.realloc( aCheckedArgs.getLength()+1 );
651                 aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName");
652                 aCheckedArgs[nProps++].Value <<= ::rtl::OUString( sTemp );
653             }
654             else
655             // It's a valid URL. but now we must know, if it is a local one or not.
656             // It's a question of using ucb or not!
657             if (::utl::LocalFileHelper::ConvertURLToSystemPath(sURL,sPath))
658             {
659                 // it's a local file, we can use vcl without special handling
660                 // And we have to use the system notation of the incoming URL.
661                 // But it into the descriptor and let the slot be executed at
662                 // the end of this method.
663                 aCheckedArgs[nProps].Name = rProp.Name;
664                 aCheckedArgs[nProps++].Value <<= sTemp;
665                 // and append the local filename
666                 aCheckedArgs.realloc( aCheckedArgs.getLength()+1 );
667                 aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName");
668                 aCheckedArgs[nProps++].Value <<= ::rtl::OUString( sPath );
669             }
670             else
671             {
672                 // it's an ucb target. So we must use a temp. file for vcl
673                 // and move it after printing by using the ucb.
674                 // Create a temp file on the heap (because it must delete the
675                 // real file on disk automaticly if it die - bt we have to share it with
676                 // some other sources ... e.g. the ImplUCBPrintWatcher).
677                 // And we put the name of this temp file to the descriptor instead
678                 // of the URL. The URL we save for later using seperatly.
679                 // Execution of the print job will be done later by executing
680                 // a slot ...
681                 pUCBPrintTempFile = new ::utl::TempFile();
682                 pUCBPrintTempFile->EnableKillingFile();
683 
684                 //FIXME: does it work?
685                 aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("LocalFileName");
686                 aCheckedArgs[nProps++].Value <<= ::rtl::OUString( pUCBPrintTempFile->GetFileName() );
687                 sUcbUrl = sURL;
688             }
689         }
690 
691         // CopyCount-Property
692         else if ( rProp.Name.compareToAscii( "CopyCount" ) == 0 )
693         {
694             sal_Int32 nCopies = 0;
695             if ( ( rProp.Value >>= nCopies ) == sal_False )
696                 throw ::com::sun::star::lang::IllegalArgumentException();
697 
698             aCheckedArgs[nProps].Name = rProp.Name;
699             aCheckedArgs[nProps++].Value <<= nCopies;
700         }
701 
702         // Collate-Property
703         // Sort-Property (deprecated)
704         else if ( rProp.Name.compareToAscii( "Collate" ) == 0 ||
705                 ( rProp.Name.compareToAscii( "Sort" ) == 0 ) )
706         {
707             sal_Bool bTemp = sal_Bool();
708             if ( rProp.Value >>= bTemp )
709             {
710                 aCheckedArgs[nProps].Name = rtl::OUString::createFromAscii("Collate");
711                 aCheckedArgs[nProps++].Value <<= bTemp;
712             }
713             else
714                 throw ::com::sun::star::lang::IllegalArgumentException();
715         }
716 
717         // Pages-Property
718         else if ( rProp.Name.compareToAscii( "Pages" ) == 0 )
719         {
720             ::rtl::OUString sTemp;
721             if( rProp.Value >>= sTemp )
722             {
723                 aCheckedArgs[nProps].Name = rProp.Name;
724                 aCheckedArgs[nProps++].Value <<= sTemp;
725             }
726             else
727                 throw ::com::sun::star::lang::IllegalArgumentException();
728         }
729 
730         // MonitorVisible
731         else if ( rProp.Name.compareToAscii( "MonitorVisible" ) == 0 )
732         {
733             if( !(rProp.Value >>= bMonitor) )
734                 throw ::com::sun::star::lang::IllegalArgumentException();
735             aCheckedArgs[nProps].Name = rProp.Name;
736             aCheckedArgs[nProps++].Value <<= bMonitor;
737         }
738 
739         // Wait
740         else if ( rProp.Name.compareToAscii( "Wait" ) == 0 )
741         {
742             if ( !(rProp.Value >>= bWaitUntilEnd) )
743                 throw ::com::sun::star::lang::IllegalArgumentException();
744             aCheckedArgs[nProps].Name = rProp.Name;
745             aCheckedArgs[nProps++].Value <<= bWaitUntilEnd;
746         }
747 
748         else if ( rProp.Name.compareToAscii( "DuplexMode" ) == 0 )
749         {
750             if ( !(rProp.Value >>= nDuplexMode ) )
751                 throw ::com::sun::star::lang::IllegalArgumentException();
752             aCheckedArgs[nProps].Name = rProp.Name;
753             aCheckedArgs[nProps++].Value <<= nDuplexMode;
754         }
755     }
756 
757     if ( nProps != aCheckedArgs.getLength() )
758         aCheckedArgs.realloc(nProps);
759 
760     // Execute the print request every time.
761     // It doesn'tmatter if it is a real printer used or we print to a local file
762     // nor if we print to a temp file and move it afterwards by using the ucb.
763     // That will be handled later. see pUCBPrintFile below!
764     pView->ExecPrint( aCheckedArgs, sal_True, sal_False );
765 
766     // Ok - may be execution before has finished (or started!) printing.
767     // And may it was a printing to a file.
768     // Now we have to check if we can move the file (if neccessary) via ucb to his right location.
769     // Cases:
770     //  a) printing finished                        => move the file directly and forget the watcher thread
771     //  b) printing is asynchron and runs currently => start watcher thread and exit this method
772     //                                                 This thread make all neccessary things by itself.
773     if (pUCBPrintTempFile!=NULL)
774     {
775         // a)
776         SfxPrinter* pPrinter = pView->GetPrinter();
777         if ( ! pPrinter->IsPrinting() )
778             ImplUCBPrintWatcher::moveAndDeleteTemp(&pUCBPrintTempFile,sUcbUrl);
779         // b)
780         else
781         {
782             // Note: we create(d) some ressource on the heap. (thread and tep file)
783             // They will be delected by the thread automaticly if he finish his run() method.
784             ImplUCBPrintWatcher* pWatcher = new ImplUCBPrintWatcher( pPrinter, pUCBPrintTempFile, sUcbUrl );
785             pWatcher->create();
786         }
787     }
788 }
789 
790 void IMPL_PrintListener_DataContainer::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
791 {
792     if ( &rBC == m_pObjectShell )
793     {
794         SfxPrintingHint* pPrintHint = PTR_CAST( SfxPrintingHint, &rHint );
795         if ( pPrintHint )
796         {
797             if ( pPrintHint->GetWhich() == com::sun::star::view::PrintableState_JOB_STARTED )
798             {
799                 if ( !m_xPrintJob.is() )
800                     m_xPrintJob = new SfxPrintJob_Impl( this );
801                 m_aPrintOptions = pPrintHint->GetOptions();
802             }
803             else if ( pPrintHint->GetWhich() != -2 )    // -2 : CancelPrintJob
804             {
805                 view::PrintJobEvent aEvent;
806                 aEvent.Source = m_xPrintJob;
807                 aEvent.State = (com::sun::star::view::PrintableState) pPrintHint->GetWhich();
808                 ::cppu::OInterfaceContainerHelper* pContainer = m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< view::XPrintJobListener >*) NULL ) );
809                 if ( pContainer!=NULL )
810                 {
811                     ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
812                     while (pIterator.hasMoreElements())
813                         ((view::XPrintJobListener*)pIterator.next())->printJobEvent( aEvent );
814                 }
815             }
816         }
817     }
818 }
819 
820 void SAL_CALL SfxPrintHelper::addPrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
821 {
822     ::vos::OGuard aGuard( Application::GetSolarMutex() );
823     m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener );
824 }
825 
826 void SAL_CALL SfxPrintHelper::removePrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
827 {
828     ::vos::OGuard aGuard( Application::GetSolarMutex() );
829     m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener );
830 }
831 
832 
833