Coverage Report

Created: 2025-12-08 09:28

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