Coverage Report

Created: 2026-10-14 09:33

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