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