xref: /trunk/main/sfx2/source/doc/printhelper.cxx (revision cdf0e10c)
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