Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/app/appenv.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 <hintids.hxx>
21
22
#include <comphelper/string.hxx>
23
#include <sfx2/request.hxx>
24
25
#include <sfx2/bindings.hxx>
26
#include <sfx2/printer.hxx>
27
#include <sfx2/viewfrm.hxx>
28
#include <editeng/boxitem.hxx>
29
#include <editeng/lrspitem.hxx>
30
#include <editeng/ulspitem.hxx>
31
#include <editeng/pbinitem.hxx>
32
#include <editeng/paperinf.hxx>
33
#include <osl/diagnose.h>
34
#include <fmthdft.hxx>
35
#include <swwait.hxx>
36
#include <swmodule.hxx>
37
#include <wrtsh.hxx>
38
#include <view.hxx>
39
#include <docsh.hxx>
40
#include <frmatr.hxx>
41
#include <fldbas.hxx>
42
#include <swundo.hxx>
43
#include <IDocumentDeviceAccess.hxx>
44
#include <dialoghelp.hxx>
45
#include <fmtcol.hxx>
46
#include <frmmgr.hxx>
47
#include <fldmgr.hxx>
48
#include <pagedesc.hxx>
49
#include <poolfmt.hxx>
50
#include <expfld.hxx>
51
#include <SwStyleNameMapper.hxx>
52
#include <fmtpdsc.hxx>
53
54
#include <cmdid.h>
55
#include <strings.hrc>
56
#include <swabstdlg.hxx>
57
#include <envimg.hxx>
58
#include "appenv.hxx"
59
60
0
#define ENV_NEWDOC      RET_OK
61
0
#define ENV_INSERT      RET_USER
62
63
// Function used for labels and envelopes in applab.cxx and appenv.cxx
64
OUString InsertLabEnvText( SwWrtShell& rSh, SwFieldMgr& rFieldMgr, const OUString& rText )
65
0
{
66
0
    OUString sRet;
67
0
    OUString aText = rText.replaceAll("\r", "");
68
69
0
    sal_Int32 nTokenPos = 0;
70
0
    while( -1 != nTokenPos )
71
0
    {
72
0
        OUString aLine = aText.getToken( 0, '\n', nTokenPos );
73
0
        while ( !aLine.isEmpty() )
74
0
        {
75
0
            OUString sTmpText;
76
0
            bool bField = false;
77
78
0
            sal_Int32 nPos = aLine.indexOf( '<' );
79
0
            if (0 != nPos)
80
0
            {
81
0
                sal_Int32 const nCopy((nPos != -1) ? nPos : aLine.getLength());
82
0
                sTmpText = aLine.copy(0, nCopy);
83
0
                aLine = aLine.copy(nCopy);
84
0
            }
85
0
            else
86
0
            {
87
0
                nPos = aLine.indexOf( '>' );
88
0
                if ( nPos == -1 )
89
0
                {
90
0
                    sTmpText = aLine;
91
0
                    aLine.clear();
92
0
                }
93
0
                else
94
0
                {
95
0
                    sTmpText = aLine.copy( 0, nPos + 1);
96
0
                    aLine = aLine.copy( nPos + 1);
97
98
                    // Database fields must contain at least 3 points!
99
0
                    OUString sDBName( sTmpText.copy( 1, sTmpText.getLength() - 2));
100
0
                    if (comphelper::string::getTokenCount(sDBName, '.') >= 3)
101
0
                    {
102
0
                        sDBName = ::ReplacePoint(sDBName, true);
103
0
                        SwInsertField_Data aData(SwFieldTypesEnum::Database, 0, sDBName, OUString(), 0, &rSh);
104
0
                        rFieldMgr.InsertField( aData );
105
0
                        sRet = sDBName;
106
0
                        bField = true;
107
0
                    }
108
0
                }
109
0
            }
110
0
            if ( !bField )
111
0
                rSh.Insert( sTmpText );
112
0
        }
113
0
        rSh.SplitNode();
114
0
    }
115
0
    rSh.DelLeft();  // Again remove last linebreak
116
117
0
    return sRet;
118
0
}
119
120
static void lcl_CopyCollAttr(SwWrtShell const * pOldSh, SwWrtShell* pNewSh, SwPoolFormatId nCollId)
121
0
{
122
0
    sal_uInt16 nCollCnt = pOldSh->GetTextFormatCollCount();
123
0
    for( sal_uInt16 nCnt = 0; nCnt < nCollCnt; ++nCnt )
124
0
    {
125
0
        SwTextFormatColl* pColl = &pOldSh->GetTextFormatColl(nCnt);
126
0
        if(nCollId == pColl->GetPoolFormatId())
127
0
            pNewSh->GetTextCollFromPool(nCollId)->SetFormatAttr(pColl->GetAttrSet());
128
0
    }
129
0
}
130
131
void SwModule::InsertEnv( SfxRequest& rReq )
132
0
{
133
0
    static sal_uInt16 nTitleNo = 0;
134
135
0
    SwDocShell      *pMyDocSh;
136
0
    SfxViewFrame    *pFrame;
137
0
    SwView          *pNewView;
138
0
    SwWrtShell      *pOldSh,
139
0
                    *pSh;
140
141
    // Get current shell
142
0
    pMyDocSh = static_cast<SwDocShell*>( SfxObjectShell::Current());
143
0
    pOldSh   = pMyDocSh ? pMyDocSh->GetWrtShell() : nullptr;
144
145
    // Create new document (don't show!)
146
0
    SfxObjectShellLock xDocSh( new SwDocShell( SfxObjectCreateMode::STANDARD ) );
147
0
    xDocSh->DoInitNew();
148
0
    pFrame = SfxViewFrame::LoadHiddenDocument( *xDocSh, SFX_INTERFACE_NONE );
149
0
    pNewView = static_cast<SwView*>( pFrame->GetViewShell());
150
0
    pNewView->AttrChangedNotify(nullptr); // so that SelectShell is being called
151
0
    pSh = pNewView->GetWrtShellPtr();
152
153
0
    if (!pSh)
154
0
        return;
155
156
0
    OUString aTmp = SwResId(STR_ENV_TITLE) + OUString::number( ++nTitleNo );
157
0
    xDocSh->SetTitle( aTmp );
158
159
    // if applicable, copy the old Collections "Sender" and "Receiver" to
160
    // a new document
161
0
    if ( pOldSh )
162
0
    {
163
0
        ::lcl_CopyCollAttr(pOldSh, pSh, SwPoolFormatId::COLL_ENVELOPE_ADDRESS);
164
0
        ::lcl_CopyCollAttr(pOldSh, pSh, SwPoolFormatId::COLL_SEND_ADDRESS);
165
0
    }
166
167
    // Read SwEnvItem from config
168
0
    SwEnvCfgItem aEnvCfg;
169
170
    // Check if there's already an envelope.
171
0
    bool bEnvChange = false;
172
173
0
    SfxItemSet aSet(SfxItemSet::makeFixedSfxItemSet<FN_ENVELOP, FN_ENVELOP>(GetPool()));
174
0
    aSet.Put(aEnvCfg.GetItem());
175
176
0
    SfxPrinter* pTempPrinter = pSh->getIDocumentDeviceAccess().getPrinter( true );
177
0
    if(pOldSh )
178
0
    {
179
0
        const SwPageDesc& rCurPageDesc = pOldSh->GetPageDesc(pOldSh->GetCurPageDesc());
180
0
        UIName sEnvelope;
181
0
        SwStyleNameMapper::FillUIName( SwPoolFormatId::PAGE_ENVELOPE, sEnvelope );
182
0
        bEnvChange = rCurPageDesc.GetName() == sEnvelope;
183
184
0
        IDocumentDeviceAccess& rIDDA_old = pOldSh->getIDocumentDeviceAccess();
185
0
        if( rIDDA_old.getPrinter( false ) )
186
0
        {
187
0
            IDocumentDeviceAccess& rIDDA = pSh->getIDocumentDeviceAccess();
188
0
            rIDDA.setJobsetup( *rIDDA_old.getJobsetup() );
189
            //#69563# if it isn't the same printer then the pointer has been invalidated!
190
0
            pTempPrinter = rIDDA.getPrinter( true );
191
0
        }
192
0
        pTempPrinter->SetPaperBin(rCurPageDesc.GetMaster().GetPaperBin().GetValue());
193
194
0
    }
195
196
0
    ScopedVclPtr<SfxAbstractTabDialog> pDlg;
197
0
    short nMode = ENV_INSERT;
198
199
0
    const SwEnvItem* pItem = rReq.GetArg<SwEnvItem>(FN_ENVELOP);
200
0
    if ( !pItem )
201
0
    {
202
0
        SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
203
0
        pDlg.disposeAndReset(pFact->CreateSwEnvDlg(GetFrameWeld(pMyDocSh), aSet, pOldSh, pTempPrinter, !bEnvChange));
204
0
        nMode = pDlg->Execute();
205
0
    }
206
0
    else
207
0
    {
208
0
        const SfxBoolItem* pBoolItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_1);
209
0
        if ( pBoolItem && pBoolItem->GetValue() )
210
0
            nMode = ENV_NEWDOC;
211
0
    }
212
213
0
    if (nMode == ENV_NEWDOC || nMode == ENV_INSERT)
214
0
    {
215
0
        SwWait aWait( static_cast<SwDocShell&>(*xDocSh), true );
216
217
        // Read dialog and save item to config
218
0
        const SwEnvItem& rItem = pItem ? *pItem : static_cast<const SwEnvItem&>( pDlg->GetOutputItemSet()->Get(FN_ENVELOP) );
219
0
        aEnvCfg.GetItem() = rItem;
220
0
        aEnvCfg.Commit();
221
222
        // When we print we take the Jobsetup that is set up in the dialog.
223
        // Information has to be set here, before a possible destruction of
224
        // the new shell because the shell's printer has been handed to the
225
        // dialog.
226
0
        if ( nMode != ENV_NEWDOC )
227
0
        {
228
0
            OSL_ENSURE(pOldSh, "No document - wasn't 'Insert' disabled???");
229
0
            SvxPaperBinItem aItem( RES_PAPER_BIN );
230
0
            aItem.SetValue(static_cast<sal_uInt8>(pSh->getIDocumentDeviceAccess().getPrinter(true)->GetPaperBin()));
231
0
            pOldSh->GetPageDescFromPool(SwPoolFormatId::PAGE_ENVELOPE)->GetMaster().SetFormatAttr(aItem);
232
0
        }
233
234
0
        SwWrtShell *pTmp = nMode == ENV_INSERT ? pOldSh : pSh;
235
0
        const SwPageDesc* pFollow = nullptr;
236
0
        SwTextFormatColl *pSend = pTmp->GetTextCollFromPool(SwPoolFormatId::COLL_SEND_ADDRESS),
237
0
                     *pAddr = pTmp->GetTextCollFromPool(SwPoolFormatId::COLL_ENVELOPE_ADDRESS);
238
0
        const UIName sSendMark = pSend->GetName();
239
0
        const UIName sAddrMark = pAddr->GetName();
240
241
0
        if (nMode == ENV_INSERT)
242
0
        {
243
244
0
            SetView(&pOldSh->GetView()); // Set pointer to top view
245
246
            // Delete new document
247
0
            xDocSh->DoClose();
248
0
            pSh = pOldSh;
249
            //#i4251# selected text or objects in the document should
250
            //not be deleted on inserting envelopes
251
0
            pSh->EnterStdMode();
252
            // Here it goes (insert)
253
0
            pSh->StartUndo(SwUndoId::UI_INSERT_ENVELOPE);
254
0
            pSh->StartAllAction();
255
0
            pSh->SttEndDoc(true);
256
257
0
            if (bEnvChange)
258
0
            {
259
                // followup template: page 2
260
0
                pFollow = pSh->GetPageDesc(pSh->GetCurPageDesc()).GetFollow();
261
262
                // Delete text from the first page
263
0
                if ( !pSh->SttNxtPg(true) )
264
0
                    pSh->EndPg(true);
265
0
                pSh->DelRight();
266
                // Delete frame of the first page
267
0
                if ( pSh->GotoFly(sSendMark) )
268
0
                {
269
0
                    pSh->EnterSelFrameMode();
270
0
                    pSh->DelRight();
271
0
                }
272
0
                if ( pSh->GotoFly(sAddrMark) )
273
0
                {
274
0
                    pSh->EnterSelFrameMode();
275
0
                    pSh->DelRight();
276
0
                }
277
0
                pSh->SttEndDoc(true);
278
0
            }
279
0
            else
280
                // Followup template: page 1
281
0
                pFollow = &pSh->GetPageDesc(pSh->GetCurPageDesc());
282
283
            // Insert page break
284
0
            if ( pSh->IsCursorInTable() )
285
0
            {
286
0
                pSh->SplitNode();
287
0
                pSh->Right( SwCursorSkipMode::Chars, false, 1, false );
288
0
                SfxItemSet aBreakSet(SfxItemSet::makeFixedSfxItemSet<RES_PAGEDESC, RES_PAGEDESC>( pSh->GetAttrPool() ));
289
0
                aBreakSet.Put( SwFormatPageDesc( pFollow ) );
290
0
                pSh->SetTableAttr( aBreakSet );
291
0
            }
292
0
            else
293
0
            {
294
0
                UIName sFollowName(pFollow->GetName());
295
0
                pSh->InsertPageBreak(&sFollowName, std::nullopt);
296
0
            }
297
0
            pSh->SttEndDoc(true);
298
0
        }
299
0
        else
300
0
        {
301
0
            pFollow = &pSh->GetPageDesc(pSh->GetCurPageDesc());
302
            // Let's go (print)
303
0
            pSh->StartAllAction();
304
0
            pSh->DoUndo(false);
305
306
            // Again, copy the new collections "Sender" and "Receiver" to
307
            // a new document
308
0
            if ( pOldSh )
309
0
            {
310
0
                ::lcl_CopyCollAttr(pOldSh, pSh, SwPoolFormatId::COLL_ENVELOPE_ADDRESS);
311
0
                ::lcl_CopyCollAttr(pOldSh, pSh, SwPoolFormatId::COLL_SEND_ADDRESS);
312
0
            }
313
0
        }
314
315
0
        CurrShell aCurr(pSh);
316
0
        pSh->SetNewDoc();   // Avoid performance problems
317
318
        // Remember Flys of this site
319
0
        std::vector<SwFrameFormat*> aFlyArr;
320
0
        if( ENV_NEWDOC != nMode && !bEnvChange )
321
0
            pSh->GetPageObjs( aFlyArr );
322
323
        // Get page description
324
0
        SwPageDesc* pDesc = pSh->GetPageDescFromPool(SwPoolFormatId::PAGE_ENVELOPE);
325
0
        SwFrameFormat&   rFormat  = pDesc->GetMaster();
326
327
0
        Printer *pPrt = pSh->getIDocumentDeviceAccess().getPrinter( true );
328
329
    // Borders (are put together by Shift-Offset and alignment)
330
0
        Size aPaperSize = pPrt->PixelToLogic( pPrt->GetPaperSizePixel(),
331
0
                                              MapMode(MapUnit::MapTwip));
332
0
        if ( !aPaperSize.Width() && !aPaperSize.Height() )
333
0
                    aPaperSize = SvxPaperInfo::GetPaperSize(PAPER_A4);
334
0
        if ( aPaperSize.Width() > aPaperSize.Height() )
335
0
            Swap( aPaperSize );
336
337
0
        tools::Long lLeft  = rItem.m_nShiftRight,
338
0
             lUpper = rItem.m_nShiftDown;
339
340
0
        sal_uInt16 nPageW = o3tl::narrowing<sal_uInt16>(std::max(rItem.m_nWidth, rItem.m_nHeight)),
341
0
               nPageH = o3tl::narrowing<sal_uInt16>(std::min(rItem.m_nWidth, rItem.m_nHeight));
342
343
0
        switch (rItem.m_eAlign)
344
0
        {
345
0
            case ENV_HOR_LEFT: break;
346
0
            case ENV_HOR_CNTR: lLeft  += std::max(tools::Long(0), aPaperSize.Width() - nPageW) / 2;
347
0
                               break;
348
0
            case ENV_HOR_RGHT: lLeft  += std::max(tools::Long(0), aPaperSize.Width() - nPageW);
349
0
                               break;
350
0
            case ENV_VER_LEFT: lUpper += std::max(tools::Long(0), aPaperSize.Width() - nPageH);
351
0
                               break;
352
0
            case ENV_VER_CNTR: lUpper += std::max(tools::Long(0), aPaperSize.Width() - nPageH) / 2;
353
0
                               break;
354
0
            case ENV_VER_RGHT: break;
355
0
        }
356
0
        SvxLRSpaceItem aLRMargin( RES_LR_SPACE );
357
0
        SvxULSpaceItem aULMargin( RES_UL_SPACE );
358
0
        aLRMargin.SetLeft(SvxIndentValue::twips(o3tl::narrowing<sal_uInt16>(lLeft)));
359
0
        aULMargin.SetUpper(o3tl::narrowing<sal_uInt16>(lUpper));
360
0
        aLRMargin.SetRight(SvxIndentValue::zero());
361
0
        aULMargin.SetLower(0);
362
0
        rFormat.SetFormatAttr(aLRMargin);
363
0
        rFormat.SetFormatAttr(aULMargin);
364
365
        // Header and footer
366
0
        rFormat.SetFormatAttr(SwFormatHeader(false));
367
0
        pDesc->ChgHeaderShare(false);
368
0
        rFormat.SetFormatAttr(SwFormatFooter(false));
369
0
        pDesc->ChgFooterShare(false);
370
371
        // Page numbering
372
0
        pDesc->SetUseOn(UseOnPage::All);
373
374
        // Page size
375
0
        rFormat.SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed,
376
0
                                            nPageW + lLeft, nPageH + lUpper));
377
378
        // Set type of page numbering
379
0
        SvxNumberType aType;
380
0
        aType.SetNumberingType(SVX_NUM_NUMBER_NONE);
381
0
        pDesc->SetNumType(aType);
382
383
        // Followup template
384
0
        if (pFollow)
385
0
            pDesc->SetFollow(pFollow);
386
387
        // Landscape
388
0
        pDesc->SetLandscape( rItem.m_eAlign >= ENV_VER_LEFT &&
389
0
                             rItem.m_eAlign <= ENV_VER_RGHT);
390
391
        // Apply page description
392
393
0
        size_t nPos;
394
0
        pSh->FindPageDescByName( pDesc->GetName(),
395
0
                                    false,
396
0
                                    &nPos );
397
398
0
        pSh->ChgPageDesc( nPos, *pDesc);
399
0
        pSh->ChgCurPageDesc(*pDesc);
400
401
        // Insert Frame
402
0
        SwFlyFrameAttrMgr aMgr(false, pSh, Frmmgr_Type::ENVELP, nullptr);
403
0
        SwFieldMgr aFieldMgr;
404
0
        aMgr.SetHeightSizeType(SwFrameSize::Variable);
405
406
        // Overwrite defaults!
407
0
        aMgr.GetAttrSet().Put( SvxBoxItem(RES_BOX) );
408
0
        aMgr.SetULSpace( 0, 0 );
409
0
        aMgr.SetLRSpace( 0, 0 );
410
411
        // Sender
412
0
        if (rItem.m_bSend)
413
0
        {
414
0
            pSh->SttEndDoc(true);
415
0
            aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PAGE,
416
0
                Point(rItem.m_nSendFromLeft + lLeft, rItem.m_nSendFromTop  + lUpper),
417
0
                Size (rItem.m_nAddrFromLeft - rItem.m_nSendFromLeft, 0));
418
419
0
            pSh->EnterSelFrameMode();
420
0
            pSh->SetFlyName(sSendMark);
421
0
            pSh->UnSelectFrame();
422
0
            pSh->LeaveSelFrameMode();
423
0
            pSh->SetTextFormatColl( pSend );
424
0
            InsertLabEnvText( *pSh, aFieldMgr, rItem.m_aSendText );
425
0
            aMgr.UpdateAttrMgr();
426
0
        }
427
428
        // Addressee
429
0
        pSh->SttEndDoc(true);
430
431
0
        aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PAGE,
432
0
            Point(rItem.m_nAddrFromLeft + lLeft, rItem.m_nAddrFromTop  + lUpper),
433
0
            Size (nPageW - rItem.m_nAddrFromLeft - 566, 0));
434
0
        pSh->EnterSelFrameMode();
435
0
        pSh->SetFlyName(sAddrMark);
436
0
        pSh->UnSelectFrame();
437
0
        pSh->LeaveSelFrameMode();
438
0
        pSh->SetTextFormatColl( pAddr );
439
0
        InsertLabEnvText(*pSh, aFieldMgr, rItem.m_aAddrText);
440
441
        // Move Flys to the "old" pages
442
0
        if (!aFlyArr.empty())
443
0
            pSh->SetPageObjsNewPage(aFlyArr);
444
445
        // Finished
446
0
        pSh->SttEndDoc(true);
447
448
0
        pSh->EndAllAction();
449
450
0
        if (nMode == ENV_NEWDOC)
451
0
            pSh->DoUndo();
452
0
        else
453
0
            pSh->EndUndo(SwUndoId::UI_INSERT_ENVELOPE);
454
455
0
        if (nMode == ENV_NEWDOC)
456
0
        {
457
0
            pFrame->GetFrame().Appear();
458
459
0
            if ( rItem.m_aAddrText.indexOf('<') >= 0 )
460
0
            {
461
0
                static sal_uInt16 const aInva[] =
462
0
                                    {
463
0
                                        SID_SBA_BRW_UPDATE,
464
0
                                        SID_SBA_BRW_INSERT,
465
0
                                        SID_SBA_BRW_MERGE,
466
0
                                        0
467
0
                                    };
468
0
                pFrame->GetBindings().Invalidate( aInva );
469
470
                // Open database beamer
471
0
                ShowDBObj(*pNewView, pSh->GetDBData());
472
0
            }
473
0
        }
474
475
0
        if ( !pItem )
476
0
        {
477
0
            rReq.AppendItem( rItem );
478
0
            if ( nMode == ENV_NEWDOC )
479
0
                rReq.AppendItem( SfxBoolItem( FN_PARAM_1, true ) );
480
0
        }
481
482
0
        rReq.Done();
483
0
    }
484
0
    else    // Abort
485
0
    {
486
0
        rReq.Ignore();
487
488
0
        xDocSh->DoClose();
489
0
        --nTitleNo;
490
491
        // Set pointer to top view
492
0
        if (pOldSh)
493
0
            SetView(&pOldSh->GetView());
494
0
    }
495
0
}
496
497
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */