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