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