Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/view/viewprn.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
#include <memory>
21
22
#include <com/sun/star/document/XDocumentProperties.hpp>
23
#include <com/sun/star/frame/XModel3.hpp>
24
#include <com/sun/star/view/PrintableState.hpp>
25
#include <com/sun/star/view/XRenderable.hpp>
26
#include <com/sun/star/view/XSelectionSupplier.hpp>
27
28
#include <comphelper/propertyvalue.hxx>
29
#include <comphelper/sequenceashashmap.hxx>
30
#include <officecfg/Office/Common.hxx>
31
#include <sal/log.hxx>
32
#include <utility>
33
#include <vcl/svapp.hxx>
34
#include <vcl/vclenum.hxx>
35
#include <vcl/weld/MessageDialog.hxx>
36
#include <svtools/prnsetup.hxx>
37
#include <svl/flagitem.hxx>
38
#include <svl/stritem.hxx>
39
#include <svl/eitem.hxx>
40
#include <unotools/useroptions.hxx>
41
#include <tools/datetime.hxx>
42
#include <sfx2/bindings.hxx>
43
#include <sfx2/objface.hxx>
44
#include <sfx2/viewsh.hxx>
45
#include "viewimp.hxx"
46
#include <sfx2/viewfrm.hxx>
47
#include <sfx2/printer.hxx>
48
#include <sfx2/sfxresid.hxx>
49
#include <sfx2/request.hxx>
50
#include <sfx2/objsh.hxx>
51
#include <sfx2/event.hxx>
52
#include <sfx2/docfile.hxx>
53
#include <sfx2/docfilt.hxx>
54
#include <sfx2/sfxsids.hrc>
55
#include <sfx2/strings.hrc>
56
#include <sfx2/sfxuno.hxx>
57
#include <sfx2/tabdlg.hxx>
58
59
#include <toolkit/awt/vclxdevice.hxx>
60
61
#include "prnmon.hxx"
62
63
using namespace com::sun::star;
64
using namespace com::sun::star::uno;
65
66
class SfxPrinterController : public vcl::PrinterController, public SfxListener
67
{
68
    Any                                     maCompleteSelection;
69
    Any                                     maSelection;
70
    Reference< view::XRenderable >          mxRenderable;
71
    mutable VclPtr<Printer>                 mpLastPrinter;
72
    mutable Reference<awt::XDevice>         mxDevice;
73
    SfxViewShell*                           mpViewShell;
74
    SfxObjectShell*                         mpObjectShell;
75
    bool        m_bJobStarted;
76
    bool        m_bOrigStatus;
77
    bool        m_bNeedsChange;
78
    bool        m_bApi;
79
    bool        m_bTempPrinter;
80
    util::DateTime  m_aLastPrinted;
81
    OUString m_aLastPrintedBy;
82
83
    Sequence< beans::PropertyValue > getMergedOptions() const;
84
    const Any& getSelectionObject() const;
85
86
public:
87
    SfxPrinterController( const VclPtr<Printer>& i_rPrinter,
88
                          Any i_Complete,
89
                          Any i_Selection,
90
                          const Any& i_rViewProp,
91
                          const Reference< view::XRenderable >& i_xRender,
92
                          bool i_bApi, bool i_bDirect,
93
                          SfxViewShell* pView,
94
                          const uno::Sequence< beans::PropertyValue >& rProps
95
                        );
96
97
    virtual void Notify( SfxBroadcaster&, const SfxHint& ) override;
98
99
    virtual int  getPageCount() const override;
100
    virtual Sequence< beans::PropertyValue > getPageParameters( int i_nPage ) const override;
101
    virtual void printPage( int i_nPage ) const override;
102
    virtual void jobStarted() override;
103
    virtual void jobFinished( css::view::PrintableState ) override;
104
};
105
106
SfxPrinterController::SfxPrinterController( const VclPtr<Printer>& i_rPrinter,
107
                                            Any i_Complete,
108
                                            Any i_Selection,
109
                                            const Any& i_rViewProp,
110
                                            const Reference< view::XRenderable >& i_xRender,
111
                                            bool i_bApi, bool i_bDirect,
112
                                            SfxViewShell* pView,
113
                                            const uno::Sequence< beans::PropertyValue >& rProps
114
                                          )
115
0
    : PrinterController(i_rPrinter, pView ? pView->GetFrameWeld() : nullptr)
116
0
    , maCompleteSelection(std::move( i_Complete ))
117
0
    , maSelection(std::move( i_Selection ))
118
0
    , mxRenderable( i_xRender )
119
0
    , mpLastPrinter( nullptr )
120
0
    , mpViewShell( pView )
121
0
    , mpObjectShell(nullptr)
122
0
    , m_bJobStarted( false )
123
0
    , m_bOrigStatus( false )
124
0
    , m_bNeedsChange( false )
125
0
    , m_bApi(i_bApi)
126
0
    , m_bTempPrinter( i_rPrinter )
