xref: /aoo42x/main/sfx2/source/doc/printhelper.cxx (revision d119d52d)
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 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::uno;
65 
66 struct IMPL_PrintListener_DataContainer : public SfxListener
67 {
68     SfxObjectShellRef                               m_pObjectShell;
69     ::cppu::OMultiTypeInterfaceContainerHelper      m_aInterfaceContainer;
70     uno::Reference< com::sun::star::view::XPrintJob>     m_xPrintJob;
71 	::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aPrintOptions;
72 
73     IMPL_PrintListener_DataContainer( ::osl::Mutex& aMutex)
74             :   m_pObjectShell          ( 0 )
75             ,   m_aInterfaceContainer   ( aMutex )
76 	{
77 	}
78 
79 
80 	void Notify(			SfxBroadcaster&	aBC		,
81 					const	SfxHint&		aHint	) ;
82 };
83 
84 awt::Size impl_Size_Object2Struct( const Size& aSize )
85 {
86     awt::Size aReturnValue;
87 	aReturnValue.Width  = aSize.Width()  ;
88 	aReturnValue.Height = aSize.Height() ;
89 	return aReturnValue ;
90 }
91 
92 Size impl_Size_Struct2Object( const awt::Size& aSize )
93 {
94 	Size aReturnValue;
95 	aReturnValue.Width()  = aSize.Width  ;
96 	aReturnValue.Height() = aSize.Height ;
97 	return aReturnValue ;
98 }
99 
100 class SfxPrintJob_Impl : public cppu::WeakImplHelper1
101 <
102 	com::sun::star::view::XPrintJob
103 >
104 {
105         IMPL_PrintListener_DataContainer* m_pData;
106 
107 public:
108         SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData );
109     	virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrintOptions(  ) throw (RuntimeException);
110     	virtual Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPrinter(  ) throw (RuntimeException);
111     	virtual Reference< ::com::sun::star::view::XPrintable > SAL_CALL getPrintable(  ) throw (RuntimeException);
112 		virtual void SAL_CALL cancelJob() throw (RuntimeException);
113 };
114 
115 SfxPrintJob_Impl::SfxPrintJob_Impl( IMPL_PrintListener_DataContainer* pData )
116 	: m_pData( pData )
117 {
118 }
119 
120 Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrintOptions() throw (RuntimeException)
121 {
122 	return m_pData->m_aPrintOptions;
123 }
124 
125 Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SfxPrintJob_Impl::getPrinter() throw (RuntimeException)
126 {
127 	if( m_pData->m_pObjectShell.Is() )
128 	{
129 		Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell->GetModel(), UNO_QUERY );
130 		if ( xPrintable.is() )
131 			return xPrintable->getPrinter();
132 	}
133 	return Sequence< ::com::sun::star::beans::PropertyValue >();
134 }
135 
136 Reference< ::com::sun::star::view::XPrintable > SAL_CALL SfxPrintJob_Impl::getPrintable() throw (RuntimeException)
137 {
138 	Reference < view::XPrintable > xPrintable( m_pData->m_pObjectShell.Is() ? m_pData->m_pObjectShell->GetModel() : NULL, UNO_QUERY );
139 	return xPrintable;
140 }
141 
142 void SAL_CALL SfxPrintJob_Impl::cancelJob() throw (RuntimeException)
143 {
144 	// FIXME: how to cancel PrintJob via API?!
145 	if( m_pData->m_pObjectShell.Is() )
146 		m_pData->m_pObjectShell->Broadcast( SfxPrintingHint( -2 ) );
147 }
148 
149 SfxPrintHelper::SfxPrintHelper()
150 {
151     m_pData = new IMPL_PrintListener_DataContainer(m_aMutex);
152 }
153 
154 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)
155 {
156 	if ( aArguments.getLength() )
157 	{
158         com::sun::star::uno::Reference < com::sun::star::frame::XModel > xModel;
159         aArguments[0] >>= xModel;
160         uno::Reference < lang::XUnoTunnel > xObj( xModel, uno::UNO_QUERY );
161         uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
162         sal_Int64 nHandle = xObj->getSomething( aSeq );
163         if ( nHandle )
164         {
165             m_pData->m_pObjectShell = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle ));
166             m_pData->StartListening(*m_pData->m_pObjectShell);
167         }
168 	}
169 }
170 
171 SfxPrintHelper::~SfxPrintHelper()
172 {
173     delete m_pData;
174 }
175 
176 namespace
177 {
178     view::PaperFormat convertToPaperFormat(Paper eFormat)
179     {
180         view::PaperFormat eRet;
181         switch (eFormat)
182         {
183             case PAPER_A3:
184                 eRet = view::PaperFormat_A3;
185                 break;
186             case PAPER_A4:
187                 eRet = view::PaperFormat_A4;
188                 break;
189             case PAPER_A5:
190                 eRet = view::PaperFormat_A5;
191                 break;
192             case PAPER_B4_ISO:
193                 eRet = view::PaperFormat_B4;
194                 break;
195             case PAPER_B5_ISO:
196                 eRet = view::PaperFormat_B5;
197                 break;
198             case PAPER_LETTER:
199                 eRet = view::PaperFormat_LETTER;
200                 break;
201             case PAPER_LEGAL:
202                 eRet = view::PaperFormat_LEGAL;
203                 break;
204             case PAPER_TABLOID:
205                 eRet = view::PaperFormat_TABLOID;
206                 break;
207             case PAPER_USER:
208             default:
209                 eRet = view::PaperFormat_USER;
210                 break;
211         }
212         return eRet;
213     }
214 
215     Paper convertToPaper(view::PaperFormat eFormat)
216     {
217         Paper eRet(PAPER_USER);
218         switch (eFormat)
219         {
220             case view::PaperFormat_A3:
221                 eRet = PAPER_A3;
222                 break;
223             case view::PaperFormat_A4:
224                 eRet = PAPER_A4;
225                 break;
226             case view::PaperFormat_A5:
227                 eRet = PAPER_A5;
228                 break;
229             case view::PaperFormat_B4:
230                 eRet = PAPER_B4_ISO;
231                 break;
232             case view::PaperFormat_B5:
233                 eRet = PAPER_B5_ISO;
234                 break;
235             case view::PaperFormat_LETTER:
236                 eRet = PAPER_LETTER;
237                 break;
238             case view::PaperFormat_LEGAL:
239                 eRet = PAPER_LEGAL;
240                 break;
241             case view::PaperFormat_TABLOID:
242                 eRet = PAPER_TABLOID;
243                 break;
244             case view::PaperFormat_USER:
245                 eRet = PAPER_USER;
246                 break;
247             case view::PaperFormat_MAKE_FIXED_SIZE:
248                 break;
249             //deliberate no default to force warn on a new papersize
250         }
251         return eRet;
252     }
253 }
254 
255 //________________________________________________________________________________________________________
256 //	XPrintable
257 //________________________________________________________________________________________________________
258 
259 uno::Sequence< beans::PropertyValue > SAL_CALL SfxPrintHelper::getPrinter() throw(::com::sun::star::uno::RuntimeException)
260 {
261     // object already disposed?
262     ::vos::OGuard aGuard( Application::GetSolarMutex() );
263 
264     // search for any view of this document that is currently printing
265     const Printer *pPrinter = NULL;
266     SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ? SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0;
267     SfxViewFrame* pFirst = pViewFrm;
268     while ( pViewFrm && !pPrinter )
269     {
270     	pPrinter = pViewFrm->GetViewShell()->GetActivePrinter();
271         pViewFrm = SfxViewFrame::GetNext( *pViewFrm, m_pData->m_pObjectShell, sal_False );
272     }
273 
274     // if no view is printing currently, use the permanent SfxPrinter instance
275     if ( !pPrinter && pFirst )
276     	pPrinter = pFirst->GetViewShell()->GetPrinter(sal_True);
277 
278     if ( !pPrinter )
279         return uno::Sequence< beans::PropertyValue >();
280 
281     uno::Sequence< beans::PropertyValue > aPrinter(8);
282 
283 	aPrinter.getArray()[7].Name = DEFINE_CONST_UNICODE( "CanSetPaperSize" );
284 	aPrinter.getArray()[7].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPERSIZE ) );
285 
286 	aPrinter.getArray()[6].Name = DEFINE_CONST_UNICODE( "CanSetPaperFormat" );
287 	aPrinter.getArray()[6].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_PAPER ) );
288 
289 	aPrinter.getArray()[5].Name = DEFINE_CONST_UNICODE( "CanSetPaperOrientation" );
290 	aPrinter.getArray()[5].Value <<= ( pPrinter->HasSupport( SUPPORT_SET_ORIENTATION ) );
291 
292 	aPrinter.getArray()[4].Name = DEFINE_CONST_UNICODE( "IsBusy" );
293 	aPrinter.getArray()[4].Value <<= ( pPrinter->IsPrinting() );
294 
295 	aPrinter.getArray()[3].Name = DEFINE_CONST_UNICODE( "PaperSize" );
296     awt::Size aSize = impl_Size_Object2Struct(pPrinter->GetPaperSize() );
297 	aPrinter.getArray()[3].Value <<= aSize;
298 
299 	aPrinter.getArray()[2].Name = DEFINE_CONST_UNICODE( "PaperFormat" );
300     view::PaperFormat eFormat = convertToPaperFormat(pPrinter->GetPaper());
301 	aPrinter.getArray()[2].Value <<= eFormat;
302 
303 	aPrinter.getArray()[1].Name = DEFINE_CONST_UNICODE( "PaperOrientation" );
304     view::PaperOrientation eOrient = (view::PaperOrientation)pPrinter->GetOrientation();
305 	aPrinter.getArray()[1].Value <<= eOrient;
306 
307 	aPrinter.getArray()[0].Name = DEFINE_CONST_UNICODE( "Name" );
308 	String sStringTemp = pPrinter->GetName() ;
309 	aPrinter.getArray()[0].Value <<= ::rtl::OUString( sStringTemp );
310 
311 	return aPrinter;
312 }
313 
314 //________________________________________________________________________________________________________
315 //	XPrintable
316 //________________________________________________________________________________________________________
317 
318 void SfxPrintHelper::impl_setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter,SfxPrinter*& pPrinter,sal_uInt16& nChangeFlags,SfxViewShell*& pViewSh)
319 
320 {
321 	// alten Printer beschaffen
322 	SfxViewFrame *pViewFrm = m_pData->m_pObjectShell.Is() ?
323 								SfxViewFrame::GetFirst( m_pData->m_pObjectShell, sal_False ) : 0;
324 	if ( !pViewFrm )
325 		return;
326 
327 	pViewSh = pViewFrm->GetViewShell();
328 	pPrinter = pViewSh->GetPrinter(sal_True);
329 	if ( !pPrinter )
330 		return;
331 
332 	// new Printer-Name available?
333 	nChangeFlags = 0;
334     sal_Int32 lDummy = 0;
335 	for ( int n = 0; n < rPrinter.getLength(); ++n )
336 	{
337 		// get Property-Value from printer description
338         const beans::PropertyValue &rProp = rPrinter.getConstArray()[n];
339 
340 		// Name-Property?
341 		if ( rProp.Name.compareToAscii( "Name" ) == 0 )
342 		{
343 			::rtl::OUString sTemp;
344             if ( ( rProp.Value >>= sTemp ) == sal_False )
345                 throw ::com::sun::star::lang::IllegalArgumentException();
346 
347 			String aPrinterName( sTemp ) ;
348             if ( aPrinterName != pPrinter->GetName() )
349             {
350                 pPrinter = new SfxPrinter( pPrinter->GetOptions().Clone(), aPrinterName );
351                 nChangeFlags = SFX_PRINTER_PRINTER;
352             }
353 			break;
354 		}
355 	}
356 
357 	Size aSetPaperSize( 0, 0);
358     view::PaperFormat nPaperFormat = view::PaperFormat_USER;
359 
360     // other properties
361 	for ( int i = 0; i < rPrinter.getLength(); ++i )
362 	{
363 		// get Property-Value from printer description
364         const beans::PropertyValue &rProp = rPrinter.getConstArray()[i];
365 
366 		// PaperOrientation-Property?
367 		if ( rProp.Name.compareToAscii( "PaperOrientation" ) == 0 )
368 		{
369             view::PaperOrientation eOrient;
370             if ( ( rProp.Value >>= eOrient ) == sal_False )
371             {
372                 if ( ( rProp.Value >>= lDummy ) == sal_False )
373                     throw ::com::sun::star::lang::IllegalArgumentException();
374                 eOrient = ( view::PaperOrientation) lDummy;
375             }
376 
377             if ( (Orientation) eOrient != pPrinter->GetOrientation() )
378             {
379                 pPrinter->SetOrientation( (Orientation) eOrient );
380                 nChangeFlags |= SFX_PRINTER_CHG_ORIENTATION;
381             }
382 		}
383 
384 		// PaperFormat-Property?
385 		else if ( rProp.Name.compareToAscii( "PaperFormat" ) == 0 )
386 		{
387 			if ( ( rProp.Value >>= nPaperFormat ) == sal_False )
388             {
389                 if ( ( rProp.Value >>= lDummy ) == sal_False )
390                     throw ::com::sun::star::lang::IllegalArgumentException();
391                 nPaperFormat = ( view::PaperFormat ) lDummy;
392             }
393 
394             if ( convertToPaper(nPaperFormat) != pPrinter->GetPaper() )
395             {
396                 pPrinter->SetPaper( convertToPaper(nPaperFormat) );
397                 nChangeFlags |= SFX_PRINTER_CHG_SIZE;
398             }
399 		}
400 
401 		// PaperSize-Property?
402 		else if ( rProp.Name.compareToAscii( "PaperSize" ) == 0 )
403 		{
404             awt::Size aTempSize ;
405 			if ( ( rProp.Value >>= aTempSize ) == sal_False )
406 			{
407                 throw ::com::sun::star::lang::IllegalArgumentException();
408 			}
409 			else
410 			{
411 				aSetPaperSize = impl_Size_Struct2Object(aTempSize);
412 			}
413 		}
414 
415 		// PrinterTray-Property
416 		else if ( rProp.Name.compareToAscii( "PrinterPaperTray" ) == 0 )
417 		{
418 			rtl::OUString aTmp;
419 			if ( ( rProp.Value >>= aTmp ) == sal_False )
420                 throw ::com::sun::star::lang::IllegalArgumentException();
421 			sal_uInt16 nCount = pPrinter->GetPaperBinCount();
422             for (sal_uInt16 nBin=0; nBin<nCount; nBin++)
423 			{
424                 ::rtl::OUString aName( pPrinter->GetPaperBinName(nBin) );
425 				if ( aName == aTmp )
426 				{
427                     pPrinter->SetPaperBin(nBin);
428 					break;
429 				}
430 			}
431 		}
432 	}
433 
434 	//os 12.11.98: die PaperSize darf nur gesetzt werden, wenn tatsaechlich
435 	//PAPER_USER gilt, sonst koennte vom Treiber ein falsches Format gewaehlt werden
436     if(nPaperFormat == view::PaperFormat_USER && aSetPaperSize.Width())
437 	{
438 		//JP 23.09.98 - Bug 56929 - MapMode von 100mm in die am
439 		//			Device gesetzten umrechnen. Zusaetzlich nur dann
440 		//			setzen, wenn sie wirklich veraendert wurden.
441 		aSetPaperSize = pPrinter->LogicToPixel( aSetPaperSize, MAP_100TH_MM );
442 		if( aSetPaperSize != pPrinter->GetPaperSizePixel() )
443 		{
444 			pPrinter->SetPaperSizeUser( pPrinter->PixelToLogic( aSetPaperSize ) );
445 			nChangeFlags |= SFX_PRINTER_CHG_SIZE;
446 		}
447 	}
448 
449     // #96772#: wait until printing is done
450     SfxPrinter* pDocPrinter = pViewSh->GetPrinter();
451     while ( pDocPrinter->IsPrinting() )
452         Application::Yield();
453 }
454 
455 void SAL_CALL SfxPrintHelper::setPrinter(const uno::Sequence< beans::PropertyValue >& rPrinter)
456         throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
457 {
458 	// object already disposed?
459     ::vos::OGuard aGuard( Application::GetSolarMutex() );
460 
461 	SfxViewShell* pViewSh = NULL;
462 	SfxPrinter* pPrinter = NULL;
463 	sal_uInt16 nChangeFlags = 0;
464 	impl_setPrinter(rPrinter,pPrinter,nChangeFlags,pViewSh);
465 	// set new printer
466 	if ( pViewSh && pPrinter )
467         pViewSh->SetPrinter( pPrinter, nChangeFlags, false );
468 }
469 
470 //________________________________________________________________________________________________________
471 //  ImplPrintWatch thread for asynchronous printing with moving temp. file to ucb location
472 //________________________________________________________________________________________________________
473 
474 /* This implements a thread which will be started to wait for asynchronous
475    print jobs to temp. localy files. If they finish we move the temp. files
476    to her right locations by using the ucb.
477  */
478 class ImplUCBPrintWatcher : public ::osl::Thread
479 {
480     private:
481         /// of course we must know the printer which execute the job
482         SfxPrinter* m_pPrinter;
483         /// this describes the target location for the printed temp file
484         String m_sTargetURL;
485         /// it holds the temp file alive, till the print job will finish and remove it from disk automaticly if the object die
486         ::utl::TempFile* m_pTempFile;
487 
488     public:
489         /* initialize this watcher but don't start it */
490         ImplUCBPrintWatcher( SfxPrinter* pPrinter, ::utl::TempFile* pTempFile, const String& sTargetURL )
491                 : m_pPrinter  ( pPrinter   )
492                 , m_sTargetURL( sTargetURL )
493                 , m_pTempFile ( pTempFile  )
494         {}
495 
496         /* waits for finishing of the print job and moves the temp file afterwards
497            Note: Starting of the job is done outside this thread!
498            But we have to free some of the given ressources on heap!
499          */
500         void SAL_CALL run()
501         {
502             /* SAFE { */
503             {
504                 ::vos::OGuard aGuard( Application::GetSolarMutex() );
505                 while( m_pPrinter->IsPrinting() )
506                     Application::Yield();
507                 m_pPrinter = NULL; // don't delete it! It's borrowed only :-)
508             }
509             /* } SAFE */
510 
511             // lock for further using of our member isn't neccessary - because
512             // we truns alone by defenition. Nobody join for us nor use us ...
513             ImplUCBPrintWatcher::moveAndDeleteTemp(&m_pTempFile,m_sTargetURL);
514 
515             // finishing of this run() method will call onTerminate() automaticly
516             // kill this thread there!
517         }
518 
519         /* nobody wait for this thread. We must kill ourself ...
520          */
521         void SAL_CALL onTerminated()
522         {
523             delete this;
524         }
525 
526         /* static helper to move the temp. file to the target location by using the ucb
527            It's static to be useable from outside too. So it's not realy neccessary to start
528            the thread, if finishing of the job was detected outside this thread.
529            But it must be called without using a corresponding thread for the given parameter!
530          */
531         static void moveAndDeleteTemp( ::utl::TempFile** ppTempFile, const String& sTargetURL )
532         {
533             // move the file
534             try
535             {
536 				INetURLObject aSplitter(sTargetURL);
537 				String		  sFileName = aSplitter.getName(
538 											INetURLObject::LAST_SEGMENT,
539 											true,
540 											INetURLObject::DECODE_WITH_CHARSET);
541 				if (aSplitter.removeSegment() && sFileName.Len()>0)
542 				{
543 					::ucbhelper::Content aSource(
544 							::rtl::OUString((*ppTempFile)->GetURL()),
545 							::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >());
546 
547 					::ucbhelper::Content aTarget(
548 							::rtl::OUString(aSplitter.GetMainURL(INetURLObject::NO_DECODE)),
549 							::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >());
550 
551 					aTarget.transferContent(
552 							aSource,
553 							::ucbhelper::InsertOperation_COPY,
554 							::rtl::OUString(sFileName),
555 							::com::sun::star::ucb::NameClash::OVERWRITE);
556 				}
557             }
558             catch( ::com::sun::star::ucb::ContentCreationException& ) { DBG_ERROR("content create exception"); }
559             catch( ::com::sun::star::ucb::CommandAbortedException&  ) { DBG_ERROR("command abort exception"); }
560             catch( ::com::sun::star::uno::RuntimeException&         ) { DBG_ERROR("runtime exception"); }
561             catch( ::com::sun::star::uno::Exception&                ) { DBG_ERROR("unknown exception"); }
562 
563             // kill the temp file!
564             delete *ppTempFile;
565             *ppTempFile = NULL;
566         }
567 };
568 
569 //------------------------------------------------
570 
571 //________________________________________________________________________________________________________
572 //  XPrintable
573 //________________________________________________________________________________________________________
574 void SAL_CALL SfxPrintHelper::print(const uno::Sequence< beans::PropertyValue >& rOptions)
575         throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
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 supress 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 may it's a simple
632                 // system path directly. It will be supported for historical
633                 // reasons. Otherwhise we break to much external code ...
634                 // We try to convert it to a file URL. If its possible
635                 // we put the system path to the item set and let vcl work with it.
636                 // No ucb or thread will be neccessary then. In case it couldnt 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 automaticly 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 neccessary) 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 neccessary 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 ressource on the heap. (thread and tep file)
779             // They will be delected by the thread automaticly if he finish his run() method.
780             ImplUCBPrintWatcher* pWatcher = new ImplUCBPrintWatcher( pPrinter, pUCBPrintTempFile, sUcbUrl );
781             pWatcher->create();
782         }
783     }
784 }
785 
786 void IMPL_PrintListener_DataContainer::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
787 {
788     if ( &rBC == m_pObjectShell )
789 	{
790 		SfxPrintingHint* pPrintHint = PTR_CAST( SfxPrintingHint, &rHint );
791 		if ( pPrintHint )
792 		{
793 			if ( pPrintHint->GetWhich() == com::sun::star::view::PrintableState_JOB_STARTED )
794 			{
795                 if ( !m_xPrintJob.is() )
796                     m_xPrintJob = new SfxPrintJob_Impl( this );
797 				m_aPrintOptions = pPrintHint->GetOptions();
798 			}
799             else if ( pPrintHint->GetWhich() != -2 )    // -2 : CancelPrintJob
800 			{
801 				view::PrintJobEvent aEvent;
802                 aEvent.Source = m_xPrintJob;
803 				aEvent.State = (com::sun::star::view::PrintableState) pPrintHint->GetWhich();
804                 ::cppu::OInterfaceContainerHelper* pContainer = m_aInterfaceContainer.getContainer( ::getCppuType( ( const uno::Reference< view::XPrintJobListener >*) NULL ) );
805 			    if ( pContainer!=NULL )
806 				{
807 			        ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
808 			        while (pIterator.hasMoreElements())
809 						((view::XPrintJobListener*)pIterator.next())->printJobEvent( aEvent );
810 				}
811 			}
812 		}
813 	}
814 }
815 
816 void SAL_CALL SfxPrintHelper::addPrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
817 {
818     ::vos::OGuard aGuard( Application::GetSolarMutex() );
819     m_pData->m_aInterfaceContainer.addInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener );
820 }
821 
822 void SAL_CALL SfxPrintHelper::removePrintJobListener( const ::com::sun::star::uno::Reference< ::com::sun::star::view::XPrintJobListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
823 {
824     ::vos::OGuard aGuard( Application::GetSolarMutex() );
825     m_pData->m_aInterfaceContainer.removeInterface( ::getCppuType((const uno::Reference < view::XPrintJobListener>*)0), xListener );
826 }
827 
828 
829