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