127
0
{
128
0
    if ( mpViewShell )
129
0
    {
130
0
        StartListening( *mpViewShell );
131
0
        mpObjectShell = mpViewShell->GetObjectShell();
132
0
        StartListening( *mpObjectShell );
133
0
    }
134
135
    // initialize extra ui options
136
0
    if( mxRenderable.is() )
137
0
    {
138
0
        for (const auto& rProp : rProps)
139
0
            setValue( rProp.Name, rProp.Value );
140
141
0
        Sequence< beans::PropertyValue > aRenderOptions{
142
0
            comphelper::makePropertyValue(u"ExtraPrintUIOptions"_ustr, Any{}),
143
0
            comphelper::makePropertyValue(u"View"_ustr, i_rViewProp),
144
0
            comphelper::makePropertyValue(u"IsPrinter"_ustr, true)
145
0
        };
146
0
        try
147
0
        {
148
0
            const Sequence< beans::PropertyValue > aRenderParms( mxRenderable->getRenderer( 0 , getSelectionObject(), aRenderOptions ) );
149
0
            for( const auto& rRenderParm : aRenderParms )
150
0
            {
151
0
                if ( rRenderParm.Name == "ExtraPrintUIOptions" )
152
0
                {
153
0
                    Sequence< beans::PropertyValue > aUIProps;
154
0
                    rRenderParm.Value >>= aUIProps;
155
0
                    setUIOptions( aUIProps );
156
0
                }
157
0
                else if( rRenderParm.Name == "NUp" )
158
0
                {
159
0
                    setValue( rRenderParm.Name, rRenderParm.Value );
160
0
                }
161
0
            }
162
0
        }
163
0
        catch( lang::IllegalArgumentException& )
164
0
        {
165
            // the first renderer should always be available for the UI options,
166
            // but catch the exception to be safe
167
0
        }
168
0
    }
169
170
    // set some job parameters
171
0
    setValue( u"IsApi"_ustr, Any( i_bApi ) );
172
0
    setValue( u"IsDirect"_ustr, Any( i_bDirect ) );
173
0
    setValue( u"IsPrinter"_ustr, Any( true ) );
174
0
    setValue( u"View"_ustr, i_rViewProp );
175
0
}
176
177
void SfxPrinterController::Notify( SfxBroadcaster& , const SfxHint& rHint )
178
0
{
179
0
    if ( rHint.GetId() == SfxHintId::Dying )
180
0
    {
181
0
        EndListening(*mpViewShell);
182
0
        EndListening(*mpObjectShell);
183
0
        dialogsParentClosing();
184
0
        mpViewShell = nullptr;
185
0
        mpObjectShell = nullptr;
186
0
    }
187
0
}
188
189
const Any& SfxPrinterController::getSelectionObject() const
190
0
{
191
0
    const beans::PropertyValue* pVal = getValue( u"PrintSelectionOnly"_ustr );
192
0
    if( pVal )
193
0
    {
194
0
        bool bSel = false;
195
0
        pVal->Value >>= bSel;
196
0
        return bSel ? maSelection : maCompleteSelection;
197
0
    }
198
199
0
    sal_Int32 nChoice = 0;
200
0
    pVal = getValue( u"PrintContent"_ustr );
201
0
    if( pVal )
202
0
        pVal->Value >>= nChoice;
203
204
0
    return (nChoice > 1) ? maSelection : maCompleteSelection;
205
0
}
206
207
Sequence< beans::PropertyValue > SfxPrinterController::getMergedOptions() const
208
0
{
209
0
    VclPtr<Printer> xPrinter( getPrinter() );
210
0
    if( xPrinter.get() != mpLastPrinter )
211
0
    {
212
0
        mpLastPrinter = xPrinter.get();
213
0
        rtl::Reference<VCLXDevice> pXDevice = new VCLXDevice();
214
0
        pXDevice->SetOutputDevice( mpLastPrinter );
215
0
        mxDevice.set( pXDevice );
216
0
    }
217
218
0
    Sequence< beans::PropertyValue > aRenderOptions{ comphelper::makePropertyValue(
219
0
        u"RenderDevice"_ustr, mxDevice) };
220
221
0
    aRenderOptions = getJobProperties( aRenderOptions );
222
0
    return aRenderOptions;
223
0
}
224
225
int SfxPrinterController::getPageCount() const
226
0
{
227
0
    int nPages = 0;
228
0
    VclPtr<Printer> xPrinter( getPrinter() );
229
0
    if( mxRenderable.is() && xPrinter )
230
0
    {
231
0
        Sequence< beans::PropertyValue > aJobOptions( getMergedOptions() );
232
0
        try
233
0
        {
234
0
            nPages = mxRenderable->getRendererCount( getSelectionObject(), aJobOptions );
235
0
        }
236
0
        catch (lang::DisposedException &)
237
0
        {
238
0
            SAL_WARN("sfx", "SfxPrinterController: document disposed while printing");
239
0
            const_cast<SfxPrinterController*>(this)->setJobState(
240
0
                    view::PrintableState_JOB_ABORTED);
241
0
        }
242
0
    }
243
0
    return nPages;
244
0
}
245
246
Sequence< beans::PropertyValue > SfxPrinterController::getPageParameters( int i_nPage ) const
247
0
{
248
0
    VclPtr<Printer> xPrinter( getPrinter() );
249
0
    Sequence< beans::PropertyValue > aResult;
250
251
0
    if (mxRenderable.is() && xPrinter)
252
0
    {
253
0
        Sequence< beans::PropertyValue > aJobOptions( getMergedOptions() );
254
0
        try
255
0
        {
256
0
            aResult = mxRenderable->getRenderer( i_nPage, getSelectionObject(), aJobOptions );
257
0
        }
258
0
        catch( lang::IllegalArgumentException& )
259
0
        {
260
0
        }
261
0
        catch (lang::DisposedException &)
262
0
        {
263
0
            SAL_WARN("sfx", "SfxPrinterController: document disposed while printing");
264
0
            const_cast<SfxPrinterController*>(this)->setJobState(
265
0
                    view::PrintableState_JOB_ABORTED);
266
0
        }
267
0
    }
268
0
    return aResult;
269
0
}
270
271
void SfxPrinterController::printPage( int i_nPage ) const
272
0
{
273
0
    VclPtr<Printer> xPrinter( getPrinter() );
274
0
    if( !mxRenderable.is() || !xPrinter )
275
0
        return;
276
277
0
    Sequence< beans::PropertyValue > aJobOptions( getMergedOptions() );
278
0
    try
279
0
    {
280
0
        mxRenderable->render( i_nPage, getSelectionObject(), aJobOptions );
281
0
    }
282
0
    catch( lang::IllegalArgumentException& )
283
0
    {
284
        // don't care enough about nonexistent page here
285
        // to provoke a crash
286
0
    }
287
0
    catch (lang::DisposedException &)
288
0
    {
289
0
        SAL_WARN("sfx", "SfxPrinterController: document disposed while printing");
290
0
        const_cast<SfxPrinterController*>(this)->setJobState(
291
0
                view::PrintableState_JOB_ABORTED);
292
0
    }
293
0
}
294
295
void SfxPrinterController::jobStarted()
296
0
{
297
0
    if ( !mpObjectShell )
298
0
        return;
299
300
0
    m_bJobStarted = true;
301
302
0
    m_bOrigStatus = mpObjectShell->IsEnableSetModified();
303
304
    // check configuration: shall update of printing information in DocInfo set the document to "modified"?
305
0
    if (m_bOrigStatus && !officecfg::Office::Common::Print::PrintingModifiesDocument::get())
306
0
    {
307
0
        mpObjectShell->EnableSetModified( false );
308
0
        m_bNeedsChange = true;
309
0
    }
310
311
    // refresh document info
312
0
    uno::Reference<document::XDocumentProperties> xDocProps(mpObjectShell->getDocProperties());
313
0
    m_aLastPrintedBy = xDocProps->getPrintedBy();
314
0
    m_aLastPrinted = xDocProps->getPrintDate();
315
316
0
    xDocProps->setPrintedBy( mpObjectShell->IsUseUserData()
317
0
        ? SvtUserOptions().GetFullName()
318
0
        : OUString() );
319
0
    ::DateTime now( ::DateTime::SYSTEM );
320
321
0
    xDocProps->setPrintDate( now.GetUNODateTime() );
322
323
0
    uno::Sequence < beans::PropertyValue > aOpts;
324
0
    aOpts = getJobProperties( aOpts );
325
326
0
    uno::Reference< frame::XController2 > xController;
327
0
    if ( mpViewShell )
328
0
        xController.set( mpViewShell->GetController(), uno::UNO_QUERY );
329
330
0
    mpObjectShell->Broadcast( SfxPrintingHint(
331
0
        view::PrintableState_JOB_STARTED, aOpts, mpObjectShell, xController ) );
332
0
}
333
334
void SfxPrinterController::jobFinished( css::view::PrintableState nState )
335
0
{
336
0
    if ( !mpObjectShell )
337
0
        return;
338
339
0
    bool bCopyJobSetup = false;
340
0
    mpObjectShell->Broadcast( SfxPrintingHint( nState ) );
341
0
    switch ( nState )
342
0
    {
343
0
        case view::PrintableState_JOB_SPOOLING_FAILED :
344
0
        case view::PrintableState_JOB_FAILED :
345
0
        {
346
            // "real" problem (not simply printing cancelled by user)
347
0
            OUString aMsg( SfxResId(STR_NOSTARTPRINTER) );
348
0
            if ( !m_bApi && mpViewShell )
349
0
            {
350
0
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(mpViewShell->GetFrameWeld(),
351
0
                                                                         VclMessageType::Warning, VclButtonsType::Ok,
352
0
                                                                         aMsg));
353
0
                xBox->run();
354
0
            }
355
0
            [[fallthrough]];
356
0
        }
357
0
        case view::PrintableState_JOB_ABORTED :
358
0
        {
359
            // printing not successful, reset DocInfo if the job started and so DocInfo was modified
360
0
            if (m_bJobStarted)
361
0
            {
362
0
                uno::Reference<document::XDocumentProperties> xDocProps(mpObjectShell->getDocProperties());
363
0
                xDocProps->setPrintedBy(m_aLastPrintedBy);
364
0
                xDocProps->setPrintDate(m_aLastPrinted);
365
0
            }
366
0
            break;
367
0
        }
368
369
0
        case view::PrintableState_JOB_SPOOLED :
370
0
        case view::PrintableState_JOB_COMPLETED :
371
0
        {
372
0
            if (mpViewShell)
373
0
            {
374
0
                SfxBindings& rBind = mpViewShell->GetViewFrame().GetBindings();
375
0
                rBind.Invalidate( SID_PRINTDOC );
376
0
                rBind.Invalidate( SID_PRINTDOCDIRECT );
377
0
                rBind.Invalidate( SID_SETUPPRINTER );
378
0
                bCopyJobSetup = ! m_bTempPrinter;
379
0
            }
380
0
            break;
381
0
        }
382
383
0
        default:
384
0
            break;
385
0
    }
