Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/wrtsh/wrtsh1.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 <com/sun/star/beans/XPropertySet.hpp>
21
#include <com/sun/star/container/XChild.hpp>
22
#include <com/sun/star/embed/EmbedMisc.hpp>
23
#include <com/sun/star/embed/EmbedStates.hpp>
24
#include <com/sun/star/embed/EmbedVerbs.hpp>
25
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
26
#include <com/sun/star/chart2/XChartDocument.hpp>
27
#include <com/sun/star/util/XModifiable.hpp>
28
#include <com/sun/star/lang/XInitialization.hpp>
29
30
#include <hintids.hxx>
31
#include <sot/exchange.hxx>
32
#include <svx/xfillit0.hxx>
33
#include <svx/hdft.hxx>
34
#include <svx/svdview.hxx>
35
#include <svl/itemiter.hxx>
36
#include <tools/bigint.hxx>
37
#include <svtools/insdlg.hxx>
38
#include <sfx2/ipclient.hxx>
39
#include <editeng/editeng.hxx>
40
#include <editeng/editobj.hxx>
41
#include <editeng/formatbreakitem.hxx>
42
#include <editeng/svxacorr.hxx>
43
#include <editeng/ulspitem.hxx>
44
#include <vcl/graph.hxx>
45
#include <vcl/svapp.hxx>
46
#include <unotools/charclass.hxx>
47
#include <comphelper/storagehelper.hxx>
48
#include <comphelper/random.hxx>
49
#include <svx/svxdlg.hxx>
50
#include <svx/extrusionbar.hxx>
51
#include <svx/fontworkbar.hxx>
52
#include <dialoghelp.hxx>
53
#include <frmfmt.hxx>
54
#include <fmtclds.hxx>
55
#include <fmtftn.hxx>
56
#include <fmthdft.hxx>
57
#include <fmtpdsc.hxx>
58
#include <txtfrm.hxx>
59
#include <wdocsh.hxx>
60
#include <swmodule.hxx>
61
#include <wrtsh.hxx>
62
#include <view.hxx>
63
#include <cmdid.h>
64
#include <pagedesc.hxx>
65
#include <frmmgr.hxx>
66
#include <swundo.hxx>
67
#include <swcli.hxx>
68
#include <poolfmt.hxx>
69
#include <postithelper.hxx>
70
#include <edtwin.hxx>
71
#include <fmtcol.hxx>
72
#include <swtable.hxx>
73
#include <viscrs.hxx>
74
#include <swdtflvr.hxx>
75
#include <doc.hxx>
76
#include <docstat.hxx>
77
#include <IDocumentSettingAccess.hxx>
78
#include <SwCapObjType.hxx>
79
#include <SwStyleNameMapper.hxx>
80
#include <sfx2/request.hxx>
81
#include <paratr.hxx>
82
#include <ndtxt.hxx>
83
#include <editeng/acorrcfg.hxx>
84
#include <IMark.hxx>
85
#include <sfx2/bindings.hxx>
86
#include <flyfrm.hxx>
87
88
// -> #111827#
89
#include <SwRewriter.hxx>
90
#include <strings.hrc>
91
// <- #111827#
92
93
#include <toolkit/helper/vclunohelper.hxx>
94
#include <sfx2/viewfrm.hxx>
95
#include <vcl/uitest/logger.hxx>
96
#include <vcl/uitest/eventdescription.hxx>
97
#include <osl/diagnose.h>
98
#include <o3tl/unit_conversion.hxx>
99
#include <officecfg/Office/Common.hxx>
100
#include <com/sun/star/i18n/WordType.hpp>
101
102
#include <PostItMgr.hxx>
103
#include <FrameControlsManager.hxx>
104
#include <fldmgr.hxx>
105
#include <docufld.hxx>
106
#include <IDocumentFieldsAccess.hxx>
107
#include <fmtfld.hxx>
108
109
#include <sfx2/msgpool.hxx>
110
#include <sfx2/msg.hxx>
111
#include <svtools/embedhlp.hxx>
112
#include <svtools/strings.hrc>
113
#include <svtools/svtresid.hxx>
114
#include <svx/postattr.hxx>
115
#include <comphelper/lok.hxx>
116
#include <comphelper/propertyvalue.hxx>
117
#include <svtools/optionsdrawinglayer.hxx>
118
#include <svl/numformat.hxx>
119
#include <svl/zformat.hxx>
120
#include <vcl/weld/MessageDialog.hxx>
121
#include <memory>
122
123
#include "../../core/crsr/callnk.hxx"
124
#include <frmtool.hxx>
125
#include <viewopt.hxx>
126
127
#include <IDocumentRedlineAccess.hxx>
128
#include <IDocumentUndoRedo.hxx>
129
#include <UndoInsert.hxx>
130
#include <UndoCore.hxx>
131
#include <formatlinebreak.hxx>
132
#include <formatcontentcontrol.hxx>
133
#include <textcontentcontrol.hxx>
134
135
#include <UndoAttribute.hxx>
136
137
#include <comphelper/flagguard.hxx>
138
139
using namespace sw::mark;
140
using namespace com::sun::star;
141
namespace {
142
143
void collectUIInformation(const OUString& rAction, const OUString& aParameters)
144
0
{
145
0
    EventDescription aDescription;
146
0
    aDescription.aAction = rAction;
147
0
    aDescription.aParameters = {{"parameters", aParameters}};
148
0
    aDescription.aID = "writer_edit";
149
0
    aDescription.aKeyWord = "SwEditWinUIObject";
150
0
    aDescription.aParent = "MainWindow";
151
0
    UITestLogger::getInstance().logEvent(aDescription);
152
0
}
153
154
}
155
156
sal_uInt32 MakeAllOutlineContentTemporarilyVisible::nLock = 0;
157
158
static bool lcl_IsAllowed(const SwWrtShell* rSh)
159
0
{
160
0
    if (rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() && rSh->IsEndPara())
161
0
    {
162
0
        SwTextNode* pTextNode = rSh->GetCursor()->GetPointNode().GetTextNode();
163
0
        if (pTextNode && pTextNode->IsOutline())
164
0
        {
165
            // disallow if this is an outline node having folded content
166
0
            if (!pTextNode->GetAttrOutlineContentVisible())
167
0
                return false;
168
0
        }
169
0
    }
170
0
    return true;
171
0
}
172
173
#define BITFLD_INI_LIST \
174
4.14k
        m_bClearMark = \
175
4.14k
        m_bIns = true;\
176
4.14k
        m_bAddMode = \
177
4.14k
        m_bBlockMode = \
178
4.14k
        m_bExtMode = \
179
4.14k
        m_bInSelect = \
180
4.14k
        m_bLayoutMode = \
181
4.14k
        m_bSelWrd = \
182
4.14k
        m_bSelLn = \
183
4.14k
        m_bRetainSelection = false; \
184
4.14k
        m_bIsInClickToEdit = false;
185
186
static SvxAutoCorrect* lcl_IsAutoCorr()
187
0
{
188
0
    SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
189
0
    if( pACorr && !pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
190
0
                            ACFlags::AddNonBrkSpace | ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
191
0
                            ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr | ACFlags::Autocorrect |
192
0
                            ACFlags::SetDOIAttr | ACFlags::EsperantoHats ))
193
0
        pACorr = nullptr;
194
0
    return pACorr;
195
0
}
196
197
void SwWrtShell::NoEdit(bool bHideCursor)
198
0
{
199
0
    if(bHideCursor)
200
0
        HideCursor();
201
0
}
202
203
void SwWrtShell::Edit()
204
0
{
205
0
    if (CanInsert())
206
0
    {
207
0
        ShowCursor();
208
0
    }
209
0
}
210
211
bool SwWrtShell::IsEndWrd()
212
0
{
213
0
    SwMvContext aMvContext(this);
214
0
    if(IsEndPara() && !IsSttPara())
215
0
        return true;
216
217
0
    return IsEndWord();
218
0
}
219
220
// Insert string
221
void SwWrtShell::InsertByWord( const OUString & rStr)
222
0
{
223
0
    if( rStr.isEmpty() )
224
0
        return;
225
226
0
    bool bDelim = GetAppCharClass().isLetterNumeric( rStr, 0 );
227
0
    sal_Int32 nPos = 0, nStt = 0;
228
0
    for( ; nPos < rStr.getLength(); nPos++ )
229
0
    {
230
0
        bool bTmpDelim = GetAppCharClass().isLetterNumeric( rStr, nPos );
231
0
        if( bTmpDelim != bDelim )
232
0
        {
233
0
            Insert( rStr.copy( nStt, nPos - nStt ));
234
0
            nStt = nPos;
235
0
        }
236
0
    }
237
0
    if( nStt != nPos )
238
0
        Insert( rStr.copy( nStt, nPos - nStt ));
239
0
}
240
241
void SwWrtShell::Insert( const OUString &rStr )
242
0
{
243
0
    ResetCursorStack();
244
0
    if( !CanInsert() )
245
0
        return;
246
247
0
    bool bStarted = false;
248
0
    bool bHasSel = HasSelection(),
249
0
         bCallIns = m_bIns /*|| bHasSel*/;
250
0
    bool bDeleted = false;
251
252
    // tdf#169913 - insert at cursor position without overwriting the selection
253
0
    if (bHasSel && !SwViewOption::IsTypingReplacesSelection())
254
0
    {
255
0
        NormalizePam(false);
256
0
        ClearMark();
257
0
        bHasSel = false;
258
0
    }
259
260
0
    if( bHasSel || ( !m_bIns && IsInHiddenRange(/*bSelect=*/true) ) )
261
0
    {
262
            // Only here parenthesizing, because the normal
263
            // insert is already in parentheses at Editshell.
264
0
        StartAllAction();
265
266
0
        SwRewriter aRewriter;
267
268
0
        aRewriter.AddRule(UndoArg1, GetCursorDescr());
269
0
        aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
270
0
        {
271
0
            OUString aTmpStr = SwResId(STR_START_QUOTE) +
272
0
                rStr + SwResId(STR_END_QUOTE);
273
274
0
            aRewriter.AddRule(UndoArg3, aTmpStr);
275
0
        }
276
277
0
        StartUndo(SwUndoId::REPLACE, &aRewriter);
278
0
        bStarted = true;
279
0
        Push();
280
        // let's interpret a selection within the same node as "replace"
281
0
        bDeleted = DelRight(GetCursor()->GetPoint()->GetNode() == GetCursor()->GetMark()->GetNode());
282
0
        Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if tracking changes)
283
0
        NormalizePam(false); // tdf#127635 put point at the end of deletion
284
0
        ClearMark();
285
0
    }
286
287
0
    bCallIns ?
288
0
        SwEditShell::Insert2( rStr, bDeleted ) : SwEditShell::Overwrite( rStr );
289
290
    // Check whether node is content control
291
0
    SwTextContentControl* pTextContentControl = CursorInsideContentControl();
292
0
    if (pTextContentControl)
293
0
    {
294
0
        std::shared_ptr<SwContentControl> pContentControl =
295
0
            pTextContentControl->GetContentControl().GetContentControl();
296
0
        if (pContentControl)
297
0
        {
298
            // Set showingPlcHdr to false as node has been edited
299
0
            pContentControl->SetShowingPlaceHolder(false);
300
0
        }
301
0
    }
302
303
0
    if( bStarted )
304
0
    {
305
0
        EndUndo();
306
0
        EndAllAction();
307
0
    }
308
0
}
309
310
// Maximum height limit not possible, because the maximum height
311
// of the current frame can not be obtained.
312
313
void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter,
314
                                const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr,
315
                                RndStdIds nAnchorType )
316
0
{
317
0
    ResetCursorStack();
318
0
    if ( !CanInsert() )
319
0
        return;
320
321
0
    StartAllAction();
322
323
0
    SwRewriter aRewriter;
324
0
    aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC));
325
326
0
    StartUndo(SwUndoId::INSERT, &aRewriter);
327
328
0
    if ( HasSelection() )
329
0
        DelRight();
330
        // Inserted graphics in its own paragraph,
331
        // if at the end of a non-empty paragraph.
332
    //For i120928,avoid to split node
333
334
0
    EnterSelFrameMode();
335
336
0
    bool bSetGrfSize = true;
337
0
    bool bOwnMgr     = false;
338
339
0
    if ( !pFrameMgr )
340
0
    {
341
0
        bOwnMgr = true;
342
0
        pFrameMgr = new SwFlyFrameAttrMgr( true, this, Frmmgr_Type::GRF, nullptr );
343
344
        // CAUTION
345
        // GetAttrSet makes an adjustment
346
        // While pasting is a SwFrameSize present
347
        // because of the DEF-Framesize
348
        // These must be removed explicitly for the optimal size.
349
0
        pFrameMgr->DelAttr(RES_FRM_SIZE);
350
351
0
        if (nAnchorType != RndStdIds::FLY_AT_PARA)
352
            // Something other than at-para was requested.
353
0
            pFrameMgr->SetAnchor(nAnchorType);
354
0
    }
355
0
    else
356
0
    {
357
0
        Size aSz( pFrameMgr->GetSize() );
358
0
        if ( !aSz.Width() || !aSz.Height() )
359
0
        {
360
0
            aSz.setWidth(o3tl::toTwips(1, o3tl::Length::cm));
361
0
            aSz.setHeight(o3tl::toTwips(1, o3tl::Length::cm));
362
0
            pFrameMgr->SetSize( aSz );
363
0
        }
364
0
        else if ( aSz.Width() != DFLT_WIDTH && aSz.Height() != DFLT_HEIGHT )
365
0
            bSetGrfSize = false;
366
367
0
        pFrameMgr->SetHeightSizeType(SwFrameSize::Fixed);
368
0
    }
369
370
    // during change tracking, insert the image anchored as character
371
    // (to create an SwRangeRedline on its anchor point)
372
0
    if ( IsRedlineOn() && nAnchorType != RndStdIds::FLY_AS_CHAR )
373
0
        pFrameMgr->SetAnchor( RndStdIds::FLY_AS_CHAR );
374
375
    // Insert the graphic
376
0
    SwFEShell::Insert(rPath, rFilter, &rGrf, &pFrameMgr->GetAttrSet());
377
0
    if ( bOwnMgr )
378
0
        pFrameMgr->UpdateAttrMgr();
379
380
0
    if( bSetGrfSize )
381
0
    {
382
0
        Size aSizePixel = rGrf.GetSizePixel();
383
0
        Size aBound = GetGraphicDefaultSize();
384
385
0
        sal_Int32 nPreferredDPI = mxDoc->getIDocumentSettingAccess().getImagePreferredDPI();
386
0
        Size aGrfSize;
387
388
0
        if (nPreferredDPI > 0)
389
0
        {
390
0
            auto nWidth = o3tl::toTwips(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in);
391
0
            auto nHeight = o3tl::toTwips(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in);
392
0
            aGrfSize = Size(nWidth, nHeight);
393
0
        }
394
0
        else
395
0
        {
396
0
            GetGrfSize(aGrfSize);
397
0
        }
398
399
        // Add the margin attributes to GrfSize,
400
        // because these counts at the margin additionally
401
0
        aGrfSize.AdjustWidth(pFrameMgr->CalcWidthBorder() );
402
0
        aGrfSize.AdjustHeight(pFrameMgr->CalcHeightBorder() );
403
404
0
        const BigInt aTempWidth( aGrfSize.Width() );
405
0
        const BigInt aTempHeight( aGrfSize.Height());
406
407
        // Fit width if necessary, scale down the height proportional thereafter.
408
0
        if( aGrfSize.Width() > aBound.Width() )
409
0
        {
410
0
            aGrfSize.setWidth( aBound.Width() );
411
0
            aGrfSize.setHeight( BigInt(aBound.Width()) * aTempHeight / aTempWidth );
412
0
        }
413
        // Fit height if necessary, scale down the width proportional thereafter.
414
0
        if( aGrfSize.Height() > aBound.Height() )
415
0
        {
416
0
            aGrfSize.setHeight( aBound.Height() );
417
0
            aGrfSize.setWidth(  BigInt(aBound.Height()) * aTempWidth / aTempHeight );
418
0
        }
419
0
        pFrameMgr->SetSize( aGrfSize );
420
0
        pFrameMgr->UpdateFlyFrame();
421
0
    }
422
0
    if ( bOwnMgr )
423
0
        delete pFrameMgr;
424
425
0
    EndUndo();
426
0
    EndAllAction();
