Coverage Report

Created: 2025-11-16 09:57

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