386
387
0
    if( bCopyJobSetup && mpViewShell )
388
0
    {
389
        // #i114306#
390
        // Note: this possibly creates a printer that gets immediately replaced
391
        // by a new one. The reason for this is that otherwise we would not get
392
        // the printer's SfxItemSet here to copy. Awkward, but at the moment there is no
393
        // other way here to get the item set.
394
0
        SfxPrinter* pDocPrt = mpViewShell->GetPrinter(true);
395
0
        if( pDocPrt )
396
0
        {
397
0
            if( pDocPrt->GetName() == getPrinter()->GetName() )
398
0
                pDocPrt->SetJobSetup( getPrinter()->GetJobSetup() );
399
0
            else
400
0
            {
401
0
                VclPtr<SfxPrinter> pNewPrt = VclPtr<SfxPrinter>::Create( pDocPrt->GetOptions().Clone(), getPrinter()->GetName() );
402
0
                pNewPrt->SetJobSetup( getPrinter()->GetJobSetup() );
403
0
                mpViewShell->SetPrinter( pNewPrt, SfxPrinterChangeFlags::PRINTER | SfxPrinterChangeFlags::JOBSETUP );
404
0
            }
405
0
        }
406
0
    }
407
408
0
    if ( m_bNeedsChange )
409
0
        mpObjectShell->EnableSetModified( m_bOrigStatus );
410
411
0
    if ( mpViewShell )
412
0
    {
413
0
        mpViewShell->pImpl->m_xPrinterController.reset();
414
0
    }
415
0
}
416
417
namespace {
418
419
/**
420
    An instance of this class is created for the life span of the
421
    printer dialogue, to create in its click handler for the additions by the
422
    virtual method of the derived SfxViewShell generated print options dialogue
423
    and to cache the options set there as SfxItemSet.
424
*/
425
class SfxDialogExecutor_Impl
426
{
427
private:
428
    SfxViewShell*           _pViewSh;
429
    PrinterSetupDialog&  _rSetupParent;
430
    std::unique_ptr<SfxItemSet> _pOptions;
431
    bool                    _bHelpDisabled;
432
433
    DECL_LINK( Execute, weld::Button&, void );
434
435
public:
436
    SfxDialogExecutor_Impl( SfxViewShell* pViewSh, PrinterSetupDialog& rParent );
437
438
0
    Link<weld::Button&, void> GetLink() const { return LINK(const_cast<SfxDialogExecutor_Impl*>(this), SfxDialogExecutor_Impl, Execute); }
439
0
    const SfxItemSet*   GetOptions() const { return _pOptions.get(); }
440
0
    void                DisableHelp() { _bHelpDisabled = true; }
441
};
442
443
}
444
445
SfxDialogExecutor_Impl::SfxDialogExecutor_Impl( SfxViewShell* pViewSh, PrinterSetupDialog& rParent ) :
446
447
0
    _pViewSh        ( pViewSh ),
448
0
    _rSetupParent   ( rParent ),
449
0
    _bHelpDisabled  ( false )
450
451
0
{
452
0
}
453
454
IMPL_LINK_NOARG(SfxDialogExecutor_Impl, Execute, weld::Button&, void)
455
0
{
456
    // Options noted locally
457
0
    if ( !_pOptions )
458
0
    {
459
0
        _pOptions = static_cast<SfxPrinter*>( _rSetupParent.GetPrinter() )->GetOptions().Clone();
460
0
    }
461
462
0
    assert(_pOptions);
463
0
    if (!_pOptions)
464
0
        return;
465
466
    // Create Dialog
467
0
    SfxPrintOptionsDialog aDlg(_rSetupParent.GetFrameWeld(), _pViewSh, _pOptions.get() );
468
0
    if (_bHelpDisabled)
469
0
        aDlg.DisableHelp();
470
0
    if (aDlg.run() == RET_OK)
471
0
    {
472
0
        _pOptions = aDlg.GetOptions().Clone();
473
0
    }
474
0
}
475
476
/**
477
   Internal method for setting the differences between 'pNewPrinter' to the
478
   current printer. pNewPrinter is either taken over or deleted.
479
*/
480
void SfxViewShell::SetPrinter_Impl( VclPtr<SfxPrinter>& pNewPrinter )
481
0
{
482
    // get current Printer
483
0
    SfxPrinter *pDocPrinter = GetPrinter();
484
485
    // Evaluate Printer Options
486
0
    const SfxFlagItem *pFlagItem = pDocPrinter->GetOptions().GetItemIfSet( SID_PRINTER_CHANGESTODOC, false );
487
0
    bool bOriToDoc = pFlagItem && (static_cast<SfxPrinterChangeFlags>(pFlagItem->GetValue()) & SfxPrinterChangeFlags::CHG_ORIENTATION);
488
0
    bool bSizeToDoc = pFlagItem && (static_cast<SfxPrinterChangeFlags>(pFlagItem->GetValue()) & SfxPrinterChangeFlags::CHG_SIZE);
489
490
    // Determine the previous format and size
491
0
    Orientation eOldOri = pDocPrinter->GetOrientation();
492
0
    Size aOldPgSz = pDocPrinter->GetPaperSizePixel();
493
494
    // Determine the new format and size
495
0
    Orientation eNewOri = pNewPrinter->GetOrientation();
496
0
    Size aNewPgSz = pNewPrinter->GetPaperSizePixel();
497
498
    // Determine the changes in page format
499
0
    bool bOriChg = (eOldOri != eNewOri) && bOriToDoc;
500
0
    bool bPgSzChg = ( aOldPgSz.Height() !=
501
0
            ( bOriChg ? aNewPgSz.Width() : aNewPgSz.Height() ) ||
502
0
            aOldPgSz.Width() !=
503
0
            ( bOriChg ? aNewPgSz.Height() : aNewPgSz.Width() ) ) &&
504
0
            bSizeToDoc;
505
506
    // Message and Flags for page format changes
507
0
    OUString aMsg;
508
0
    SfxPrinterChangeFlags nNewOpt = SfxPrinterChangeFlags::NONE;
509
0
    if( bOriChg && bPgSzChg )
510
0
    {
511
0
        aMsg = SfxResId(STR_PRINT_NEWORISIZE);
512
0
        nNewOpt = SfxPrinterChangeFlags::CHG_ORIENTATION | SfxPrinterChangeFlags::CHG_SIZE;
513
0
    }
514
0
    else if (bOriChg )
515
0
    {
516
0
        aMsg = SfxResId(STR_PRINT_NEWORI);
517
0
        nNewOpt = SfxPrinterChangeFlags::CHG_ORIENTATION;
518
0
    }
519
0
    else if (bPgSzChg)
520
0
    {
521
0
        aMsg = SfxResId(STR_PRINT_NEWSIZE);
522
0
        nNewOpt = SfxPrinterChangeFlags::CHG_SIZE;
523
0
    }
524
525
    // Summarize in this variable what has been changed.
526
0
    SfxPrinterChangeFlags nChangedFlags = SfxPrinterChangeFlags::NONE;
527
528
    // Ask if possible, if page format should be taken over from printer.
529
0
    if (bOriChg || bPgSzChg)
530
0
    {
531
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
532
0
                                                                 VclMessageType::Question, VclButtonsType::YesNo,
533
0
                                                                 aMsg));
534
0
        if (RET_YES == xBox->run())
535
0
        {
536
            // Flags with changes for  <SetPrinter(SfxPrinter*)> are maintained
537
0
            nChangedFlags |= nNewOpt;
538
0
        }
539
0
    }
540
541
    // Was the printer selection changed from Default to Specific
542
    // or the other way around?
543
0
    if ( (pNewPrinter->GetName() != pDocPrinter->GetName())
544
0
         || (pDocPrinter->IsDefPrinter() != pNewPrinter->IsDefPrinter()) )
545
0
    {
546
0
        nChangedFlags |= SfxPrinterChangeFlags::PRINTER|SfxPrinterChangeFlags::JOBSETUP;
547
0
        if ( ! (pNewPrinter->GetOptions() == pDocPrinter->GetOptions()) )
548
0
        {
549
0
            nChangedFlags |= SfxPrinterChangeFlags::OPTIONS;
550
0
        }
551
552
0
        pDocPrinter = pNewPrinter;
553
0
    }
554
0
    else
555
0
    {
556
        // Compare extra options
557
0
        if ( ! (pNewPrinter->GetOptions() == pDocPrinter->GetOptions()) )
558
0
        {
559
            // Option have changed
560
0
            pDocPrinter->SetOptions( pNewPrinter->GetOptions() );
561
0
            nChangedFlags |= SfxPrinterChangeFlags::OPTIONS;
562
0
        }
563
564
        // Compare JobSetups
565
0
        JobSetup aNewJobSetup = pNewPrinter->GetJobSetup();
566
0
        JobSetup aOldJobSetup = pDocPrinter->GetJobSetup();
567
0
        if ( aNewJobSetup != aOldJobSetup )
568
0
        {
569
0
            nChangedFlags |= SfxPrinterChangeFlags::JOBSETUP;
570
0
        }
571
572
        // Keep old changed Printer.
573
0
        pDocPrinter->SetPrinterProps( pNewPrinter );
574
0
        pNewPrinter.disposeAndClear();
575
0
    }
576
577
0
    if ( SfxPrinterChangeFlags::NONE != nChangedFlags )
578
        // SetPrinter will delete the old printer if it changes
579
0
        SetPrinter( pDocPrinter, nChangedFlags );
580
0
}
581
582
void SfxViewShell::StartPrint( const uno::Sequence < beans::PropertyValue >& rProps, bool bIsAPI, bool bIsDirect )
583
0
{
584
0
    assert( !pImpl->m_xPrinterController );
585
586
    // get the current selection; our controller should know it
587
0
    Reference< frame::XController > xController( GetController() );
588
0
    Reference< view::XSelectionSupplier > xSupplier( xController, UNO_QUERY );
589
590
0
    Any aSelection;
591
0
    if( xSupplier.is() )
592
0
        aSelection = xSupplier->getSelection();
593
0
    else
594
0
        aSelection <<= GetObjectShell()->GetModel();
595
0
    Any aComplete( Any( GetObjectShell()->GetModel() ) );
596
0
    Any aViewProp( xController );
597
0
    VclPtr<Printer> aPrt;
598
599
0
    const beans::PropertyValue* pVal = std::find_if(rProps.begin(), rProps.end(),
600
0
        [](const beans::PropertyValue& rVal) { return rVal.Name == "PrinterName"; });
601
0
    if (pVal != rProps.end())
602
0
    {
603
0
        OUString aPrinterName;
604
0
        pVal->Value >>= aPrinterName;
605
0
        aPrt.reset( VclPtr<Printer>::Create( aPrinterName ) );
606
0
    }
607
608
0
    std::shared_ptr<vcl::PrinterController> xNewController(std::make_shared<SfxPrinterController>(
609
0
                                                                               aPrt,
610
0
                                                                               aComplete,
611
0
                                                                               aSelection,
612
0
                                                                               aViewProp,
613
0
                                                                               GetRenderable(),
614
0
                                                                               bIsAPI,
615
0
                                                                               bIsDirect,
616
0
                                                                               this,
617
0
                                                                               rProps
618
0
                                                                               ));
619
0
    pImpl->m_xPrinterController = xNewController;
620
621
    // When no JobName was specified via com::sun::star::view::PrintOptions::JobName ,
622
    // use the document title as default job name
623
0
    css::beans::PropertyValue* pJobNameVal = xNewController->getValue(u"JobName"_ustr);
624
0
    if (!pJobNameVal)
625
0
    {
626
0
        if (SfxObjectShell* pDoc = GetObjectShell())
627
0
        {
628
0
            xNewController->setValue(u"JobName"_ustr, Any(pDoc->GetTitle(1)));
629
0
            xNewController->setPrinterModified(mbPrinterSettingsModified);
630
0
        }
631
0
    }
632
0
}
633
634
void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rProps, bool bIsAPI, bool bIsDirect )
635
0
{
636
0
    StartPrint( rProps, bIsAPI, bIsDirect );
637
    // FIXME: job setup
638
0
    SfxPrinter* pDocPrt = GetPrinter();
639
0
    JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : JobSetup();
640
0
    Printer::PrintJob( GetPrinterController(), aJobSetup );
641
0
}
642
643
const std::shared_ptr< vcl::PrinterController >& SfxViewShell::GetPrinterController() const
644
0
{
645
0
    return pImpl->m_xPrinterController;
646
0
}
647
648
Printer* SfxViewShell::GetActivePrinter() const
649
0
{
650
0
    return pImpl->m_xPrinterController
651
0
        ?  pImpl->m_xPrinterController->getPrinter().get() : nullptr;
652
0
}
653
654
void SfxViewShell::ExecPrint_Impl( SfxRequest &rReq )
655
0
{
656
0
    sal_uInt16              nDialogRet = RET_CANCEL;
657
0
    VclPtr<SfxPrinter>      pPrinter;
658
0
    bool                    bSilent = false;
659
660
    // does the function have been called by the user interface or by an API call
661
0
    bool bIsAPI = rReq.GetArgs() && rReq.GetArgs()->Count();
662
0
    if ( bIsAPI )
663
0
    {
664
        // the function have been called by the API
665
666
        // Should it be visible on the user interface,
667
        // should it launch popup dialogue ?
668
0
        const SfxBoolItem* pSilentItem = rReq.GetArg(SID_SILENT);
669
0
        bSilent = pSilentItem && pSilentItem->GetValue();
670
0
    }
671
672
    // no help button in dialogs if called from the help window
673
    // (pressing help button would exchange the current page inside the help
674
    // document that is going to be printed!)
675
0
    SfxMedium* pMedium = GetViewFrame().GetObjectShell()->GetMedium();
676
0
    std::shared_ptr<const SfxFilter> pFilter = pMedium ? pMedium->GetFilter() : nullptr;
677
0
    bool bPrintOnHelp = ( pFilter && pFilter->GetFilterName() == "writer_web_HTML_help" );
678
679
0
    const sal_uInt16 nId = rReq.GetSlot();
680
0
    switch( nId )
681
0
    {
682
0
        case SID_PRINTDOC: // display the printer selection and properties dialogue : File > Print...
683
0
        case SID_PRINTDOCDIRECT: // Print the document directly, without displaying the dialogue
684
0
        {
685
0
            SfxObjectShell* pDoc = GetObjectShell();
686
687
            // derived class may decide to abort this
688
0
            if( pDoc == nullptr || !pDoc->QuerySlotExecutable( nId ) )
689
0
            {
690
0
                rReq.SetReturnValue( SfxBoolItem( 0, false ) );
691
0
                return;
692
0
            }
693
694
0
            pDoc->QueryHiddenInformation(HiddenWarningFact::WhenPrinting);
695
696
            // should we print only the selection or the whole document
697
0
            const SfxBoolItem* pSelectItem = rReq.GetArg(SID_SELECTION);
698
0
            bool bSelection = ( pSelectItem != nullptr && pSelectItem->GetValue() );
699
            // detect non api call from writer ( that adds SID_SELECTION ) and reset bIsAPI
700
0
            if ( pSelectItem && rReq.GetArgs()->Count() == 1 )
701
0
                bIsAPI = false;
702
703
0
            comphelper::SequenceAsHashMap aProps;
704
0
            if ( bIsAPI )
705
0
            {
706
                // supported properties:
707
                // String PrinterName
708
                // String FileName
709
                // Int16 From
710
                // Int16 To
711
                // In16 Copies
712
                // String RangeText
713
                // bool Selection
714
                // bool Asynchron
715
                // bool Collate
716
                // bool Silent
717
718
0
                aProps = TransformItems(nId, *rReq.GetArgs(), GetInterface()->GetSlot(nId));
719
720
0
                if (aProps.contains(u"Copies"_ustr))
721
0
                {
722
0
                    aProps[u"CopyCount"_ustr] = aProps[u"Copies"_ustr];
723
0
                }
724
725
0
                if (aProps.contains(u"RangeText"_ustr))
726
0
                {
727
0
                    aProps[u"Pages"_ustr] = aProps[u"RangeText"_ustr];
728
0
                }
729
730
0
                if (aProps.contains(u"Asynchron"_ustr))
731
0
                {
732
0
                    aProps[u"Wait"_ustr] <<= !aProps.getUnpackedValueOrDefault(u"Asynchron"_ustr, false);
733
0
                }
734
735
0
                if (aProps.contains(u"Silent"_ustr))
736
0
                {
737
0
                    aProps[u"MonitorVisible"_ustr] <<= !aProps.getUnpackedValueOrDefault(u"Silent"_ustr, false);
738
0
                }
739
0
            }
740
741
            // HACK: writer sets the SID_SELECTION item when printing directly and expects
742
            // to get only the selection document in that case (see getSelectionObject)
743
            // however it also reacts to the PrintContent property. We need this distinction here, too,
744
            // else one of the combinations print / print direct and selection / all will not work.
745
            // it would be better if writer handled this internally
746
0
            if( nId == SID_PRINTDOCDIRECT )
747
0
            {
748
0
                aProps[u"PrintSelectionOnly"_ustr] <<= bSelection;
749
0
            }
750
0
            else // if nId == SID_PRINTDOC ; nothing to do with the previous HACK
751
0
            {
752
                // should the printer selection and properties dialogue display an help button
753
0
                aProps[u"HideHelpButton"_ustr] <<= bPrintOnHelp;
754
0
            }
755
756
0
            ExecPrint(aProps.getAsConstPropertyValueList(), bIsAPI, (nId == SID_PRINTDOCDIRECT));
757
758
            // FIXME: Recording
759
0
            rReq.Done();
760
0
            break;
761
0
        }
762
763
0
        case SID_PRINTER_NAME: // for recorded macros
764
0
        {
765
            // get printer and printer settings from the document
766
0
            SfxPrinter* pDocPrinter = GetPrinter(true);
767
0
            const SfxStringItem* pPrinterItem = rReq.GetArg(SID_PRINTER_NAME);
768
0
            if (!pPrinterItem)
769
0
            {
770
0
                rReq.Ignore();
771
0
                break;
772
0
            }
773
            // use PrinterName parameter to create a printer
774
0
            pPrinter = VclPtr<SfxPrinter>::Create(pDocPrinter->GetOptions().Clone(),
775
0
                                                  pPrinterItem->GetValue());
776
777
0
            if (!pPrinter->IsKnown())
778
0
            {
779
0
                pPrinter.disposeAndClear();
780
0
                rReq.Ignore();
781
0
                break;
782
0
            }
783
0
            SetPrinter(pPrinter, SfxPrinterChangeFlags::PRINTER);
784
0
            rReq.Done();
785
0
            break;
786
0
        }
787
0
        case SID_SETUPPRINTER : // display the printer settings dialog : File > Printer Settings...
788
0
        {
789
            // get printer and printer settings from the document
790
0
            SfxPrinter *pDocPrinter = GetPrinter(true);
791
792
            // look for printer in parameters
793
0
            const SfxStringItem* pPrinterItem = rReq.GetArg(SID_PRINTER_NAME);
794
0
            if ( pPrinterItem )
795
0
            {
796
                // use PrinterName parameter to create a printer
797
0
                pPrinter = VclPtr<SfxPrinter>::Create( pDocPrinter->GetOptions().Clone(), pPrinterItem->GetValue() );
798
799
                // if printer is unknown, it can't be used - now printer from document will be used
800
0
                if ( !pPrinter->IsKnown() )
801
0
                    pPrinter.disposeAndClear();
802
0
            }
803
804
            // no PrinterName parameter in ItemSet or the PrinterName points to an unknown printer
805
0
            if ( !pPrinter )
806
                // use default printer from document
807
0
                pPrinter = pDocPrinter;
808
809
0
            if( !pPrinter || !pPrinter->IsValid() )
810
0
            {
811
                // no valid printer either in ItemSet or at the document
812
0
                if ( !bSilent )
813
0
                {
814
0
                    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
815
0
                                                                             VclMessageType::Warning, VclButtonsType::Ok,
816
0
                                                                             SfxResId(STR_NODEFPRINTER)));
817
0
                    xBox->run();
818
0
                }
819
820
0
                rReq.SetReturnValue(SfxBoolItem(0,false));
821
822
0
                break;
823
0
            }
824
825
            // FIXME: printer isn't used for printing anymore!
826
0
            if( pPrinter->IsPrinting() )
827
0
            {
828
                // if printer is busy, abort configuration
829
0
                if ( !bSilent )
830
0
                {
831
0
                    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
832
0
                                                                             VclMessageType::Info, VclButtonsType::Ok,
833
0
                                                                             SfxResId(STR_ERROR_PRINTER_BUSY)));
834
0
                    xBox->run();
835
0
                }