427
0
}
428
429
// Insert an OLE-Object into the CORE.
430
// if no object is transferred, then one will be created.
431
432
void SwWrtShell::InsertObject( const svt::EmbeddedObjectRef& xRef, SvGlobalName const *pName,
433
                               sal_uInt16 nSlotId )
434
0
{
435
0
    ResetCursorStack();
436
0
    if( !CanInsert() )
437
0
        return;
438
439
0
    if( !xRef.is() )
440
0
    {
441
        // temporary storage
442
0
        svt::EmbeddedObjectRef xObj;
443
0
        uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetTemporaryStorage();
444
0
        bool bDoVerb = true;
445
0
        if ( pName )
446
0
        {
447
0
            comphelper::EmbeddedObjectContainer aCnt( xStor );
448
0
            OUString aName;
449
            // TODO/LATER: get aspect?
450
0
            xObj.Assign( aCnt.CreateEmbeddedObject( pName->GetByteSequence(), aName ), embed::Aspects::MSOLE_CONTENT );
451
0
        }
452
0
        else
453
0
        {
454
0
            SvObjectServerList aServerList;
455
0
            switch (nSlotId)
456
0
            {
457
0
                case SID_INSERT_OBJECT:
458
0
                {
459
0
                    if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
460
0
                    {
461
0
                        std::unique_ptr<weld::MessageDialog> xError(
462
0
                            Application::CreateMessageDialog(
463
0
                                nullptr, VclMessageType::Warning, VclButtonsType::Ok,
464
0
                                SvtResId(STR_WARNING_ACTIVE_CONTENT_DISABLED)));
465
0
                        xError->run();
466
0
                        break;
467
0
                    }
468
0
                    aServerList.FillInsertObjects();
469
0
                    aServerList.Remove( SwDocShell::Factory().GetClassId() );
470
0
                    [[fallthrough]];
471
0
                }
472
473
                // TODO/LATER: recording! Convert properties to items
474
0
                case SID_INSERT_FLOATINGFRAME:
475
0
                {
476
0
                    SfxSlotPool* pSlotPool = SwModule::get()->GetSlotPool();
477
0
                    const SfxSlot* pSlot = pSlotPool->GetSlot(nSlotId);
478
0
                    OUString aCmd = pSlot->GetCommand();
479
0
                    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
480
0
                    ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(pFact->CreateInsertObjectDialog(GetFrameWeld(mxDoc->GetDocShell()),
481
0
                                aCmd, xStor, &aServerList));
482
0
                    if (pDlg)
483
0
                    {
484
0
                        pDlg->Execute();
485
0
                        bDoVerb = pDlg->IsCreateNew();
486
0
                        OUString aIconMediaType;
487
0
                        uno::Reference< io::XInputStream > xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
488
0
                        xObj.Assign( pDlg->GetObject(),
489
0
                                     xIconMetaFile.is() ? embed::Aspects::MSOLE_ICON : embed::Aspects::MSOLE_CONTENT );
490
0
                        if ( xIconMetaFile.is() )
491
0
                            xObj.SetGraphicStream( xIconMetaFile, aIconMediaType );
492
0
                    }
493
494
0
                    break;
495
0
                }
496
497
0
                default:
498
0
                    break;
499
0
            }
500
0
        }
501
502
0
        if ( xObj.is() )
503
0
        {
504
0
            if( InsertOleObject( xObj ) && bDoVerb )
505
0
            {
506
0
                SfxInPlaceClient* pClient = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
507
0
                if ( !pClient )
508
0
                {
509
0
                    pClient = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
510
0
                    SetCheckForOLEInCaption( true );
511
0
                }
512
513
0
                if ( xObj.GetViewAspect() == embed::Aspects::MSOLE_ICON )
514
0
                {
515
0
                    SwRect aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
516
0
                    aArea += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
517
0
                    MapMode aMapMode( MapUnit::MapTwip );
518
0
                    Size aSize = xObj.GetSize( &aMapMode );
519
0
                    aArea.Width( aSize.Width() );
520
0
                    aArea.Height( aSize.Height() );
521
0
                    RequestObjectResize( aArea, xObj.GetObject() );
522
0
                }
523
0
                else
524
0
                    CalcAndSetScale( xObj );
525
526
                //#50270# We don't need to handle error, this is handled by the
527
                //DoVerb in the SfxViewShell
528
0
                pClient->DoVerb(embed::EmbedVerbs::MS_OLEVERB_SHOW);
529
530
                // TODO/LATER: set document name - should be done in Client
531
0
            }
532
0
        }
533
0
    }
534
0
    else
535
0
    {
536
0
        if( HasSelection() )
537
0
            DelRight();
538
0
        InsertOleObject( xRef );
539
0
    }
540
0
}
541
542
// Insert object into the Core.
543
// From ClipBoard or Insert
544
545
bool SwWrtShell::InsertOleObject( const svt::EmbeddedObjectRef& xRef, SwFlyFrameFormat **pFlyFrameFormat )
546
0
{
547
    //tdf#125100 Ensure that ole object is initially shown as pictogram
548
0
    comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mxDoc->GetDocShell()->getEmbeddedObjectContainer();
549
0
    bool bSaveUserAllowsLinkUpdate = rEmbeddedObjectContainer.getUserAllowsLinkUpdate();
550
0
    rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
551
552
0
    ResetCursorStack();
553
0
    StartAllAction();
554
555
0
    StartUndo(SwUndoId::INSERT);
556
557
    //Some differences between StarMath and any other objects:
558
    //1. Selections should be deleted. For StarMath the Text should be
559
    //   passed to the Object
560
    //2. If the cursor is at the end of a non empty paragraph a paragraph
561
    //   break should be inserted. StarMath objects are character bound and
562
    //   no break should be inserted.
563
    //3. If an selection is passed to a StarMath object, this object should
564
    //   not be activated. false should be returned then.
565
0
    bool bStarMath = true;
566
0
    bool bActivate = true;
567
568
    // set parent to get correct VisArea(in case of object needing parent printer)
569
0
    uno::Reference < container::XChild > xChild( xRef.GetObject(), uno::UNO_QUERY );
570
0
    if ( xChild.is() )
571
0
        xChild->setParent( mxDoc->GetDocShell()->GetModel() );
572
573
0
    SvGlobalName aCLSID( xRef->getClassID() );
574
0
    bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
575
0
    if( IsSelection() )
576
0
    {
577
0
        if( bStarMath )
578
0
        {
579
0
            OUString aMathData;
580
0
            GetSelectedText( aMathData, ParaBreakType::ToOnlyCR );
581
582
0
            if( !aMathData.isEmpty() && svt::EmbeddedObjectRef::TryRunningState( xRef.GetObject() ) )
583
0
            {
584
0
                uno::Reference < beans::XPropertySet > xSet( xRef->getComponent(), uno::UNO_QUERY );
585
0
                if ( xSet.is() )
586
0
                {
587
0
                    try
588
0
                    {
589
0
                        xSet->setPropertyValue(u"Formula"_ustr, uno::Any( aMathData ) );
590
0
                        bActivate = false;
591
0
                    }
592
0
                    catch (const uno::Exception&)
593
0
                    {
594
0
                    }
595
0
                }
596
0
            }
597
0
        }
598
0
        DelRight();
599
0
    }
600
601
0
    if ( !bStarMath )
602
0
        SwFEShell::SplitNode(false);
603
604
0
    EnterSelFrameMode();
605
606
0
    const SvGlobalName* pName = nullptr;
607
0
    SvGlobalName aObjClsId;
608
0
    if (xRef.is())
609
0
    {
610
0
        aObjClsId = SvGlobalName(xRef.GetObject()->getClassID());
611
0
        pName = &aObjClsId;
612
0
    }
613
0
    SwFlyFrameAttrMgr aFrameMgr( true, this, Frmmgr_Type::OLE, pName );
614
0
    aFrameMgr.SetHeightSizeType(SwFrameSize::Fixed);
615
616
0
    SwRect aBound;
617
0
    CalcBoundRect( aBound, aFrameMgr.GetAnchor() );
618
619
    //The Size should be suggested by the OLE server
620
0
    MapMode aMapMode( MapUnit::MapTwip );
621
0
    Size aSz = xRef.GetSize( &aMapMode );
622
623
    //Object size can be limited
624
0
    if ( aSz.Width() > aBound.Width() )
625
0
    {
626
        //Always limit proportional.
627
0
        aSz.setHeight( aSz.Height() * aBound.Width() / aSz.Width() );
628
0
        aSz.setWidth( aBound.Width() );
629
0
    }
630
0
    aFrameMgr.SetSize( aSz );
631
0
    SwFlyFrameFormat *pFormat = SwFEShell::InsertObject( xRef, &aFrameMgr.GetAttrSet() );
632
633
    // --> #i972#
634
0
    if ( bStarMath && mxDoc->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT ) )
635
0
        AlignFormulaToBaseline( xRef.GetObject() );
636
637
0
    if (pFlyFrameFormat)
638
0
        *pFlyFrameFormat = pFormat;
639
640
0
    if ( SotExchange::IsChart( aCLSID ) )
641
0
    {
642
0
        const uno::Reference< embed::XEmbeddedObject >& xEmbeddedObj = xRef.GetObject();
643
0
        if ( xEmbeddedObj.is() )
644
0
        {
645
0
            bool bDisableDataTableDialog = false;
646
0
            svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
647
0
            uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
648
0
            if ( xProps.is() &&
649
0
                 ( xProps->getPropertyValue(u"DisableDataTableDialog"_ustr) >>= bDisableDataTableDialog ) &&
650
0
                 bDisableDataTableDialog )
651
0
            {
652
0
                xProps->setPropertyValue(u"DisableDataTableDialog"_ustr,
653
0
                    uno::Any( false ) );
654
0
                xProps->setPropertyValue(u"DisableComplexChartTypes"_ustr,
655
0
                    uno::Any( false ) );
656
0
                uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY );
657
0
                if ( xModifiable.is() )
658
0
                {
659
0
                    xModifiable->setModified( true );
660
0
                }
661
0
            }
662
0
        }
663
0
    }
664
665
0
    EndAllAction();
666
0
    GetView().AutoCaption(OLE_CAP, &aCLSID);
667
668
0
    SwRewriter aRewriter;
669
670
0
    if ( bStarMath )
671
0
        aRewriter.AddRule(UndoArg1, SwResId(STR_MATH_FORMULA));
672
0
    else if ( SotExchange::IsChart( aCLSID ) )
673
0
        aRewriter.AddRule(UndoArg1, SwResId(STR_CHART));
674
0
    else
675
0
        aRewriter.AddRule(UndoArg1, SwResId(STR_OLE));
676
677
0
    EndUndo(SwUndoId::INSERT, &aRewriter);
678
679
0
    rEmbeddedObjectContainer.setUserAllowsLinkUpdate(bSaveUserAllowsLinkUpdate);
680
681
0
    return bActivate;
682
0
}
683
684
0
bool SwWrtShell::IsOLEMath() {
685
0
    svt::EmbeddedObjectRef& xRef = GetOLEObject();
686
0
    OSL_ENSURE( xRef.is(), "OLE not found" );
687
688
0
    const auto classId = xRef->getClassID();
689
0
    if ( SotExchange::IsMath(classId) )
690
0
        return true;
691
0
    return false;
692
0
}
693
694
// The current selected OLE object will be loaded with the
695
// verb into the server.
696
void SwWrtShell::LaunchOLEObj(sal_Int32 nVerb)
697
0
{
698
0
    if ( GetCntType() != CNT_OLE ||
699
0
         GetView().GetViewFrame().GetFrame().IsInPlace() )
700
0
        return;
701
702
0
    svt::EmbeddedObjectRef& xRef = GetOLEObject();
703
0
    OSL_ENSURE( xRef.is(), "OLE not found" );
704
705
    // LOK: we don't want to handle any other embedded objects than
706
    // charts, there are too many problems with eg. embedded spreadsheets
707
    // (like it creates a separate view for the calc sheet)
708
0
    if (comphelper::LibreOfficeKit::isActive())
709
0
    {
710
0
        const auto classId = xRef->getClassID();
711
0
        if (!SotExchange::IsChart(classId) && !SotExchange::IsMath(classId))
712
0
            return;
713
0
    }
714
715
0
    SfxInPlaceClient* pCli = GetView().FindIPClient( xRef.GetObject(), &GetView().GetEditWin() );
716
0
    if ( !pCli )
717
0
        pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xRef );
718
719
0
    uno::Reference<lang::XInitialization> xOLEInit(xRef.GetObject(), uno::UNO_QUERY);
720
0
    if (xOLEInit.is())
721
0
    {
722
0
        uno::Sequence<beans::PropertyValue> aArguments
723
0
            = { comphelper::makePropertyValue(u"ReadOnly"_ustr, pCli->IsProtected()) };
724
0
        xOLEInit->initialize({ uno::Any(aArguments) });
725
0
    }
726
727
0
    static_cast<SwOleClient*>(pCli)->SetInDoVerb( true );
728
729
0
    CalcAndSetScale( xRef );
730
0
    pCli->DoVerb( nVerb );
731
732
0
    static_cast<SwOleClient*>(pCli)->SetInDoVerb( false );
733
0
    CalcAndSetScale( xRef );
734
0
}
735
736
void SwWrtShell::MoveObjectIfActive( svt::EmbeddedObjectRef& xObj, const Point& rOffset )
737
0
{
738
0
    try
739
0
    {
740
0
        sal_Int32 nState = xObj->getCurrentState();
741
0
        if ( nState == css::embed::EmbedStates::INPLACE_ACTIVE
742
0
          || nState == css::embed::EmbedStates::UI_ACTIVE )
743
0
        {
744
0
            SfxInPlaceClient* pCli =
745
0
                GetView().FindIPClient( xObj.GetObject(), &(GetView().GetEditWin()) );
746
0
            if ( pCli )
747
0
            {
748
0
                tools::Rectangle aArea = pCli->GetObjArea();
749
0
                aArea += rOffset;
750
0
                pCli->SetObjArea( aArea );
751
0
            }
752
0
        }
753
0
    }
754
0
    catch (const uno::Exception&)
755
0
    {
756
0
    }
757
0
}
758
759
void SwWrtShell::CalcAndSetScale( svt::EmbeddedObjectRef& xObj,
760
                                  const SwRect *pFlyPrtRect,
761
                                  const SwRect *pFlyFrameRect,
762
                                  const bool bNoTextFramePrtAreaChanged )
763
0
{
764
    // Setting the scale of the client. This arises from the difference
765
    // between the VisArea of the object and the ObjArea.
766
0
    OSL_ENSURE( xObj.is(), "ObjectRef not  valid" );
767
768
0
    sal_Int64 nAspect = xObj.GetViewAspect();
769
0
    if ( nAspect == embed::Aspects::MSOLE_ICON )
770
0
        return; // the replacement image is completely controlled by container in this case
771
772
0
    sal_Int64 nMisc = 0;
773
0
    bool bLinkingChart = false;
774
775
0
    try
776
0
    {
777
0
        nMisc = xObj->getStatus( nAspect );
778
779
        // This can surely only be a non-active object, if desired they
780
        // get the new size set as VisArea (StarChart).
781
0
        if( embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE & nMisc )
782
0
        {
783
            // TODO/MBA: testing
784
0
            SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
785
0
                        : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
786
0
            if( !aRect.IsEmpty() )
787
0
            {
788
                // TODO/LEAN: getMapUnit can switch object to running state
789
                // xObj.TryRunningState();
790
791
0
                MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
792
793
                // TODO/LATER: needs complete VisArea?!
794
0
                Size aSize( OutputDevice::LogicToLogic(aRect.SVRect(), MapMode(MapUnit::MapTwip), MapMode(aUnit)).GetSize() );
795
0
                awt::Size aSz;
796
0
                aSz.Width = aSize.Width();
797
0
                aSz.Height = aSize.Height();
798
799
                // Action 'setVisualAreaSize' doesn't have to turn on the
800
                // modified state of the document, either.
801
0
                bool bModified = false;
802
0
                uno::Reference<util::XModifiable> xModifiable(xObj->getComponent(), uno::UNO_QUERY);
803
0
                if (xModifiable.is())
804
0
                    bModified = xModifiable->isModified();
805
0
                xObj->setVisualAreaSize( nAspect, aSz );
806
0
                xModifiable.set(xObj->getComponent(), uno::UNO_QUERY);
807
0
                if (xModifiable.is() && xModifiable->isModified() && !bModified)
808
0
                    xModifiable->setModified(bModified);
809
810
                // #i48419# - action 'UpdateReplacement' doesn't
811
                // have to change the modified state of the document.
812
                // This is only a workaround for the defect, that this action
813
                // modifies a document after load, because unnecessarily the
814
                // replacement graphic is updated, in spite of the fact that
815
                // nothing has been changed.
816
                // If the replacement graphic changes by this action, the document
817
                // will be already modified via other mechanisms.
818
0
                {
819
0
                    bool bResetEnableSetModified(false);
820
0
                    if ( GetDoc()->GetDocShell()->IsEnableSetModified() )
821
0
                    {
822
0
                        GetDoc()->GetDocShell()->EnableSetModified( false );
823
0
                        bResetEnableSetModified = true;
824
0
                    }
825
826
                    //#i79576# don't destroy chart replacement images on load
827
                    //#i79578# don't request a new replacement image for charts to often
828
                    //a chart sends a modified call to the framework if it was changed
829
                    //thus the replacement update is already handled elsewhere
830
0
                    if ( !SotExchange::IsChart( xObj->getClassID() ) )
831
0
                        xObj.UpdateReplacement();
832
833
0
                    if ( bResetEnableSetModified )
834
0
                    {
835
0
                        GetDoc()->GetDocShell()->EnableSetModified();
836
0
                    }
837
0
                }
838
0
            }
839
840
            // TODO/LATER: this is only a workaround,
841
0
            uno::Reference< chart2::XChartDocument > xChartDocument( xObj->getComponent(), uno::UNO_QUERY );
842
0
            bLinkingChart = ( xChartDocument.is() && !xChartDocument->hasInternalDataProvider() );
843
0
        }
844
0
    }
845
0
    catch (const uno::Exception&)
846
0
    {
847
        // TODO/LATER: handle the error
848
0
        return;
849
0
    }
850
851
0
    SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
852
0
    if ( !pCli )
853
0
    {
854
0
        if ( (embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY & nMisc)
855
0
             || bLinkingChart
856
             // --> OD #i117189# - refine condition for non-resizable objects
857
             // non-resizable objects need to be set the size back by this method
858
0
             || ( bNoTextFramePrtAreaChanged && nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
859
0
        {
860
0
            pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
861
0
        }
862
0
        else
863
0
            return;
864
0
    }
865
866
    // TODO/LEAN: getMapUnit can switch object to running state
867
    // xObj.TryRunningState();
868
869
0
    awt::Size aSize;
870
0
    try
871
0
    {
872
0
        aSize = xObj->getVisualAreaSize( nAspect );
873
0
    }
874
0
    catch (const embed::NoVisualAreaSizeException&)
875
0
    {
876
0
        OSL_FAIL("Can't get visual area size!" );
877
        // the scaling will not be done
878
0
    }
879
0
    catch (const uno::Exception&)
880
0
    {
881
        // TODO/LATER: handle the error
882
0
        OSL_FAIL("Can't get visual area size!" );
883
0
        return;
884
0
    }
885
886
0
    Size _aVisArea( aSize.Width, aSize.Height );
887
888
0
    double fScaleWidth = 1.0;
889
0
    double fScaleHeight = 1.0;
890
891
0
    bool bUseObjectSize = false;
892
893
    // As long as there comes no reasonable size from the object,
894
    // nothing can be scaled.
895
0
    if( _aVisArea.Width() && _aVisArea.Height() )
896
0
    {
897
0
        const MapMode aTmp( MapUnit::MapTwip );
898
0
        MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
899
0
        _aVisArea = OutputDevice::LogicToLogic(_aVisArea, MapMode(aUnit), aTmp);
900
0
        Size aObjArea;
901
0
        if ( pFlyPrtRect )
902
0
            aObjArea = pFlyPrtRect->SSize();
903
0
        else
904
0
            aObjArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ).SSize();
905
906
        // differ the aObjArea and _aVisArea by 1 Pixel then set new VisArea
907
0
        tools::Long nX, nY;
908
0
        SwSelPaintRects::Get1PixelInLogic( *this, &nX, &nY );
909
0
        if( !( _aVisArea.Width() - nX <= aObjArea.Width() &&
910
0
               _aVisArea.Width() + nX >= aObjArea.Width() &&
911
0
               _aVisArea.Height()- nY <= aObjArea.Height()&&
912
0
               _aVisArea.Height()+ nY >= aObjArea.Height() ))
913
0
        {
914
0
            if ( nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE )
915
0
            {
916
                // the object must not be scaled,
917
                // the size stored in object must be used for restoring
918
0
                bUseObjectSize = true;
919
0
            }
920
0
            else
921
0
            {
922
0
                fScaleWidth = static_cast<double>(aObjArea.Width()) / _aVisArea.Width();
923
0
                fScaleHeight = static_cast<double>(aObjArea.Height()) / _aVisArea.Height();
924
0
            }
925
0
        }
926
0
    }
927
928
    // Now is the favorable time to set the ObjArea.
929
    // The Scaling must be considered.
930
0
    SwRect aArea;
931
0
    if ( pFlyPrtRect )
932
0
    {
933
0
        aArea = *pFlyPrtRect;
934
0
        aArea += pFlyFrameRect->Pos();
935
0
    }
936
0
    else
937
0
    {
938
0
        aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
939
0
        aArea += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
940
0
    }
941
942
0
    if ( bUseObjectSize )
943
0
    {
944
        // --> this moves non-resizable object so that when adding borders the baseline remains the same
945
0
        const SwFlyFrameFormat *pFlyFrameFormat = dynamic_cast< const SwFlyFrameFormat * >( GetFlyFrameFormat() );
946
0
        OSL_ENSURE( pFlyFrameFormat, "Could not find fly frame." );
947
0
        if ( pFlyFrameFormat )
948
0
        {
949
0
            const Point &rPoint = pFlyFrameFormat->GetLastFlyFramePrtRectPos();
950
0
            SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
951
0
                        : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
952
0
            aArea += rPoint - aRect.Pos(); // adjust area by diff of printing area position in order to keep baseline alignment correct.
953
0
        }
954
0
        aArea.Width ( _aVisArea.Width() );
955
0
        aArea.Height( _aVisArea.Height() );
956
0
        RequestObjectResize( aArea, xObj.GetObject() );
957
0
    }
958
0
    else
959
0
    {
960
0
        double nWidth(pCli->GetScaleWidth());
961
0
        double nHeight(pCli->GetScaleHeight());
962
0
        if (nWidth && nHeight)
963
0
        {
964
0
            aArea.Width ( aArea.Width()  / nWidth );
965
0
            aArea.Height( aArea.Height() / nHeight );
966
0
        }
967
0
    }
968
969
0
    pCli->SetObjAreaAndScale( aArea.SVRect(), fScaleWidth, fScaleHeight );
970
0
}
971
972
void SwWrtShell::ConnectObj( svt::EmbeddedObjectRef& xObj, const SwRect &rPrt,
973
                            const SwRect &rFrame )
974
0
{
975
0
    SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin());
976
0
    if ( !pCli )
977
0
        new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
978
0
    CalcAndSetScale( xObj, &rPrt, &rFrame );
979
0
}
980
981
// Insert hard page break;
982
// Selections will be overwritten
983
void SwWrtShell::InsertPageBreak(const UIName *pPageDesc, const ::std::optional<sal_uInt16>& oPgNum )
984
0
{
985
0
    if (!lcl_IsAllowed(this))
986
0
        return;
987
988
0
    ResetCursorStack();
989
0
    if( CanInsert() )
990
0
    {
991
0
        SwActContext aActContext(this);
992
0
        StartUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
993
994
0
        if ( !IsCursorInTable() )
995
0
        {
996
0
            if(HasSelection())
997
0
                DelRight();
998
0
            SwFEShell::SplitNode();
999
            // delete the numbered attribute of the last line if the last line is empty
1000
0
            GetDoc()->ClearLineNumAttrs( *GetCursor()->GetPoint() );
1001
0
        }
1002
1003
0
        const SwPageDesc *pDesc = pPageDesc
1004
0
                                ? FindPageDescByName( *pPageDesc, true ) : nullptr;
1005
0
        if( pDesc )
1006
0
        {
1007
0
            SwFormatPageDesc aDesc( pDesc );
1008
0
            aDesc.SetNumOffset( oPgNum );
1009
0
            SetAttrItem( aDesc );
1010
0
        }
1011
0
        else
1012
0
            SetAttrItem( SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK) );
1013
0
        EndUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
1014
0
    }
1015
0
    collectUIInformation(u"BREAK_PAGE"_ustr, u"parameter"_ustr);
1016
0
}
1017
1018
// Insert enclosing characters
1019
// Selections will be overwritten
1020
void SwWrtShell::InsertEnclosingChars(const OUString& sStartStr, const OUString& sEndStr)
1021
0
{
1022
0
    if (!lcl_IsAllowed(this) || !CanInsert())
1023
0
        return;
1024
0
    StartAllAction();
1025
0
    StartUndo();
1026
1027
0
    OUStringBuffer currentText, newText;
1028
0
    bool dotsAdded = false;
1029
0
    const OUString dots = SwResId(STR_LDOTS);
1030
0
    for (SwPaM& rPaM : SwWrtShell::GetCursor()->GetRingContainer())
1031
0
    {
1032
0
        if (*rPaM.GetPoint() == *rPaM.GetMark())
1033
0
            continue;
1034
0
        if (newText.isEmpty())
1035
0
        {
1036
0
            OUString pamText = ShortenString(rPaM.GetText(), nUndoStringLength, dots)
1037
0
                                   .replaceAll("\n", " ");
1038
0
            currentText.append(pamText);
1039
0
            newText.append(sStartStr + pamText + sEndStr);
1040
0
        }
1041
0
        else if (!dotsAdded)
1042
0
        {
1043
0
            dotsAdded = true;
1044
0
            currentText.append(dots);
1045
0
            newText.append(dots);
1046
0
        }
1047
1048
0
        {
1049
0
            SwPaM aLocalPam(rPaM, nullptr);
1050
0
            aLocalPam.Normalize(); // point is at start now
1051
0
            auto& contentOperations = SwViewShell::getIDocumentContentOperations();
1052
1053
            // To copy the formatting of the start of the range, insert the start string in two
1054
            // phases: insert it after the first selected character; and then move it back
1055
0
            SwPosition posStart = *aLocalPam.GetPoint();
1056
0
            aLocalPam.GetPoint()->AdjustContent(+1);
1057
0
            contentOperations.InsertString(aLocalPam, sStartStr);
1058
            // Now aLocalPam's point is *after* the inserted string
1059
0
            SwPaM insertedPaM(*aLocalPam.GetPoint());
1060
0
            insertedPaM.SetMark();
1061
0
            insertedPaM.GetPoint()->AdjustContent(-sStartStr.getLength());
1062
0
            contentOperations.CopyRange(insertedPaM, posStart, SwCopyFlags::CopyAll);
1063
0
            contentOperations.DeleteRange(insertedPaM);
1064
1065
            // No such problems with end string
1066
0
            aLocalPam.Exchange(); // point is at end now
1067
0
            contentOperations.InsertString(aLocalPam, sEndStr);
1068
0
        }
1069
0
        rPaM.Start()->AdjustContent(-sStartStr.getLength()); // now the selection includes insertion
1070
0
    }
1071
1072
0
    SwRewriter aRewriter;
1073
0
    aRewriter.AddRule(UndoArg1, currentText.makeStringAndClear());
1074
0
    aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
1075
0
    aRewriter.AddRule(UndoArg3, newText.makeStringAndClear());
1076
0
    EndUndo(SwUndoId::UI_REPLACE, &aRewriter);
1077
1078
0
    EndAllAction();
1079
0
}
1080
1081
// Insert hard page break;
1082
// Selections will be overwritten
1083
1084
void SwWrtShell::InsertLineBreak(std::optional<SwLineBreakClear> oClear)
1085
0
{
1086
0
    if (!lcl_IsAllowed(this))
1087
0
        return;
1088
1089
0
    ResetCursorStack();
1090
0
    if( CanInsert() )
1091
0
    {
1092
0
        if(HasSelection())
1093
0
            DelRight();
1094
1095
0
        const sal_Unicode cIns = 0x0A;
1096
0
        SwLineBreakClear eClear = SwLineBreakClear::NONE;
1097
0
        if (oClear.has_value())
1098
0
        {
1099
0
            eClear = *oClear;
1100
0
        }
1101
0
        SvxAutoCorrect* pACorr = lcl_IsAutoCorr();
1102
0
        if (pACorr && eClear == SwLineBreakClear::NONE)
1103
0
            AutoCorrect( *pACorr, cIns );
1104
0
        else
1105
0
        {
1106
0
            if (eClear == SwLineBreakClear::NONE)
1107
0
            {
1108
0
                SwWrtShell::Insert(OUString(cIns));
1109
0
            }
1110
0
            else
1111
0
            {
1112
0
                SwFormatLineBreak aLineBreak(eClear);
1113
0
                SetAttrItem(aLineBreak);
1114
0
            }
1115
0
        }
1116
0
    }
1117
0
}
1118
1119
// Insert hard column break;
1120
// Selections will be overwritten
1121
1122
void SwWrtShell::InsertColumnBreak()
1123
0
{
1124
0
    if (!lcl_IsAllowed(this))
1125
0
        return;
1126
1127
0
    SwActContext aActContext(this);
1128
0
    ResetCursorStack();
1129
0
    if( !CanInsert() )
1130
0
        return;
1131
1132
0
    StartUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
1133
1134
0
    if ( !IsCursorInTable() )
1135
0
    {
1136
0
        if(HasSelection())
1137
0
            DelRight();
1138
0
        SwFEShell::SplitNode(false);
1139
0
    }
1140
0
    SetAttrItem(SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
1141
1142
0
    EndUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
1143
0
}
1144
1145
void SwWrtShell::InsertContentControl(SwContentControlType eType)
1146
0
{
1147
0
    if (!lcl_IsAllowed(this))
1148
0
    {
1149
0
        return;
1150
0
    }
1151
1152
0
    ResetCursorStack();
1153
0
    if (!CanInsert())
1154
0
    {
1155
0
        return;
1156
0
    }
1157
1158
0
    auto pContentControl = std::make_shared<SwContentControl>(nullptr);
1159
1160
    // Make Random ID... check if it is unique
1161
    // warning: possible infinite loop if there would be billions of content controls.
1162
0
    SwContentControlManager& pManager = GetDoc()->GetContentControlManager();
1163
0
    size_t nCCCount = pManager.GetCount();
1164
0
    sal_Int32 nIdToCheck;
1165
0
    nIdToCheck
1166
0
        = comphelper::rng::uniform_uint_distribution(1, std::numeric_limits<sal_Int32>::max());
1167
0
    size_t nIdx = 0;
1168
0
    while (nIdx < nCCCount)
1169
0
    {
1170
0
        sal_Int32 nID
1171
0
            = pManager.UnsortedGet(nIdx)->GetContentControl().GetContentControl()->GetId();
1172
0
        if (nID == nIdToCheck)
1173
0
        {
1174
0
            nIdToCheck = comphelper::rng::uniform_uint_distribution(
1175
0
                1, std::numeric_limits<sal_Int32>::max());
1176
0
            nIdx = 0;
1177
0
        }
1178
0
        else
1179
0
            nIdx++;
1180
0
    }
1181
0
    pContentControl->SetId(nIdToCheck);
1182
1183
0
    OUString aPlaceholder;
1184
0
    switch (eType)
1185
0
    {
1186
0
        case SwContentControlType::RICH_TEXT:
1187
0
        case SwContentControlType::PLAIN_TEXT:
1188
0
        {
1189
0
            pContentControl->SetShowingPlaceHolder(true);
1190
0
            if (eType == SwContentControlType::PLAIN_TEXT)
1191
0
            {
1192
0
                pContentControl->SetPlainText(true);
1193
0
            }
1194
0
            if (!HasSelection())
1195
0
            {
1196
0
                aPlaceholder = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER);
1197
0
            }
1198
0
            break;
1199
0
        }
1200
0
        case SwContentControlType::CHECKBOX:
1201
0
        {
1202
0
            pContentControl->SetCheckbox(true);
1203
0
            pContentControl->SetCheckedState(SwContentControl::CHECKED_STATE);
1204
0
            pContentControl->SetUncheckedState(SwContentControl::UNCHECKED_STATE);
1205
0
            aPlaceholder = u"\u2610"_ustr;
1206
0
            break;
1207
0
        }
1208
0
        case SwContentControlType::COMBO_BOX:
1209
0
        case SwContentControlType::DROP_DOWN_LIST:
1210
0
        {
1211
0
            if (eType == SwContentControlType::COMBO_BOX)
1212
0
            {
1213
0
                pContentControl->SetComboBox(true);
1214
0
            }
1215
0
            else if (eType == SwContentControlType::DROP_DOWN_LIST)
1216
0
            {
1217
0
                pContentControl->SetDropDown(true);
1218
0
            }
1219
1220
0
            pContentControl->SetShowingPlaceHolder(true);
1221
0
            if (!HasSelection())
1222
0
            {
1223
0
                aPlaceholder = SwResId(STR_DROPDOWN_CONTENT_CONTROL_PLACEHOLDER);
1224
0
            }
1225
0
            SwContentControlListItem aListItem;
1226
0
            aListItem.m_aValue = aPlaceholder;
1227
0
            pContentControl->SetListItems({ std::move(aListItem) });
1228
0
            break;
1229
0
        }
1230
0
        case SwContentControlType::PICTURE:
1231
0
        {
1232
            // Set up the picture content control.
1233
0
            pContentControl->SetShowingPlaceHolder(true);
1234
0
            pContentControl->SetPicture(true);
1235
1236
            // Create the placeholder bitmap.
1237
0
            Bitmap aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
1238
0
            Color aColor = SvtOptionsDrawinglayer::getHilightColor();
1239
0
            aColor.IncreaseLuminance(255 * 0.75);
1240
0
            aBitmap.Erase(aColor);
1241
0
            SwRewriter aRewriter;
1242
0
            aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME));
1243
0
            StartUndo(SwUndoId::INSERT, &aRewriter);
1244
0
            LockPaint(LockPaintReason::InsertGraphic);
1245
0
            StartAction();
1246
0
            InsertGraphic(OUString(), OUString(), aBitmap, nullptr, RndStdIds::FLY_AS_CHAR);
1247
1248
            // Set properties on the bitmap.
1249
0
            SfxItemSet aSet(SfxItemSet::makeFixedSfxItemSet<RES_FRM_SIZE, RES_FRM_SIZE>(GetDoc()->GetAttrPool()));
1250
0
            GetFlyFrameAttr(aSet);
1251
0
            SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000);
1252
0
            aSet.Put(aSize);
1253
0
            SetFlyFrameAttr(aSet);
1254
0
            SwFrameFormat* pFrameFormat = GetFlyFrameFormat();
1255
0
            EndAction();
1256
0
            UnlockPaint();
1257
0
            EndUndo();
1258
1259
            // Go after the anchor position.
1260
0
            UnSelectFrame();
1261
0
            LeaveSelFrameMode();
1262
0
            {
1263
0
                SwCursor* pCursor = getShellCursor(true);
1264
0
                pCursor->DeleteMark();
1265
0
                const SwFormatAnchor& rFormatAnchor = pFrameFormat->GetAnchor();
1266
0
                pCursor->GetPoint()->Assign( *rFormatAnchor.GetAnchorContentNode(), rFormatAnchor.GetAnchorContentOffset() + 1);
1267
0
            }
1268
1269
            // Select before the anchor position.
1270
0
            Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1271
0
            break;
1272
0
        }
1273
0
        case SwContentControlType::DATE:
1274
0
        {
1275
0
            pContentControl->SetShowingPlaceHolder(true);
1276
0
            pContentControl->SetDate(true);
1277
0
            SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
1278
0
            sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
1279
0
            const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);
1280
0
            pContentControl->SetDateFormat(pFormat->GetFormatstring());
1281
0
            pContentControl->SetDateLanguage(LanguageTag(pFormat->GetLanguage()).getBcp47());
1282
0
            if (!HasSelection())
1283
0
            {
1284
0
                aPlaceholder = SwResId(STR_DATE_CONTENT_CONTROL_PLACEHOLDER);
1285
0
            }
1286
0
            break;
1287
0
        }
1288
0
    }
1289
0
    if (aPlaceholder.getLength())
1290
0
    {
1291
0
        Insert(aPlaceholder);
1292
0
        Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(),
1293
0
                /*bBasicCall=*/false);
1294
0
    }
1295
1296
0
    const RedlineFlags oldRedlineFlags = getIDocumentRedlineAccess().GetRedlineFlags();
1297
0
    getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::Ignore);
1298
0
    SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL);
1299
0
    SetAttrItem(aContentControl);
1300
0
    getIDocumentRedlineAccess().SetRedlineFlags(oldRedlineFlags);
1301
0
}
1302
1303
// Insert footnote
1304
// rStr - optional footnote mark
1305
1306
void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit )
1307
0
{
1308
0
    ResetCursorStack();
1309
0
    if( !CanInsert() )
1310
0
        return;
1311
1312
0
    if(HasSelection())
1313
0
    {
1314
        //collapse cursor to the end
1315
0
        if(!IsCursorPtAtEnd())
1316
0
            SwapPam();
1317
0
        ClearMark();
1318
0
    }
1319
0
    SwPosition aPos = *GetCursor()->GetPoint();
1320
0
    SwFormatFootnote aFootNote( bEndNote );
1321
0
    if(!rStr.isEmpty())
1322
0
        aFootNote.SetNumStr( rStr );
1323
1324
0
    SetAttrItem(aFootNote);
1325
1326
0
    if( bEdit )
1327
0
    {
1328
        // For editing the footnote text.
1329
0
        Left(SwCursorSkipMode::Chars, false, 1, false );
1330
0
        GotoFootnoteText();
1331
0
    }
1332
0
    m_aNavigationMgr.addEntry(aPos);
1333
0
}
1334
1335
// tdf#141634
1336
static bool lcl_FoldedOutlineNodeEndOfParaSplit(SwWrtShell* pThis)
1337
0
{
1338
0
    SwTextNode* pTextNode = pThis->GetCursor()->GetPointNode().GetTextNode();
1339
0
    const SwNodes& rNodes = pThis->GetNodes();
1340
0
    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
1341
0
    SwOutlineNodes::size_type nPos;
1342
1343
0
    if (!pTextNode || pTextNode->GetAttrOutlineContentVisible()
1344
0
        || !rOutlineNodes.Seek_Entry(pTextNode, &nPos))
1345
0
        return false;
1346
1347
0
    SwNode* pSttNd = rOutlineNodes[nPos];
1348
1349
    // determine end node of folded outline content
1350
0
    SwNode* pEndNd = &rNodes.GetEndOfContent();
1351
0
    if (rOutlineNodes.size() > nPos + 1)
1352
0
        pEndNd = rOutlineNodes[nPos + 1];
1353
1354
0
    if (pThis->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
1355
0
    {
1356
        // get the next outline node after the folded outline content (iPos)
1357
        // it is the next outline node with the same level or less
1358
0
        int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
1359
0
        SwOutlineNodes::size_type iPos = nPos;
1360
0
        while (++iPos < rOutlineNodes.size()
1361
0
               && rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel)
1362
0
            ;
1363
1364
        // get the correct end node
1365
        // the outline node may be in frames, headers, footers special section of doc model
1366
0
        SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
1367
0
        while (pStartOfSectionNodeSttNd->StartOfSectionNode()
1368
0
               != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
1369
0
        {
1370
0
            pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
1371
0
        }
1372
0
        pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
1373
1374
0
        if (iPos < rOutlineNodes.size())
1375
0
        {
1376
0
            SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
1377
0
            while (pStartOfSectionNode->StartOfSectionNode()
1378
0
                   != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
1379
0
            {
1380
0
                pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
1381
0
            }
1382
0
            if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
1383
0
                pEndNd = rOutlineNodes[iPos];
1384
0
        }
1385
0
    }
1386
1387
    // table, text box, header, footer
1388
0
    if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
1389
0
    {
1390
        // insert before section end node
1391
0
        if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
1392
0
        {
1393
0
            SwNodeIndex aIdx(*pSttNd->EndOfSectionNode());
1394
0
            while (aIdx.GetNode().IsEndNode())
1395
0
                --aIdx;
1396
0
            ++aIdx;
1397
0
            pEndNd = &aIdx.GetNode();
1398
0
        }
1399
0
    }
1400
    // if pSttNd isn't in table but pEndNd is then insert after table
1401
0
    else if (pEndNd->GetTableBox())
1402
0
    {
1403
0
        pEndNd = pEndNd->FindTableNode();
1404
0
        SwNodeIndex aIdx(*pEndNd, -1);
1405
        // account for nested tables
1406
0
        while (aIdx.GetNode().GetTableBox())
1407
0
        {
1408
0
            pEndNd = aIdx.GetNode().FindTableNode();
1409
0
            aIdx.Assign(*pEndNd, -1);
1410
0
        }
1411
0
        aIdx.Assign(*pEndNd->EndOfSectionNode(), +1);
1412
0
        pEndNd = &aIdx.GetNode();
1413
0
    }
1414
    // end node determined
1415
1416
    // now insert the new outline node
1417
0
    SwDoc* pDoc = pThis->GetDoc();
1418
1419
    // insert at end of tablebox doesn't work correct without
1420
0
    MakeAllOutlineContentTemporarilyVisible a(pDoc);
1421
1422
0
    SwTextNode* pNd = pDoc->GetNodes().MakeTextNode(*pEndNd, pTextNode->GetTextColl(), true);
1423
1424
    // if the outline level is not set in style then it is set in direct formatting
1425
0
    if (!pTextNode->GetTextColl()->GetAttrOutlineLevel())
1426
0
        pNd->SetAttrOutlineLevel(pTextNode->GetAttrOutlineLevel());
1427
1428
0
    (void)rOutlineNodes.Seek_Entry(pNd, &nPos);
1429
0
    pThis->GotoOutline(nPos);
1430
1431
0
    if (pDoc->GetIDocumentUndoRedo().DoesUndo())
1432
0
    {
1433
0
        pDoc->GetIDocumentUndoRedo().ClearRedo();
1434
0
        pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsert>(*pNd));
1435
0
        pDoc->GetIDocumentUndoRedo().AppendUndo(
1436
0
            std::make_unique<SwUndoFormatColl>(SwPaM(*pNd), pNd->GetTextColl(), true, true));
1437
0
        if (!pTextNode->GetTextColl()->GetAttrOutlineLevel())
1438
0
            pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttr>(
1439
0
                SwPaM(*pNd),
1440
0
                SfxUInt16Item(RES_PARATR_OUTLINELEVEL, pTextNode->GetAttrOutlineLevel()),
1441
0
                SetAttrMode::DEFAULT));
1442
0
    }
1443
1444
0
    pThis->SetModified();
1445
0
    return true;
1446
0
}
1447
1448
// SplitNode; also, because
1449
//                  - of deleting selected content;
1450
//                  - of reset of the Cursorstack if necessary.
1451
1452
void SwWrtShell::SplitNode( bool bAutoFormat )
1453
0
{
1454
0
    ResetCursorStack();
1455
0
    if( !CanInsert() )
1456
0
        return;
1457
1458
0
    SwActContext aActContext(this);
1459
1460
0
    m_rView.GetEditWin().FlushInBuffer();
1461
0
    StartUndo(SwUndoId::SPLITNODE);
1462
1463
0
    bool bHasSel = HasSelection();
1464
0
    if (bHasSel)
1465
0
        DelRight();
1466
1467
0
    bool bHandled = false;
1468
0
    if (GetViewOptions()->IsShowOutlineContentVisibilityButton() && IsEndPara())
1469
0
        bHandled = lcl_FoldedOutlineNodeEndOfParaSplit(this);
1470
1471
0
    if (!bHandled)
1472
0
        SwFEShell::SplitNode();
1473
1474
0
    EndUndo(SwUndoId::SPLITNODE);
1475
1476
    // run autoformat after "New Paragraph" undo, so it can be undone separately from the newline
1477
0
    if (!bHandled && bAutoFormat)
1478
0
        AutoFormatBySplitNode();
1479
0
}
1480
1481
// Turn on numbering
1482
// Parameter:   Optional specification of a name for the named list;
1483
//              this indicates a position if it is possible to convert them
1484
//              into a number and less than nMaxRules.
1485
1486
// To test the CharFormats at the numbering
1487
// external void SetNumChrFormat( SwWrtShell*, SwNumRules& );
1488
1489
// -> #i40041#
1490
// Preconditions (as far as OD has figured out):
1491
// - <SwEditShell::HasNumber()> is false, if <bNum> is true
1492
// - <SwEditShell::HasBullet()> is false, if <bNum> is false
1493
// Behavior of method is determined by the current situation at the current
1494
// cursor position in the document.
1495
void SwWrtShell::NumOrBulletOn(bool bNum)
1496
0
{
1497
0
    StartUndo(SwUndoId::NUMORNONUM);
1498
1499
0
    const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
1500
1501
    // - activate outline rule respectively turning on outline rule for
1502
    //   current text node. But, only for turning on a numbering (<bNum> == true).
1503
    // - overwrite found numbering rule at current cursor position, if
1504
    //   no numbering rule can be retrieved from the paragraph style.
1505
0
    bool bContinueFoundNumRule( false );
1506
0
    bool bActivateOutlineRule( false );
1507
0
    int nActivateOutlineLvl( MAXLEVEL );    // only relevant, if <bActivateOutlineRule> == true
1508
0
    SwTextFormatColl * pColl = GetCurTextFormatColl();
1509
0
    if ( pColl )
1510
0
    {
1511
        // retrieve numbering rule at paragraph
1512
        // style, which is found at current cursor position in the document.
1513
0
        SwNumRule* pCollRule = mxDoc->FindNumRulePtr(pColl->GetNumRule().GetValue());
1514
        // #125993# - The outline numbering rule isn't allowed
1515
        // to be derived from a parent paragraph style to a derived one.
1516
        // Thus check, if the found outline numbering rule is directly
1517
        // set at the paragraph style <pColl>. If not, set <pCollRule> to NULL
1518
0
        if ( pCollRule && pCollRule == GetDoc()->GetOutlineNumRule() )
1519
0
        {
1520
0
            const SwNumRule* pDirectCollRule =
1521
0
                    mxDoc->FindNumRulePtr(pColl->GetNumRule( false ).GetValue());
1522
0
            if ( !pDirectCollRule )
1523
0
            {
1524
0
                pCollRule = nullptr;
1525
0
            }
1526
0
        }
1527
1528
0
        if ( !pCollRule )
1529
0
        {
1530
0
            pNumRule = pCollRule;
1531
0
        }
1532
        // no activation or continuation of outline numbering in Writer/Web document
1533
0
        else if ( bNum &&
1534
0
                  !dynamic_cast<SwWebDocShell*>(GetDoc()->GetDocShell()) &&
1535
0
                  pCollRule == GetDoc()->GetOutlineNumRule() )
1536
0
        {
1537
0
            if ( pNumRule == pCollRule )
1538
0
            {
1539
                // check, if text node at current cursor positioned is counted.
1540
                // If not, let it been counted. Then it has to be checked,
1541
                // of the outline numbering has to be activated or continued.
1542
0
                SwTextNode const*const pTextNode = sw::GetParaPropsNode(
1543
0
                        *GetLayout(), GetCursor()->GetPoint()->GetNode());
1544
0
                if ( pTextNode && !pTextNode->IsCountedInList() )
1545
0
                {
1546
                    // check, if numbering of the outline level of the paragraph
1547
                    // style is active. If not, activate this outline level.
1548
0
                    nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1549
0
                    OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
1550
0
                            "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
1551
0
                    if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
1552
0
                         pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1553
0
                            == SVX_NUM_NUMBER_NONE )
1554
0
                    {
1555
                        // activate outline numbering
1556
0
                        bActivateOutlineRule = true;
1557
0
                    }
1558
0
                    else
1559
0
                    {
1560
                        // turning on outline numbering at current cursor position
1561
0
                        bContinueFoundNumRule = true;
1562
0
                    }
1563
0
                }
1564
0
                else
1565
0
                {
1566
                    // #i101234#
1567
                    // activate outline numbering, because from the precondition
1568
                    // it's known, that <SwEdit::HasNumber()> == false
1569
0
                    bActivateOutlineRule = true;
1570
0
                    nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1571
0
                }
1572
0
            }
1573
0
            else if ( !pNumRule )
1574
0
            {
1575
                // #i101234#
1576
                // Check, if corresponding list level of the outline numbering
1577
                // has already a numbering format set.
1578
0
                nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1579
0
                if ( pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1580
0
                                == SVX_NUM_NUMBER_NONE )
1581
0
                {
1582
                    // activate outline numbering, because from the precondition
1583
                    // it's known, that <SwEdit::HasNumber()> == false
1584
0
                    bActivateOutlineRule = true;
1585
0
                }
1586
0
                else
1587
0
                {
1588
                    // turning on outline numbering at current cursor position
1589
0
                    bContinueFoundNumRule = true;
1590
0
                }
1591
0
            }
1592
0
            else
1593
0
            {
1594
                // check, if numbering of the outline level of the paragraph
1595
                // style is active. If not, activate this outline level.
1596
0
                nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1597
0
                OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
1598
0
                        "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
1599
0
                if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
1600
0
                     pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1601
0
                        == SVX_NUM_NUMBER_NONE )
1602
0
                {
1603
                    // activate outline numbering
1604
0
                    bActivateOutlineRule = true;
1605
0
                }
1606
0
                else
1607
0
                {
1608
                    // turning on outline numbering at current cursor position
1609
0
                    bContinueFoundNumRule = true;
1610
0
                }
1611
0
            }
1612
0
            pNumRule = pCollRule;
1613
0
        }
1614
0
    }
1615
1616
    // Only automatic numbering/bullet rules should be changed.
1617
    // Note: The outline numbering rule is also an automatic one. It's only
1618
    //       changed, if it has to be activated.
1619
0
    if ( pNumRule )
1620
0
    {
1621
0
        if ( !pNumRule->IsAutoRule() )
1622
0
        {
1623
0
            pNumRule = nullptr;
1624
0
        }
1625
0
        else if ( pNumRule == GetDoc()->GetOutlineNumRule() &&
1626
0
                  !bActivateOutlineRule && !bContinueFoundNumRule )
1627
0
        {
1628
0
            pNumRule = nullptr;
1629
0
        }
1630
0
    }
1631
1632
    // Search for a previous numbering/bullet rule to continue it.
1633
0
    OUString sContinuedListId;
1634
0
    if ( !pNumRule )
1635
0
    {
1636
0
        pNumRule = GetDoc()->SearchNumRule( *GetCursor()->GetPoint(),
1637
0
                                            false, bNum, false, 0,
1638
0
                                            sContinuedListId, GetLayout() );
1639
0
        bContinueFoundNumRule = pNumRule != nullptr;
1640
0
    }
1641
1642
0
    if (pNumRule)
1643
0
    {
1644
0
        SwNumRule aNumRule(*pNumRule);
1645
1646
        // do not change found numbering/bullet rule, if it should only be continued.
1647
0
        if ( !bContinueFoundNumRule )
1648
0
        {
1649
0
            SwTextNode const*const pTextNode = sw::GetParaPropsNode(
1650
0
                    *GetLayout(), GetCursor()->GetPoint()->GetNode());
1651
1652
0
            if (pTextNode)
1653
0
            {
1654
                // use above retrieve outline level, if outline numbering has to be activated.
1655
0
                int nLevel = bActivateOutlineRule
1656
0
                              ? nActivateOutlineLvl
1657
0
                              : pTextNode->GetActualListLevel();
1658
1659
0
                if (nLevel < 0)
1660
0
                    nLevel = 0;
1661
1662
0
                if (nLevel >= MAXLEVEL)
1663
0
                    nLevel = MAXLEVEL - 1;
1664
1665
0
                SwNumFormat aFormat(aNumRule.Get(o3tl::narrowing<sal_uInt16>(nLevel)));
1666
1667
0
                if (bNum)
1668
0
                    aFormat.SetNumberingType(SVX_NUM_ARABIC);
1669
0
                else
1670
0
                {
1671
                    // #i63395# Only apply user defined default bullet font
1672
0
                    if ( numfunc::IsDefBulletFontUserDefined() )
1673
0
                    {
1674
0
                        const vcl::Font* pFnt = &numfunc::GetDefBulletFont();
1675
0
                        aFormat.SetBulletFont( pFnt );
1676
0
                    }
1677
0
                    aFormat.SetBulletChar( numfunc::GetBulletChar(static_cast<sal_uInt8>(nLevel)));
1678
0
                    aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1679
                    // #i93908# clear suffix for bullet lists
1680
0
                    aFormat.SetListFormat(u""_ustr, u""_ustr, nLevel);
1681
0
                }
1682
0
                aNumRule.Set(o3tl::narrowing<sal_uInt16>(nLevel), aFormat);
1683
0
            }
1684
0
        }
1685
1686
        // reset indent attribute on applying list style
1687
0
        SetCurNumRule( aNumRule, false, sContinuedListId, true );
1688
0
    }
1689
0
    else
1690
0
    {
1691
        // #i95907#
1692
0
        const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
1693
0
                                    numfunc::GetDefaultPositionAndSpaceMode() );
1694
0
        SwNumRule aNumRule( GetUniqueNumRuleName(), ePosAndSpaceMode );
1695
        // Append the character template at the numbering.
1696
0
        SwCharFormat* pChrFormat;
1697
0
        SwDocShell* pDocSh = GetView().GetDocShell();
1698
1699
0
        if (bNum)
1700
0
        {
1701
0
            pChrFormat = GetCharFormatFromPool( SwPoolFormatId::CHR_NUM_LEVEL );
1702
0
        }
1703
0
        else
1704
0
        {
1705
0
            pChrFormat = GetCharFormatFromPool( SwPoolFormatId::CHR_BULLET_LEVEL );
1706
0
        }
1707
1708
0
        const SwTextNode *const pTextNode = sw::GetParaPropsNode(*GetLayout(),
1709
0
                GetCursor()->GetPoint()->GetNode());
1710
0
        const SwTwips nWidthOfTabs = pTextNode
1711
0
                                     ? pTextNode->GetWidthOfLeadingTabs()
1712
0
                                     : 0;
1713
0
        GetDoc()->getIDocumentContentOperations().RemoveLeadingWhiteSpace(*GetCursor());
1714
1715
0
        const bool bHtml = dynamic_cast<SwWebDocShell*>( pDocSh ) !=  nullptr;
1716
0
        const bool bRightToLeft = IsInRightToLeftText();
1717
0
        for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
1718
0
        {
1719
0
            SwNumFormat aFormat( aNumRule.Get( nLvl ) );
1720
0
            aFormat.SetCharFormat( pChrFormat );
1721
1722
0
            if (! bNum)
1723
0
            {
1724
0
                static constexpr OUString sDefaultBulletSymbol = u"•"_ustr;
1725
0
                static constexpr OUString sDefaultBulletSymbolFont = u"OpenSymbol"_ustr;
1726
0
                uno::Sequence<OUString> aBulletSymbols(
1727
0
                    officecfg::Office::Common::BulletsNumbering::DefaultListBullets::get());
1728
0
                uno::Sequence<OUString> aBulletSymbolsFonts(
1729
0
                    officecfg::Office::Common::BulletsNumbering::DefaultListBulletsFonts::get());
1730
0
                if (!aBulletSymbols.hasElements())
1731
0
                {
1732
0
                    SAL_WARN("sw", "empty DefaultListBullets config, adding a default single bullet");
1733
                    // Add a single element even if user cleared the list in the config
1734
0
                    aBulletSymbols.realloc(1);
1735
0
                    aBulletSymbols.getArray()[0] = sDefaultBulletSymbol;
1736
0
                }
1737
0
                const sal_Int32 nBulletSymbolIndex = nLvl % aBulletSymbols.getLength();
1738
0
                aFormat.SetBulletChar(aBulletSymbols[nBulletSymbolIndex].toChar());
1739
0
                vcl::Font aFont;
1740
                // Symbol and font correspond to each other, use same index
1741
0
                if (nBulletSymbolIndex < aBulletSymbolsFonts.getLength())
1742
0
                    aFont.SetFamilyName(aBulletSymbolsFonts[nBulletSymbolIndex]);
1743
0
                else
1744
0
                    aFont.SetFamilyName(sDefaultBulletSymbolFont);
1745
0
                aFormat.SetBulletFont(&aFont);
1746
0
                aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1747
                // #i93908# clear suffix for bullet lists
1748
0
                aFormat.SetListFormat(u""_ustr, u""_ustr, nLvl);
1749
0
            }
1750
1751
            // #i95907#
1752
0
            if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1753
0
            {
1754
0
                if(bHtml && nLvl)
1755
0
                {
1756
                    // 1/2" for HTML
1757
0
                    aFormat.SetAbsLSpace(nLvl * 720);
1758
0
                }
1759
0
                else if ( nWidthOfTabs > 0 )
1760
0
                {
1761
0
                    aFormat.SetAbsLSpace(nWidthOfTabs + nLvl * 720);
1762
0
                }
1763
0
            }
1764
1765
            // #i38904#  Default alignment for
1766
            // numbering/bullet should be rtl in rtl paragraph:
1767
0
            if ( bRightToLeft )
1768
0
            {
1769
0
                aFormat.SetNumAdjust( SvxAdjust::Right );
1770
0
            }
1771
1772
0
            aNumRule.Set( nLvl, aFormat );
1773
0
        }
1774
1775
        // #i95907#
1776
0
        if ( pTextNode &&
1777
0
             ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
1778
0
        {
1779
1780
0
            const SwTwips nTextNodeIndent = pTextNode->GetAdditionalIndentForStartingNewList();
1781
0
            if ( ( nTextNodeIndent + nWidthOfTabs ) != 0 )
1782
0
            {
1783
                // #i111172#/fdo#85666
1784
                // If text node is already inside a list, assure that the indents
1785
                // are the same. Thus, adjust the indent change value by subtracting
1786
                // indents of to be applied list style.
1787
0
                SwTwips nIndentChange = nTextNodeIndent + nWidthOfTabs;
1788
0
                if ( pTextNode->GetNumRule() )
1789
0
                {
1790
0
                    int nLevel = pTextNode->GetActualListLevel();
1791
1792
0
                    if (nLevel < 0)
1793
0
                        nLevel = 0;
1794
1795
0
                    if (nLevel >= MAXLEVEL)
1796
0
                        nLevel = MAXLEVEL - 1;
1797
1798
0
                    const SwNumFormat& aFormat( aNumRule.Get( nLevel ) );
1799
0
                    if ( aFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1800
0
                    {
1801
0
                        nIndentChange -= aFormat.GetIndentAt() + aFormat.GetFirstLineIndent();
1802
0
                    }
1803
0
                }
1804
0
                aNumRule.ChangeIndent( nIndentChange );
1805
0
            }
1806
0
        }
1807
        // reset indent attribute on applying list style
1808
        // start new list
1809
0
        SetCurNumRule( aNumRule, true, OUString(), true );
1810
0
    }
1811
1812
0
    EndUndo(SwUndoId::NUMORNONUM);
1813
0
}
1814
// <- #i40041#
1815
1816
void SwWrtShell::NumOn()
1817
0
{
1818
0
    NumOrBulletOn(true);
1819
0
}
1820
1821
void SwWrtShell::NumOrBulletOff()
1822
0
{
1823
0
    const SwNumRule * pCurNumRule = GetNumRuleAtCurrCursorPos();
1824
1825
0
    if (!pCurNumRule)
1826
0
        return;
1827
1828
0
    DelNumRules();
1829
1830
    // #126346# - Cursor can not be anymore in front of
1831
    // a label, because numbering/bullet is switched off.
1832
0
    SetInFrontOfLabel( false );
1833
0
}
1834
// <- #i29560#
1835
1836
// Request Default-Bulletlist
1837
1838
void SwWrtShell::BulletOn()
1839
0
{
1840
0
    NumOrBulletOn(false);
1841
0
}
1842
1843
SelectionType SwWrtShell::GetSelectionType() const
1844
16.1k
{
1845
    // ContentType cannot be determined within a Start-/EndAction.
1846
    // Because there is no invalid value TEXT will be returned.
1847
    // The value does not matter, it may be updated in EndAction anyway.
1848
1849
16.1k
    if (ActionPend())
1850
0
        return IsSelFrameMode() ? SelectionType::Frame : SelectionType::Text;
1851
1852
16.1k
    SwView &_rView = const_cast<SwView&>(GetView());
1853
16.1k
    if (_rView.GetPostItMgr() && _rView.GetPostItMgr()->HasActiveSidebarWin() )
1854
0
        return SelectionType::PostIt;
1855
1856
    // Inserting a frame is not a DrawMode
1857
16.1k
    SelectionType nCnt;
1858
16.1k
    if ( !_rView.GetEditWin().IsFrameAction() &&
1859
16.1k
        (GetSelectedObjCount() || (_rView.IsDrawMode() && !IsFrameSelected()) ))
1860
0
    {
1861
0
        if (GetDrawView()->IsTextEdit())
1862
0
            nCnt = SelectionType::DrawObjectEditMode;
1863
0
        else
1864
0
        {
1865
0
            if (GetView().IsFormMode()) // Only Form selected
1866
0
                nCnt = SelectionType::DbForm;
1867
0
            else
1868
0
                nCnt = SelectionType::DrawObject;            // Any draw object
1869
1870
0
            if (_rView.IsBezierEditMode())
1871
0
                nCnt |= SelectionType::Ornament;
1872
0
            else if( GetDrawView()->GetContext() == SdrViewContext::Media )
1873
0
                nCnt |= SelectionType::Media;
1874
1875
0
            if (svx::checkForSelectedCustomShapes( GetDrawView(), true /* bOnlyExtruded */ ))
1876
0
            {
1877
0
                nCnt |= SelectionType::ExtrudedCustomShape;
1878
0
            }
1879
1880
0
            if (svx::checkForSelectedFontWork( GetDrawView() ))
1881
0
            {
1882
0
                nCnt |= SelectionType::FontWork;
1883
0
            }
1884
0
        }
1885
1886
0
        return nCnt;
1887
0
    }
1888
1889
16.1k
    nCnt = static_cast<SelectionType>(GetCntType());
1890
1891
16.1k
    if ( IsFrameSelected() )
1892
0
    {
1893
0
        if (_rView.IsDrawMode())
1894
0
            _rView.LeaveDrawCreate();   // clean up (Bug #45639)
1895
0
        if ( !(nCnt & (SelectionType::Graphic | SelectionType::Ole)) )
1896
0
            return SelectionType::Frame;
1897
0
    }
1898
1899
16.1k
    if ( IsCursorInTable() )
1900
48
        nCnt |= SelectionType::Table;
1901
1902
16.1k
    if ( IsTableMode() )
1903
0
    {
1904
0
        nCnt |= SelectionType::Table | SelectionType::TableCell;
1905
0
        SwTable::SearchType eTableSel = GetEnhancedTableSelection();
1906
0
        if ( eTableSel == SwTable::SEARCH_ROW )
1907
0
            nCnt |= SelectionType::TableRow;
1908
0
        else if ( eTableSel == SwTable::SEARCH_COL )
1909
0
            nCnt |= SelectionType::TableCol;
1910
0
    }
1911
1912
    // Do not pop up numbering toolbar, if the text node has a numbering of type SVX_NUM_NUMBER_NONE.
1913
16.1k
    const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
1914
16.1k
    if ( pNumRule )
1915
1.14k
    {
1916
1.14k
        const SwTextNode* pTextNd =
1917
1.14k
            sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->GetNode());
1918
1919
1.14k
        if ( pTextNd && pTextNd->IsInList() )
1920
1.14k
        {
1921
1.14k
            int nLevel = pTextNd->GetActualListLevel();
1922
1923
1.14k
            if (nLevel < 0)
1924
0
                nLevel = 0;
1925
1926
1.14k
            if (nLevel >= MAXLEVEL)
1927
0
                nLevel = MAXLEVEL - 1;
1928
1929
1.14k
            const SwNumFormat& rFormat = pNumRule->Get(nLevel);
1930
1.14k
            if ( SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType() )
1931
27
                nCnt |= SelectionType::NumberList;
1932
1.14k
        }
1933
1.14k
    }
1934
1935
16.1k
    return nCnt;
1936
16.1k
}
1937
1938
bool SwWrtShell::IsSectionEditableInReadonly() const
1939
0
{
1940
0
    bool bIsEditableSect = false;
1941
0
    SwTextNode* pTextNode = GetCursor()->GetPointNode().GetTextNode();
1942
0
    if (pTextNode)
1943
0
    {
1944
0
        if (SwSectionNode* pSectNode = pTextNode->FindSectionNode())
1945
0
        {
1946
0
            bIsEditableSect = pSectNode->GetSection().IsEditInReadonly();
1947
0
        }
1948
0
    }
1949
1950
0
    return bIsEditableSect;
1951
0
}
1952
1953
// Find the text collection with the name rCollname
1954
// Returns:   Pointer at the collection or 0, if no
1955
//            text collection with this name exists, or
1956
//            this is a default template.
1957
1958
SwTextFormatColl *SwWrtShell::GetParaStyle(const UIName &rCollName, GetStyle eCreate )
1959
0
{
1960
0
    SwTextFormatColl* pColl = FindTextFormatCollByName( rCollName );
1961
0
    if( !pColl && GETSTYLE_NOCREATE != eCreate )
1962
0
    {
1963
0
        SwPoolFormatId nId = SwStyleNameMapper::GetPoolIdFromUIName( rCollName, SwGetPoolIdFromName::TxtColl );
1964
0
        if( SwPoolFormatId::UNKNOWN != nId || GETSTYLE_CREATEANY == eCreate )
1965
0
            pColl = GetTextCollFromPool( nId );
1966
0
    }
1967
0
    return pColl;
1968
0
}
1969
1970
// Find the text collection with the name rCollname
1971
// Returns:   Pointer at the collection or 0, if no
1972
//            character template with this name exists, or
1973
//            this is a default template or template is automatic.
1974
1975
SwCharFormat *SwWrtShell::GetCharStyle(const UIName &rFormatName, GetStyle eCreate )
1976
0
{
1977
0
    SwCharFormat* pFormat = FindCharFormatByName( rFormatName );
1978
0
    if( !pFormat && GETSTYLE_NOCREATE != eCreate )
1979
0
    {
1980
0
        SwPoolFormatId nId = SwStyleNameMapper::GetPoolIdFromUIName( rFormatName, SwGetPoolIdFromName::ChrFmt );
1981
0
        if( SwPoolFormatId::UNKNOWN != nId || GETSTYLE_CREATEANY == eCreate )
1982
0
            pFormat = static_cast<SwCharFormat*>(GetFormatFromPool( nId ));
1983
0
    }
1984
0
    return pFormat;
1985
0
}
1986
1987
// Find the table format with the name rFormatname
1988
// Returns:   Pointer at the collection or 0, if no
1989
//            frame format with this name exists or
1990
//            this is a default format or the format is automatic.
1991
1992
SwFrameFormat *SwWrtShell::GetTableStyle(const UIName& rFormatName)
1993
0
{
1994
0
    for( size_t i = GetTableFrameFormatCount(); i; )
1995
0
    {
1996
0
        SwFrameFormat *pFormat = &GetTableFrameFormat( --i );
1997
0
        if( !pFormat->IsDefault() &&
1998
0
            pFormat->GetName() == rFormatName && IsUsed( *pFormat ) )
1999
0
            return pFormat;
2000
0
    }
2001
0
    return nullptr;
2002
0
}
2003
2004
900
void SwWrtShell::addCurrentPosition() {
2005
900
    SwPaM* pPaM = GetCursor();
2006
900
    m_aNavigationMgr.addEntry(*pPaM->GetPoint());
2007
900
}
2008
2009
// Applying templates
2010
2011
void SwWrtShell::SetPageStyle(const UIName &rCollName)
2012
0
{
2013
0
    if( !SwCursorShell::HasSelection() && !IsSelFrameMode() && !GetSelectedObjCount() )
2014
0
    {
2015
0
        SwPageDesc* pDesc = FindPageDescByName( rCollName, true );
2016
0
        if( pDesc )
2017
0
            ChgCurPageDesc( *pDesc );
2018
0
    }
2019
0
}
2020
2021
// Access templates
2022
2023
UIName const & SwWrtShell::GetCurPageStyle() const
2024
0
{
2025
0
    return GetPageDesc(GetCurPageDesc( false/*bCalcFrame*/ )).GetName();
2026
0
}
2027
2028
// Change the current template referring to the existing change.
2029
2030
void SwWrtShell::QuickUpdateStyle()
2031
0
{
2032
0
    SwTextFormatColl *pColl = GetCurTextFormatColl();
2033
2034
    // Default cannot be changed
2035
0
    if(pColl && !pColl->IsDefault())
2036
0
    {
2037
0
        FillByEx(pColl);
2038
            // Also apply the template to remove hard attribute assignment.
2039
0
        SetTextFormatColl(pColl);
2040
0
    }
2041
0
}
2042
2043
void SwWrtShell::AutoUpdatePara(SwTextFormatColl* pColl, const SfxItemSet& rStyleSet, SwPaM* pPaM )
2044
0
{
2045
0
    SwPaM* pCursor = pPaM ? pPaM : GetCursor( );
2046
0
    SfxItemSet aCoreSet(SfxItemSet::makeFixedSfxItemSet<
2047
0
            RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2048
0
            RES_PARATR_BEGIN, RES_PARATR_END - 1,
2049
0
            RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
2050
0
            SID_ATTR_TABSTOP_DEFAULTS,SID_ATTR_TABSTOP_OFFSET,
2051
0
            SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
2052
0
            SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
2053
0
            SID_ATTR_PARA_PAGENUM, SID_ATTR_PARA_PAGENUM>( GetAttrPool() ));
2054
0
    GetPaMAttr( pCursor, aCoreSet );
2055
0
    bool bReset = false;
2056
2057
    // ITEM: SfxItemIter and removing SfxPoolItems:
2058
0
    std::vector<sal_uInt16> aDeleteWhichIDs;
2059
2060
0
    for (SfxItemIter aIter(aCoreSet); !aIter.IsAtEnd(); aIter.Next())
2061
0
    {
2062
0
        if(!IsInvalidItem(aIter.GetCurItem()))
2063
0
        {
2064
0
            if (SfxItemState::SET == aIter.GetItemState() &&
2065
0
                SfxItemState::SET == rStyleSet.GetItemState(aIter.GetCurWhich()))
2066
0
            {
2067
0
                aDeleteWhichIDs.push_back(aIter.GetCurWhich());
2068
0
                bReset = true;
2069
0
            }
2070
0
        }
2071
0
    }
2072
2073
0
    for (auto nDelWhich : aDeleteWhichIDs)
2074
0
        aCoreSet.ClearItem(nDelWhich);
2075
2076
0
    StartAction();
2077
0
    if(bReset)
2078
0
    {
2079
0
        ResetAttr({}, pCursor);
2080
0
        SetAttrSet(aCoreSet, SetAttrMode::DEFAULT, pCursor);
2081
0
    }
2082
0
    mxDoc->ChgFormat(*pColl, rStyleSet );
2083
0
    EndAction();
2084
0
}
2085
2086
void SwWrtShell::AutoUpdateFrame( SwFrameFormat* pFormat, const SfxItemSet& rStyleSet )
2087
0
{
2088
0
    StartAction();
2089
2090
0
    ResetFlyFrameAttr( &rStyleSet );
2091
0
    pFormat->SetFormatAttr( rStyleSet );
2092
2093
0
    EndAction();
2094
0
}
2095
2096
void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Unicode cChar )
2097
0
{
2098
0
    ResetCursorStack();
2099
0
    if(!CanInsert())
2100
0
        return;
2101
2102
0
    bool bStarted = false;
2103
0
    SwRewriter aRewriter;
2104
2105
0
    if(HasSelection())
2106
0
    {
2107
            // Only parentheses here, because the regular insert
2108
            // is already clipped to the editshell
2109
0
        StartAllAction();
2110
2111
0
        OUString aTmpStr1 = SwResId(STR_START_QUOTE) +
2112
0
            GetSelText() +
2113
0
            SwResId(STR_END_QUOTE);
2114
0
        OUString aTmpStr3 = SwResId(STR_START_QUOTE) +
2115
0
            OUStringChar(cChar) +
2116
0
            SwResId(STR_END_QUOTE);
2117
0
        aRewriter.AddRule( UndoArg1, aTmpStr1 );
2118
0
        aRewriter.AddRule( UndoArg2, SwResId(STR_YIELDS) );
2119
0
        aRewriter.AddRule( UndoArg3, aTmpStr3 );
2120
2121
0
        StartUndo( SwUndoId::REPLACE, &aRewriter );
2122
0
        bStarted = true;
2123
0
        DelRight(true);
2124
0
    }
2125
0
    SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
2126
2127
0
    if(bStarted)
2128
0
    {
2129
0
        EndAllAction();
2130
0
        EndUndo( SwUndoId::REPLACE, &aRewriter );
2131
0
    }
2132
0
}
2133
2134
// Some kind of controlled copy ctor
2135
2136
SwWrtShell::SwWrtShell( SwWrtShell& rSh, vcl::Window *_pWin, SwView &rShell )
2137
0
    : SwFEShell(rSh, _pWin)
2138
0
    , m_rView(rShell)
2139
0
    , m_aNavigationMgr(*this)
2140
0
{
2141
0
    BITFLD_INI_LIST
2142
0
    CurrShell aCurr( this );
2143
2144
0
    SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
2145
0
    SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
2146
2147
    // place the cursor on the first field...
2148
0
    Fieldmark *pBM = nullptr;
2149
0
    if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
2150
0
        GotoFieldmark(pBM);
2151
0
    }
2152
0
}
2153
2154
SwWrtShell::SwWrtShell( SwDoc& rDoc, vcl::Window *_pWin, SwView &rShell,
2155
                        const SwViewOption *pViewOpt )
2156
4.14k
    : SwFEShell(rDoc, _pWin, pViewOpt)
2157
4.14k
    , m_rView(rShell)
2158
4.14k
    , m_aNavigationMgr(*this)
2159
4.14k
{
2160
4.14k
    BITFLD_INI_LIST
2161
4.14k
    CurrShell aCurr( this );
2162
4.14k
    SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
2163
4.14k
    SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
2164
2165
    // place the cursor on the first field...
2166
4.14k
    Fieldmark *pBM = nullptr;
2167
4.14k
    if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
2168
0
        GotoFieldmark(pBM);
2169
0
    }
2170
4.14k
}
2171
2172
SwWrtShell::~SwWrtShell()
2173
4.14k
{
2174
4.14k
    CurrShell aCurr( this );
2175
4.14k
    while(IsModePushed())
2176
0
        PopMode();
2177
4.14k
    while(PopCursor(false))
2178
0
        ;
2179
4.14k
    SwTransferable::ClearSelection( *this );
2180
4.14k
}
2181
2182
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
2183
0
{
2184
0
    ::std::optional<SwCallLink> aLink(std::in_place, *this);
2185
0
    return Pop(eDelete, aLink);
2186
0
}
2187
2188
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::optional<SwCallLink>& roLink)
2189
0
{
2190
0
    bool bRet = SwCursorShell::Pop(eDelete, roLink);
2191
0
    if( bRet && IsSelection() )
2192
0
    {
2193
0
        m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
2194
0
        m_fnKillSel = &SwWrtShell::ResetSelect;
2195
0
    }
2196
0
    return bRet;
2197
0
}
2198
2199
bool SwWrtShell::CanInsert()
2200
0
{
2201
0
    if(IsSelFrameMode())
2202
0
    {
2203
0
        return false;
2204
0
    }
2205
2206
0
    if(GetSelectedObjCount())
2207
0
    {
2208
0
        return false;
2209
0
    }
2210
2211
0
    if(GetView().GetDrawFuncPtr())
2212
0
    {
2213
0
        return false;
2214
0
    }
2215
2216
0
    if(GetView().GetPostItMgr()->GetActiveSidebarWin())
2217
0
    {
2218
0
        return false;
2219
0
    }
2220
2221
0
    return true;
2222
0
}
2223
2224
void SwWrtShell::ChgDBData(const SwDBData& aDBData)
2225
0
{
2226
0
    SwEditShell::ChgDBData(aDBData);
2227
    //notify the db-beamer if available
2228
0
    GetView().NotifyDBChanged();
2229
0
}
2230
2231
OUString SwWrtShell::GetSelDescr() const
2232
0
{
2233
0
    OUString aResult;
2234
2235
0
    SelectionType nSelType = GetSelectionType();
2236
0
    switch (nSelType)
2237
0
    {
2238
0
    case SelectionType::Graphic:
2239
0
        aResult = SwResId(STR_GRAPHIC);
2240
2241
0
        break;
2242
0
    case SelectionType::Frame:
2243
0
        {
2244
0
            const SwFrameFormat * pFrameFormat = GetSelectedFrameFormat();
2245
2246
0
            if (pFrameFormat)
2247
0
                aResult = pFrameFormat->GetDescription();
2248
0
        }
2249
0
        break;
2250
0
    case SelectionType::DrawObject:
2251
0
        {
2252
0
            aResult = SwResId(STR_DRAWING_OBJECTS);
2253
0
        }
2254
0
        break;
2255
0
    default:
2256
0
        if (mxDoc)
2257
0
            aResult = GetCursorDescr();
2258
0
    }
2259
2260
0
    return aResult;
2261
0
}
2262
2263
void SwWrtShell::ApplyViewOptions( const SwViewOption &rOpt )
2264
8.61k
{
2265
8.61k
    SwFEShell::ApplyViewOptions( rOpt );
2266
    //#i115062# invalidate meta character slot
2267
8.61k
    GetView().GetViewFrame().GetBindings().Invalidate( FN_VIEW_META_CHARS );
2268
8.61k
}
2269
2270
void SwWrtShell::SetReadonlyOption(bool bSet)
2271
0
{
2272
0
    GetView().GetEditWin().GetFrameControlsManager().SetReadonlyControls( bSet );
2273
0
    SwViewShell::SetReadonlyOption( bSet );
2274
0
}
2275
2276
// Switch on/off header or footer of a page style - if an empty name is
2277
// given all styles are changed
2278
2279
void SwWrtShell::ChangeHeaderOrFooter(
2280
    const UIName& rStyleName, bool bHeader, bool bOn, bool bShowWarning)
2281
0
{
2282
0
    SdrView *const pSdrView = GetDrawView();
2283
0
    if (pSdrView && pSdrView->IsTextEdit())
2284
0
    {   // tdf#107474 deleting header may delete active drawing object
2285
0
        pSdrView->SdrEndTextEdit(true);
2286
0
    }
2287
0
    addCurrentPosition();
2288
    // tdf#137107 - prevent scrolling to cursor when deleting header/footer
2289
0
    const bool bLockedView = IsViewLocked();
2290
0
    if (!bOn)
2291
0
        LockView(true);
2292
0
    StartAllAction();
2293
0
    StartUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
2294
0
    bool bExecute = true;
2295
0
    bool bCursorSet = false;
2296
0
    for( size_t nFrom = 0, nTo = GetPageDescCnt();
2297
0
            nFrom < nTo; ++nFrom )
2298
0
    {
2299
0
        SwPageDesc aDesc( GetPageDesc( nFrom ));
2300
0
        UIName sTmp(aDesc.GetName());
2301
0
        if( rStyleName.toString().isEmpty() || rStyleName == sTmp )
2302
0
        {
2303
0
            bool bChgd = false;
2304
2305
0
            if( bShowWarning && !bOn && GetActiveView() && GetActiveView() == &GetView() &&
2306
0
                ( (bHeader && aDesc.GetMaster().GetHeader().IsActive()) ||
2307
0
                  (!bHeader && aDesc.GetMaster().GetFooter().IsActive()) ) )
2308
0
            {
2309
0
                bShowWarning = false;
2310
                //Actions have to be closed while the dialog is showing
2311
0
                EndAllAction();
2312
2313
0
                weld::Window* pParent = GetView().GetFrameWeld();
2314
0
                short nResult;
2315
0
                if (bHeader) {
2316
0
                    nResult = DeleteHeaderDialog(pParent).run();
2317
0
                } else {
2318
0
                    nResult = DeleteFooterDialog(pParent).run();
2319
0
                }
2320
2321
0
                bExecute = nResult == RET_YES;
2322
0
                StartAllAction();
2323
0
                if (nResult == RET_YES)
2324
0
                    ToggleHeaderFooterEdit();
2325
0
            }
2326
0
            if( bExecute )
2327
0
            {
2328
0
                bChgd = true;
2329
0
                SwFrameFormat &rMaster = aDesc.GetMaster();
2330
0
                if (bOn && (bHeader ? aDesc.IsWithoutFirstHeader() : aDesc.IsWithoutFirstFooter()))
2331
0
                {
2332
0
                    if (bHeader)
2333
0
                    {
2334
0
                        aDesc.ChgWithoutFirstHeader(false);
2335
0
                    }
2336
0
                    else
2337
0
                    {
2338
0
                        aDesc.ChgWithoutFirstFooter(false);
2339
0
                    }
2340
0
                }
2341
0
                else
2342
0
                {
2343
0
                    if (bHeader)
2344
0
                        rMaster.SetFormatAttr( SwFormatHeader( bOn ));
2345
0
                    else
2346
0
                        rMaster.SetFormatAttr( SwFormatFooter( bOn ));
2347
0
                }
2348
0
                if( bOn )
2349
0
                {
2350
                    // keep in sync with FN_PGNUMBER_WIZARD
2351
0
                    constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
2352
0
                    SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm, bHeader ? constTwips_5mm : 0, RES_UL_SPACE );
2353
0
                    SwFrameFormat* pFormat = bHeader ?
2354
0
                        const_cast<SwFrameFormat*>(rMaster.GetHeader().GetHeaderFormat()) :
2355
0
                        const_cast<SwFrameFormat*>(rMaster.GetFooter().GetFooterFormat());
2356
0
                    pFormat->SetFormatAttr( aUL );
2357
0
                    XFillStyleItem aFill(drawing::FillStyle_NONE);
2358
0
                    pFormat->SetFormatAttr(aFill);
2359
0
                }
2360
0
            }
2361
0
            if( bChgd )
2362
0
            {
2363
0
                ChgPageDesc( nFrom, aDesc );
2364
2365
0
                if( !bCursorSet && bOn )
2366
0
                {
2367
0
                    if ( !IsHeaderFooterEdit() )
2368
0
                        ToggleHeaderFooterEdit();
2369
0
                    bCursorSet = SetCursorInHdFt(
2370
0
                            rStyleName.toString().isEmpty() ? SIZE_MAX : nFrom,
2371
0
                            bHeader );
2372
0
                }
2373
0
            }
2374
0
        }
2375
0
    }
2376
0
    EndUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
2377
0
    EndAllAction();
2378
    // tdf#137107 - prevent scrolling to cursor when deleting header/footer
2379
0
    if (!bOn)
2380
0
        LockView(bLockedView);
2381
0
}
2382
2383
void SwWrtShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow )
2384
0
{
2385
0
    SwViewShell::SetShowHeaderFooterSeparator( eControl, bShow );
2386
0
    if ( !bShow )
2387
0
        GetView().GetEditWin().GetFrameControlsManager().HideControls( eControl );
2388
0
}
2389
2390
void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
2391
0
{
2392
0
    SwPostItField* pPostIt = dynamic_cast<SwPostItField*>(rFieldMgr.GetCurField());
2393
0
    bool bNew = !(pPostIt && pPostIt->GetTyp()->Which() == SwFieldIds::Postit);
2394
0
    if (bNew || GetView().GetPostItMgr()->IsAnswer() || comphelper::LibreOfficeKit::isActive())
2395
0
    {
2396
0
        const SvxPostItAuthorItem* pAuthorItem = rReq.GetArg(SID_ATTR_POSTIT_AUTHOR);
2397
0
        OUString sAuthor;
2398
0
        if ( pAuthorItem )
2399
0
            sAuthor = pAuthorItem->GetValue();
2400
0
        else
2401
0
        {
2402
0
            SwModule* mod = SwModule::get();
2403
0
            std::size_t nAuthor = mod->GetRedlineAuthor();
2404
0
            sAuthor = mod->GetRedlineAuthor(nAuthor);
2405
0
        }
2406
2407
0
        const SvxPostItTextItem* pTextItem = rReq.GetArg(SID_ATTR_POSTIT_TEXT);
2408
0
        OUString sText;
2409
0
        if ( pTextItem )
2410
0
            sText = pTextItem->GetValue();
2411
2412
0
        std::optional<OutlinerParaObject> oTextPara;
2413
0
        if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg(SID_ATTR_POSTIT_HTML))
2414
0
        {
2415
0
            SwDocShell* pDocSh = GetView().GetDocShell();
2416
0
            Outliner aOutliner(&pDocSh->GetPool(), OutlinerMode::TextObject);
2417
0
            SwPostItHelper::ImportHTML(aOutliner, pHtmlItem->GetValue());
2418
0
            oTextPara = aOutliner.CreateParaObject();
2419
0
            sText = aOutliner.GetEditEngine().GetText();
2420
0
        }
2421
2422
        // If we have a text already registered for answer, use that
2423
0
        SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
2424
0
        if (OutlinerParaObject* pAnswer = pPostItMgr->IsAnswer())
2425
0
        {
2426
0
            if (!pPostItMgr->GetAnswerText().isEmpty())
2427
0
            {
2428
0
                sText = GetView().GetPostItMgr()->GetAnswerText();
2429
0
                pPostItMgr->RegisterAnswerText(OUString());
2430
0
            }
2431
0
            const EditTextObject& rTextObject = pAnswer->GetTextObject();
2432
0
            if (rTextObject.GetParagraphCount() != 1 || !rTextObject.GetText(0).isEmpty())
2433
0
            {
2434
0
                oTextPara = *pAnswer;
2435
0
                sText = rTextObject.GetText();
2436
0
            }
2437
0
        }
2438
2439
0
        if ( HasSelection() && !IsTableMode() )
2440
0
        {
2441
0
            KillPams();
2442
0
        }
2443
2444
        // #i120513# Inserting a comment into an autocompletion crashes
2445
        // --> suggestion has to be removed before
2446
0
        GetView().GetEditWin().StopQuickHelp();
2447
2448
0
        SwInsertField_Data aData(SwFieldTypesEnum::Postit, 0, sAuthor, sText, 0);
2449
2450
0
        {
2451
0
            SvxPostItIdItem const*const pParentParaIdItem{rReq.GetArg(SID_ATTR_POSTIT_PARENTPARAID)};
2452
0
            SvxPostItIdItem const*const pParentPostItIdItem{rReq.GetArg(SID_ATTR_POSTIT_PARENTPOSTITID)};
2453
0
            SfxStringItem const*const pParentNameItem{rReq.GetArg(SID_ATTR_POSTIT_PARENTNAME)};
2454
0
            if (pParentParaIdItem && pParentPostItIdItem && pParentNameItem)
2455
0
            {
2456
0
                aData.m_oParentId.emplace(pParentParaIdItem->GetValue().toUInt32(),
2457
0
                    pParentPostItIdItem->GetValue().toUInt32(),
2458
0
                    pParentNameItem->GetValue());
2459
0
            }
2460
0
        }
2461
2462
0
        if (IsSelFrameMode())
2463
0
        {
2464
0
            SwFlyFrame* pFly = GetSelectedFlyFrame();
2465
2466
            // Remember the anchor of the selected object before deletion.
2467
0
            std::optional<SwPosition> oAnchor;
2468
0
            if (pFly)
2469
0
            {
2470
0
                SwFrameFormat* pFormat = pFly->GetFormat();
2471
0
                if (pFormat)
2472
0
                {
2473
0
                    RndStdIds eAnchorId = pFormat->GetAnchor().GetAnchorId();
2474
0
                    if ((eAnchorId == RndStdIds::FLY_AS_CHAR || eAnchorId == RndStdIds::FLY_AT_CHAR) && pFormat->GetAnchor().GetAnchorNode())
2475
0
                    {
2476
0
                        oAnchor.emplace(*pFormat->GetAnchor().GetContentAnchor());
2477
0
                    }
2478
0
                }
2479
0
            }
2480
2481
            // A frame is selected, end frame selection.
2482
0
            EnterStdMode();
2483
0
            GetView().AttrChangedNotify(nullptr);
2484
2485
            // Set up text selection, so the anchor of the frame will be the anchor of the
2486
            // comment.
2487
0
            if (pFly)
2488
0
            {
2489
0
                if (oAnchor)
2490
0
                    *GetCurrentShellCursor().GetPoint() = *oAnchor;
2491
0
                SwFrameFormat* pFormat = pFly->GetFormat();
2492
0
                if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
2493
0
                {
2494
0
                    Right(SwCursorSkipMode::Cells, /*bSelect=*/true, 1, /*bBasicCall=*/false, /*bVisual=*/true);
2495
0
                }
2496
0
                else if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR)
2497
0
                {
2498
0
                    aData.m_oAnnotationRange.emplace(*GetCurrentShellCursor().Start(),
2499
0
                                                     *GetCurrentShellCursor().End());
2500
0
                }
2501
0
            }
2502
0
        }
2503
2504
        // Defer broadcast of postit field update from layout until oTextPara has been
2505
        // applied to the field's associated postit window
2506
0
        if (oTextPara)
2507
0
            StartAction();
2508
2509
0
        rFieldMgr.InsertField( aData );
2510
2511
0
        Push();
2512
0
        SwCursorShell::Left(1, SwCursorSkipMode::Chars);
2513
0
        pPostIt = static_cast<SwPostItField*>(rFieldMgr.GetCurField());
2514
2515
0
        if (pPostIt && oTextPara)
2516
0
            pPostIt->SetTextObject(*oTextPara);
2517
2518
0
        Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position
2519
2520
0
        if (oTextPara)
2521
0
            EndAction();
2522
0
    }
2523
2524
    // Client has disabled annotations rendering, no need to
2525
    // focus the postit field
2526
0
    if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
2527
0
        return;
2528
2529
0
    if (pPostIt)
2530
0
    {
2531
0
        SwFieldType* pType = GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
2532
0
        if(auto pFormat = pType->FindFormatForField(pPostIt))
2533
0
            pFormat->Broadcast( SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::FOCUS, &GetView() ) );
2534
0
    }
2535
0
}
2536
2537
bool SwWrtShell::IsOutlineContentVisible(const size_t nPos)
2538
0
{
2539
0
    const SwOutlineNodes& rOutlineNodes = GetDoc()->GetNodes().GetOutLineNds();
2540
0
    const SwNode* pOutlineNode = rOutlineNodes[nPos];
2541
2542
    // no layout frame means outline folding is set to include sub levels and the outline node has
2543
    // a parent outline node with outline content visible attribute false (folded outline content)
2544
0
    if (!pOutlineNode->GetTextNode()->getLayoutFrame(GetLayout()))
2545
0
        return false;
2546
2547
    // try the next node to determine if this outline node has visible content
2548
0
    SwNodeIndex aIdx(*pOutlineNode, +1);
2549
0
    if (aIdx.GetNode() == aIdx.GetNodes().GetEndOfContent()) // end of regular content
2550
0
        return false;
2551
2552
0
    if (aIdx.GetNode().IsTextNode() || aIdx.GetNode().IsTableNode() ||
2553
0
            aIdx.GetNode().IsSectionNode())
2554
0
    {
2555
        // * sublevels treated as outline content
2556
        //     If next node (aIdx) doesn't have a layout frame
2557
        //     then this outline node does not have visible outline content.
2558
        // * sublevels NOT treated as outline content
2559
        //     If the next node (aIdx) is the next outline node
2560
        //     then return the outline content visible attribute value.
2561
0
        if (!GetViewOptions()->IsTreatSubOutlineLevelsAsContent() &&
2562
0
                nPos + 1 < rOutlineNodes.size() &&
2563
0
                rOutlineNodes[nPos + 1] == &aIdx.GetNode())
2564
0
            return GetAttrOutlineContentVisible(nPos);
2565
2566
0
        if (aIdx.GetNode().IsTextNode())
2567
0
            return aIdx.GetNode().GetTextNode()->getLayoutFrame(GetLayout());
2568
0
        if (aIdx.GetNode().IsTableNode())
2569
0
        {
2570
0
            SwTable& rTable = aIdx.GetNode().GetTableNode()->GetTable();
2571
0
            return rTable.HasLayout();
2572
0
        }
2573
0
        if (aIdx.GetNode().IsSectionNode())
2574
0
        {
2575
0
            const auto pFormat = aIdx.GetNode().GetSectionNode()->GetSection().GetFormat();
2576
0
            return pFormat && pFormat->IsVisible();
2577
0
        }
2578
0
    }
2579
2580
0
    return true;
2581
0
}
2582
2583
void SwWrtShell::MakeOutlineLevelsVisible(const int nLevel)
2584
0
{
2585
0
    MakeAllOutlineContentTemporarilyVisible a(GetDoc());
2586
2587
0
    m_rView.SetMaxOutlineLevelShown(nLevel);
2588
2589
0
    bool bDocChanged = false;
2590
2591
0
    const SwOutlineNodes& rOutlineNodes = GetNodes().GetOutLineNds();
2592
2593
    // Make all missing frames.
2594
0
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
2595
0
    {
2596
0
        SwNode* pNode = rOutlineNodes[nPos];
2597
0
        if (!pNode->GetTextNode()->getLayoutFrame(GetLayout()))
2598
0
        {
2599
0
            SwNodeIndex aIdx(*pNode, +1);
2600
            // Make the outline paragraph frame
2601
0
            ::MakeFrames(*GetDoc(), *pNode, aIdx.GetNode(), true);
2602
            // Make the outline content visible but don't set the outline visible attribute and
2603
            // don't make outline content made visible not visible that have outline visible
2604
            // attribute false. Visibility will be taken care of when
2605
            // MakeAllOutlineContentTemporarilyVisible goes out of scope.
2606
0
            MakeOutlineContentVisible(nPos, true, false);
2607
0
            bDocChanged = true;
2608
0
        }
2609
0
    }
2610
    // Remove outline paragraph frame and outline content frames above given level.
2611
0
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
2612
0
    {
2613
0
        SwNode* pNode = rOutlineNodes[nPos];
2614
0
        auto nOutlineLevel = pNode->GetTextNode()->GetAttrOutlineLevel();
2615
0
        if (nOutlineLevel > nLevel)
2616
0
        {
2617
            // Remove the outline content but don't set the outline visible attribute. Visibility
2618
            // will be taken care of when MakeAllOutlineContentTemporarilyVisible goes out of scope.
2619
0
            MakeOutlineContentVisible(nPos, false, false);
2620
            // Remove the outline paragraph frame.
2621
0
            pNode->GetTextNode()->DelFrames(GetLayout());
2622
0
            bDocChanged = true;
2623
0
        }
2624
0
    }
2625
2626
    // Broadcast DocChanged if document layout has changed so the Navigator will be updated.
2627
0
    if (bDocChanged)
2628
0
        GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
2629
0
}
2630
2631
void SwWrtShell::MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible, bool bSetAttrOutlineVisibility)
2632
0
{
2633
0
    const SwNodes& rNodes = GetNodes();
2634
0
    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
2635
2636
0
    SwNode* pSttNd = rOutlineNodes[nPos];
2637
2638
    // determine end node
2639
0
    SwNode* pEndNd = &rNodes.GetEndOfContent();
2640
0
    if (rOutlineNodes.size() > nPos + 1)
2641
0
        pEndNd = rOutlineNodes[nPos + 1];
2642
2643
0
    if (GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
2644
0
    {
2645
        // get the last outline node to include (iPos)
2646
0
        int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
2647
0
        int nMaxOutlineLevelShown = m_rView.GetMaxOutlineLevelShown();
2648
0
        SwOutlineNodes::size_type iPos = nPos;
2649
0
        while (++iPos < rOutlineNodes.size() &&
2650
0
               rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel &&
2651
0
               rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() <= nMaxOutlineLevelShown);
2652
2653
        // get the correct end node
2654
        // the outline node may be in frames, headers, footers special section of doc model
2655
0
        SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
2656
0
        while (pStartOfSectionNodeSttNd->StartOfSectionNode()
2657
0
               != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
2658
0
        {
2659
0
            pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
2660
0
        }
2661
0
        pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
2662
2663
0
        if (iPos < rOutlineNodes.size())
2664
0
        {
2665
0
            SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
2666
0
            while (pStartOfSectionNode->StartOfSectionNode()
2667
0
                   != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
2668
0
            {
2669
0
                pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
2670
0
            }
2671
0
            if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
2672
0
                pEndNd = rOutlineNodes[iPos];
2673
0
        }
2674
0
    }
2675
2676
    // table, text box, header, footer
2677
0
    if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
2678
0
    {
2679
        // limit to within section
2680
0
        if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
2681
0
            pEndNd = pSttNd->EndOfSectionNode();
2682
0
    }
2683
    // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
2684
0
    else if (pEndNd->GetTableBox())
2685
0
    {
2686
0
        pEndNd = &rNodes.GetEndOfContent();
2687
0
        for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
2688
0
        {
2689
0
            if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
2690
0
            {
2691
0
                pEndNd = rOutlineNodes[nOutlinePos];
2692
0
                break;
2693
0
            }
2694
0
        }
2695
0
    }
2696
    // end node determined
2697
2698
    // Remove content frames from the next node after the starting outline node to
2699
    // the determined ending node. Always do this to prevent the chance of duplicate
2700
    // frames being made. They will be remade below if needed.
2701
0
    SwNodeIndex aIdx(*pSttNd, +1);
2702
0
    while (aIdx != *pEndNd)
2703
0
    {
2704
0
        SwNode* pNd = &aIdx.GetNode();
2705
0
        if (pNd->IsContentNode())
2706
0
            pNd->GetContentNode()->DelFrames(nullptr);
2707
0
        else if (pNd->IsTableNode())
2708
0
            pNd->GetTableNode()->DelFrames(nullptr);
2709
0
        ++aIdx;
2710
0
    }
2711
2712
0
    if (bMakeVisible) // make outline nodes outline content visible
2713
0
    {
2714
        // reset the index marker and make frames
2715
0
        aIdx.Assign(*pSttNd, +1);
2716
0
        ::MakeFrames(*GetDoc(), aIdx.GetNode(), *pEndNd, true);
2717
2718
0
        if (bSetAttrOutlineVisibility)
2719
0
        {
2720
0
            pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true);
2721
2722
            // make outline content made visible that have outline visible attribute false not visible
2723
0
            while (aIdx != *pEndNd)
2724
0
            {
2725
0
                SwNode* pNd = &aIdx.GetNode();
2726
0
                if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline())
2727
0
                {
2728
0
                    SwTextNode* pTextNd = pNd->GetTextNode();
2729
0
                    if (!pTextNd->GetAttrOutlineContentVisible())
2730
0
                    {
2731
0
                        SwOutlineNodes::size_type iPos;
2732
0
                        if (rOutlineNodes.Seek_Entry(pTextNd, &iPos))
2733
0
                        {
2734
0
                            if (pTextNd->getLayoutFrame(nullptr))
2735
0
                                MakeOutlineContentVisible(iPos, false);
2736
0
                        }
2737
0
                    }
2738
0
                }
2739
0
                ++aIdx;
2740
0
            }
2741
0
        }
2742
0
    }
2743
0
    else if (bSetAttrOutlineVisibility)
2744
0
        pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
2745
0
}
2746
2747
// make content visible or not visible only if needed
2748
void SwWrtShell::InvalidateOutlineContentVisibility()
2749
0
{
2750
    // tdf#170599 fix taken from fix for:
2751
    //   "rhbz#818557, fdo#58893: EndAllAction will call SelectShell(),
2752
    //    which pushes a bunch of SfxShells that are not cleared
2753
    //    (for unknown reasons) when closing the document, causing crash;
2754
    //    setting g_bNoInterrupt appears to avoid the problem."
2755
    // In this case the crash occurs when reopening Print Preview with outline folding enabled and
2756
    // a heading in the first paragraph and display formatting hidden characters option is enabled.
2757
0
    comphelper::FlagRestorationGuard g(g_bNoInterrupt, true);
2758
2759
0
    StartAction();
2760
2761
0
    GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
2762
2763
0
    const SwOutlineNodes& rOutlineNds = GetNodes().GetOutLineNds();
2764
0
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
2765
0
    {
2766
0
        bool bIsOutlineContentVisible = IsOutlineContentVisible(nPos);
2767
0
        bool bOutlineContentVisibleAttr = rOutlineNds[nPos]->GetTextNode()->GetAttrOutlineContentVisible();
2768
0
        if (!bIsOutlineContentVisible && bOutlineContentVisibleAttr)
2769
0
            MakeOutlineContentVisible(nPos);
2770
0
        else if (bIsOutlineContentVisible && !bOutlineContentVisibleAttr)
2771
0
            MakeOutlineContentVisible(nPos, false);
2772
0
    }
2773
2774
0
    EndAction();
2775
0
}
2776
2777
void SwWrtShell::MakeAllFoldedOutlineContentVisible(bool bMakeVisible)
2778
0
{
2779
0
    if (bMakeVisible)
2780
0
    {
2781
        // make all content visible
2782
2783
        // When shortcut is assigned to the show outline content visibility button and used to
2784
        // toggle the feature and the mouse pointer is on an outline frame the button will not
2785
        // be removed. An easy way to make sure the button does not remain shown is to use the
2786
        // HideControls function.
2787
0
        GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
2788
2789
        // temporarily set outline content visible attribute true for folded outline nodes
2790
0
        std::vector<SwNode*> aFoldedOutlineNodeArray;
2791
0
        for (SwNode* pNd: GetNodes().GetOutLineNds())
2792
0
        {
2793
0
            if (!pNd->GetTextNode()->GetAttrOutlineContentVisible())
2794
0
            {
2795
0
                aFoldedOutlineNodeArray.push_back(pNd);
2796
0
                pNd->GetTextNode()->SetAttrOutlineContentVisible(true);
2797
0
            }
2798
0
        }
2799
2800
0
        InvalidateOutlineContentVisibility();
2801
2802
        // restore outline content visible attribute for folded outline nodes
2803
0
        for (SwNode* pNd: aFoldedOutlineNodeArray)
2804
0
            pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
2805
0
    }
2806
0
    else
2807
0
    {
2808
0
        AssureStdMode();
2809
2810
        // Get the outline position of the cursor so the cursor can be place at a visible outline
2811
        // node if it is not visible after InvalidateOutlineContentVisiblity below.
2812
0
        SwOutlineNodes::size_type nPos = GetOutlinePos();
2813
2814
0
        InvalidateOutlineContentVisibility();
2815
2816
        // If needed, find a visible outline node to place the cursor.
2817
0
        if (nPos != SwOutlineNodes::npos && !IsOutlineContentVisible(nPos))
2818
0
        {
2819
0
            while (nPos != SwOutlineNodes::npos &&
2820
0
                   !GetNodes().GetOutLineNds()[nPos]->GetTextNode()->getLayoutFrame(GetLayout()))
2821
0
                --nPos;
2822
0
            if (nPos != SwOutlineNodes::npos)
2823
0
                GotoOutline(nPos);
2824
0
        }
2825
0
    }
2826
0
    GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
2827
0
}
2828
2829
bool SwWrtShell::GetAttrOutlineContentVisible(const size_t nPos) const
2830
0
{
2831
0
    return GetNodes().GetOutLineNds()[nPos]->GetTextNode()->GetAttrOutlineContentVisible();
2832
0
}
2833
2834
bool SwWrtShell::HasFoldedOutlineContentSelected() const
2835
0
{
2836
    // No need to check for selection over folded outline content when there are no outline nodes.
2837
0
    if (GetDoc()->GetNodes().GetOutLineNds().empty())
2838
0
        return false;
2839
0
    for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
2840
0
    {
2841
0
        SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint());
2842
0
        aPaM.Normalize();
2843
0
        SwNodeIndex aPointIdx(aPaM.GetPoint()->GetNode());
2844
0
        SwNodeIndex aMarkIdx(aPaM.GetMark()->GetNode());
2845
        // Prevent crash in the for loop below by adjusting the mark if it is set to the end of
2846
        // content node.
2847
0
        if (aMarkIdx.GetNode() == GetDoc()->GetNodes().GetEndOfContent())
2848
0
            --aMarkIdx;
2849
0
        if (aPointIdx == aMarkIdx)
2850
0
            continue;
2851
        // Return true if any nodes in PaM are folded outline content nodes.
2852
0
        SwOutlineNodes::size_type nPos;
2853
0
        for (SwNodeIndex aIdx = aPointIdx; aIdx <= aMarkIdx; ++aIdx)
2854
0
        {
2855
            // To allow delete when the start of the selection is at the start of a
2856
            // paragraph and the end of the selection is at the start of a paragraph and there
2857
            // are no folded outline content nodes in between.
2858
0
            if (aIdx == aMarkIdx && aPaM.GetPoint()->GetContentIndex() == 0 &&
2859
0
                    aPaM.GetMark()->GetContentIndex() == 0)
2860
0
                return false;
2861
2862
0
            if (GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(&(aIdx.GetNode()), &nPos) &&
2863
0
                    !GetAttrOutlineContentVisible(nPos))
2864
0
                return true;
2865
0
        }
2866
0
    }
2867
0
    return false;
2868
0
}
2869
2870
void SwWrtShell::InfoReadOnlyDialog(bool bAsync) const
2871
0
{
2872
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 16
2873
#pragma GCC diagnostic push
2874
#pragma GCC diagnostic ignored "-Warray-bounds"
2875
#endif
2876
0
    if (bAsync)
2877
0
    {
2878
0
        auto xInfo = std::make_shared<weld::MessageDialogController>(
2879
0
                    GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui", "InfoReadonlyDialog");
2880
0
        if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
2881
0
                HasFoldedOutlineContentSelected())
2882
0
        {
2883
0
            xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2884
0
            xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2885
0
        }
2886
0
        weld::DialogController::runAsync(xInfo, [](int) {});
2887
0
    }
2888
0
    else
2889
0
    {
2890
0
        std::unique_ptr<weld::Builder>
2891
0
                xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(),
2892
0
                                                    u"modules/swriter/ui/inforeadonlydialog.ui"_ustr));
2893
0
        std::unique_ptr<weld::MessageDialog>
2894
0
                xInfo(xBuilder->weld_message_dialog(u"InfoReadonlyDialog"_ustr));
2895
0
        if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
2896
0
                HasFoldedOutlineContentSelected())
2897
0
        {
2898
0
            xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2899
0
            xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2900
0
        }
2901
0
        xInfo->run();
2902
0
    }
2903
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 16
2904
#pragma GCC diagnostic pop
2905
#endif
2906
0
}
2907
2908
bool SwWrtShell::WarnHiddenSectionDialog() const
2909
0
{
2910
0
    std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
2911
0
        GetView().GetFrameWeld(), u"modules/swriter/ui/warnhiddensectiondialog.ui"_ustr));
2912
0
    std::unique_ptr<weld::MessageDialog> xQuery(
2913
0
        xBuilder->weld_message_dialog(u"WarnHiddenSectionDialog"_ustr));
2914
0
    if (GetViewOptions()->IsShowOutlineContentVisibilityButton()
2915
0
        && HasFoldedOutlineContentSelected())
2916
0
    {
2917
0
        xQuery->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2918
0
        xQuery->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2919
0
    }
2920
2921
0
    return (RET_YES == xQuery->run());
2922
0
}
2923
2924
bool SwWrtShell::WarnSwitchToDesignModeDialog() const
2925
0
{
2926
0
    std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(nullptr,
2927
0
        VclMessageType::Question, VclButtonsType::YesNo, SwResId(STR_A11Y_DESIGN_MODE_PRIMARY)));
2928
0
    xQuery->set_default_response(RET_YES);
2929
0
    xQuery->set_title(SwResId(STR_A11Y_DESIGN_MODE_TITLE));
2930
0
    xQuery->set_secondary_text(SwResId(STR_A11Y_DESIGN_MODE_SECONDARY));
2931
2932
0
    return (RET_YES == xQuery->run());
2933
0
}
2934
2935
void SwWrtShell::CountWordsBeforeAfterCursor(SwDocStat& rBefore, SwDocStat& rAfter)
2936
0
{
2937
0
    SwNodes& rNodes = GetDoc()->GetNodes();
2938
2939
0
    SwNodeIndex nNode(rNodes.GetEndOfAutotext());
2940
0
    SwContentNode* pStart = SwNodes::GoNext(&nNode);
2941
2942
0
    nNode = rNodes.GetEndOfContent();
2943
0
    SwContentNode* pEnd = SwNodes::GoPrevious(&nNode);
2944
2945
0
    if (!pStart || !pEnd)
2946
0
        return;
2947
2948
0
    SwPosition aDocStart(*pStart, sal_Int32(0));
2949
0
    SwPosition aDocEnd(*pEnd, pEnd->Len());
2950
2951
    // Use WORD_COUNT word type — same as SwDoc::CountWords — so that
2952
    // word boundary detection is consistent with how words are counted.
2953
    // When cursor is mid-word, snap to the start of the current word
2954
    // so the word is fully counted in the "after" part.
2955
    // This ensures before + after = total words at all times.
2956
0
    const sal_Int16 nWordType = css::i18n::WordType::WORD_COUNT;
2957
2958
0
    SwPosition aSplitPos = *GetCursor()->GetPoint();
2959
2960
0
    if (IsInWord(nWordType) && !IsStartWord(nWordType) && !IsEndWord(nWordType))
2961
0
    {
2962
0
        Push();
2963
0
        GetCursor()->GoStartWordWT(nWordType);
2964
0
        aSplitPos = *GetCursor()->GetPoint();
2965
0
        Pop(SwCursorShell::PopMode::DeleteCurrent);
2966
0
    }
2967
2968
0
    SwPaM aBefore(aDocStart, aSplitPos);
2969
0
    SwPaM aAfter(aSplitPos, aDocEnd);
2970
2971
0
    SwDoc::CountWords(aBefore, rBefore);
2972
0
    SwDoc::CountWords(aAfter, rAfter);
2973
0
}
2974
2975
// Draft View: Browse Mode yet, but showing multi-column
2976
// sections as single-column sections focusing on text editing.
2977
// To enable the single-column view, remove all the multi-column
2978
// section frames, and make them back only with a single column
2979
// in SwSectionFrame::Init().
2980
void SwWrtShell::UpdateMultiColumnSectionsForBrowseModeChange()
2981
0
{
2982
0
    SwDoc* pDoc = GetDoc();
2983
0
    SwSectionFormats const& rFormats = pDoc->GetSections();
2984
2985
    // check multi-column sections
2986
0
    size_t i = 0;
2987
0
    for (; i < rFormats.size(); ++i)
2988
0
    {
2989
0
        if ( rFormats[i]->GetCol().GetNumCols() > 1 )
2990
0
            break;
2991
0
    }
2992
2993
    // no multi-column sections
2994
0
    if ( i == rFormats.size() )
2995
0
        return;
2996
2997
    // check normal document sections only
2998
0
    const SwSection* rFirstSection = rFormats[i]->GetSection();
2999
3000
0
    const SwNodes& rNodes = GetNodes();
3001
0
    SwNode* pSttNd = rNodes[SwNodeOffset(0)];
3002
0
    SwNode* pEndNd = &rNodes.GetEndOfContent();
3003
0
    SwNodeIndex aIdx(*pSttNd, +1);
3004
3005
0
    bool bStartFrameDeletion = false;
3006
3007
0
    while (aIdx != *pEndNd)
3008
0
    {
3009
0
        SwNode* pNd = &aIdx.GetNode();
3010
0
        if ( !bStartFrameDeletion && pNd->IsSectionNode() &&
3011
0
            static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat() ==
3012
0
                                                                    rFirstSection->GetFormat() )
3013
0
        {
3014
0
            bStartFrameDeletion = true;
3015
0
        }
3016
3017
0
        if ( bStartFrameDeletion && pNd->IsSectionNode() &&
3018
            // update multi-column sections only
3019
0
            static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat()->GetCol().GetNumCols() > 1 )
3020
0
        {
3021
            // insert a dummy paragraph to avoid of crashing at removing page frames unnecessarily
3022
0
            {
3023
0
                ::sw::UndoGuard const undoGuard(GetDoc()->GetIDocumentUndoRedo());
3024
0
                SwNodeIndex aDummyIdx( *pNd, -1 );
3025
0
                SwPosition aDummyPos( aDummyIdx );
3026
0
                getIDocumentContentOperations().AppendTextNode(aDummyPos);
3027
0
            }
3028
3029
            // remove and make section frames to update their columns
3030
0
            pNd->GetSectionNode()->DelFrames(nullptr);
3031
0
            static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat()->MakeFrames();
3032
3033
            // remove the dummy paragraph
3034
0
            {
3035
0
                ::sw::UndoGuard const undoGuard(GetDoc()->GetIDocumentUndoRedo());
3036
0
                SwNodeIndex aDelIdx( *pNd, -1 );
3037
0
                SwPaM aDelPam(aDelIdx);
3038
0
                getIDocumentContentOperations().DelFullPara(aDelPam);
3039
0
            }
3040
0
        }
3041
0
        ++aIdx;
3042
0
    }
3043
0
}
3044
3045
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */