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