836
0
                rReq.SetReturnValue(SfxBoolItem(0,false));
837
838
0
                return;
839
0
            }
840
841
            // Open Printer Setup dialog (needs a temporary printer)
842
0
            VclPtr<SfxPrinter> pDlgPrinter = pPrinter->Clone();
843
0
            PrinterSetupDialog aPrintSetupDlg(GetFrameWeld());
844
0
            std::unique_ptr<SfxDialogExecutor_Impl> pExecutor;
845
846
0
            if (pImpl->m_bHasPrintOptions && HasPrintOptionsPage())
847
0
            {
848
                // additional controls for dialog
849
0
                pExecutor.reset(new SfxDialogExecutor_Impl(this, aPrintSetupDlg));
850
0
                if (bPrintOnHelp)
851
0
                    pExecutor->DisableHelp();
852
0
                aPrintSetupDlg.SetOptionsHdl(pExecutor->GetLink());
853
0
            }
854
855
0
            aPrintSetupDlg.SetPrinter(pDlgPrinter);
856
0
            nDialogRet = aPrintSetupDlg.run();
857
858
0
            if (pExecutor && pExecutor->GetOptions())
859
0
            {
860
0
                if (nDialogRet == RET_OK)
861
                    // remark: have to be recorded if possible!
862
0
                    pDlgPrinter->SetOptions(*pExecutor->GetOptions());
863
0
                else
864
0
                {
865
0
                    pPrinter->SetOptions(*pExecutor->GetOptions());
866
0
                    SetPrinter(pPrinter, SfxPrinterChangeFlags::OPTIONS);
867
0
                }
868
0
            }
869
870
            // no recording of PrinterSetup except printer name (is printer dependent)
871
0
            rReq.Ignore();
872
873
0
            if (nDialogRet == RET_OK)
874
0
            {
875
0
                if (pPrinter->GetName() != pDlgPrinter->GetName())
876
0
                {
877
                    // user has changed the printer -> macro recording
878
0
                    SfxRequest aReq(GetViewFrame(), SID_PRINTER_NAME);
879
0
                    aReq.AppendItem(SfxStringItem(SID_PRINTER_NAME, pDlgPrinter->GetName()));
880
0
                    aReq.Done();
881
0
                }
882
883
                // take the changes made in the dialog
884
0
                SetPrinter_Impl(pDlgPrinter);
885
886
                // forget new printer, it was taken over (as pPrinter) or deleted
887
0
                pDlgPrinter = nullptr;
888
0
                mbPrinterSettingsModified = true;
889
0
            }
890
0
            else
891
0
            {
892
                // PrinterDialog is used to transfer information on printing,
893
                // so it will only be deleted here if dialog was cancelled
894
0
                pDlgPrinter.disposeAndClear();
895
0
                rReq.Ignore();
896
0
            }
897
0
            break;
898
0
        }
899
0
    }
900
0
}
901
902
SfxPrinter* SfxViewShell::GetPrinter( bool /*bCreate*/ )
903
0
{
904
0
    return nullptr;
905
0
}
906
907
sal_uInt16 SfxViewShell::SetPrinter( SfxPrinter* /*pNewPrinter*/, SfxPrinterChangeFlags /*nDiffFlags*/ )
908
0
{
909
0
    return 0;
910
0
}
911
912
std::unique_ptr<SfxTabPage> SfxViewShell::CreatePrintOptionsPage(weld::Container*, weld::DialogController*, const SfxItemSet&)
913
0
{
914
0
    return nullptr;
915
0
}
916
917
bool SfxViewShell::HasPrintOptionsPage() const
918
0
{
919
0
    return false;
920
0
}
921
922
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */