enable spotlight subset in kit mode
[LibreOffice.git] / sw / source / uibase / wrtsh / wrtsh1.cxx
blobcd5572e44d6a48e7b80e943a35bfc569d3522638
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
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 <unotools/charclass.hxx>
46 #include <comphelper/storagehelper.hxx>
47 #include <comphelper/random.hxx>
48 #include <svx/svxdlg.hxx>
49 #include <svx/extrusionbar.hxx>
50 #include <svx/fontworkbar.hxx>
51 #include <dialoghelp.hxx>
52 #include <frmfmt.hxx>
53 #include <fmtftn.hxx>
54 #include <fmthdft.hxx>
55 #include <fmtpdsc.hxx>
56 #include <txtfrm.hxx>
57 #include <wdocsh.hxx>
58 #include <swmodule.hxx>
59 #include <wrtsh.hxx>
60 #include <view.hxx>
61 #include <cmdid.h>
62 #include <pagedesc.hxx>
63 #include <frmmgr.hxx>
64 #include <swundo.hxx>
65 #include <swcli.hxx>
66 #include <poolfmt.hxx>
67 #include <postithelper.hxx>
68 #include <edtwin.hxx>
69 #include <fmtcol.hxx>
70 #include <swtable.hxx>
71 #include <viscrs.hxx>
72 #include <swdtflvr.hxx>
73 #include <doc.hxx>
74 #include <IDocumentSettingAccess.hxx>
75 #include <SwCapObjType.hxx>
76 #include <SwStyleNameMapper.hxx>
77 #include <sfx2/request.hxx>
78 #include <paratr.hxx>
79 #include <ndtxt.hxx>
80 #include <editeng/acorrcfg.hxx>
81 #include <IMark.hxx>
82 #include <sfx2/bindings.hxx>
83 #include <flyfrm.hxx>
85 // -> #111827#
86 #include <SwRewriter.hxx>
87 #include <strings.hrc>
88 // <- #111827#
90 #include <toolkit/helper/vclunohelper.hxx>
91 #include <sfx2/viewfrm.hxx>
92 #include <vcl/uitest/logger.hxx>
93 #include <vcl/uitest/eventdescription.hxx>
94 #include <osl/diagnose.h>
95 #include <o3tl/unit_conversion.hxx>
96 #include <officecfg/Office/Common.hxx>
98 #include <PostItMgr.hxx>
99 #include <FrameControlsManager.hxx>
100 #include <fldmgr.hxx>
101 #include <docufld.hxx>
102 #include <IDocumentFieldsAccess.hxx>
103 #include <fmtfld.hxx>
105 #include <sfx2/msgpool.hxx>
106 #include <sfx2/msg.hxx>
107 #include <svtools/embedhlp.hxx>
108 #include <svtools/strings.hrc>
109 #include <svtools/svtresid.hxx>
110 #include <svx/postattr.hxx>
111 #include <comphelper/lok.hxx>
112 #include <comphelper/propertyvalue.hxx>
113 #include <svtools/optionsdrawinglayer.hxx>
114 #include <svl/numformat.hxx>
115 #include <svl/zformat.hxx>
116 #include <memory>
118 #include "../../core/crsr/callnk.hxx"
119 #include <frmtool.hxx>
120 #include <viewopt.hxx>
122 #include <IDocumentRedlineAccess.hxx>
123 #include <IDocumentUndoRedo.hxx>
124 #include <UndoInsert.hxx>
125 #include <UndoCore.hxx>
126 #include <formatlinebreak.hxx>
127 #include <formatcontentcontrol.hxx>
128 #include <textcontentcontrol.hxx>
130 using namespace sw::mark;
131 using namespace com::sun::star;
132 namespace {
134 void collectUIInformation(const OUString& rAction, const OUString& aParameters)
136 EventDescription aDescription;
137 aDescription.aAction = rAction;
138 aDescription.aParameters = {{"parameters", aParameters}};
139 aDescription.aID = "writer_edit";
140 aDescription.aKeyWord = "SwEditWinUIObject";
141 aDescription.aParent = "MainWindow";
142 UITestLogger::getInstance().logEvent(aDescription);
147 sal_uInt32 MakeAllOutlineContentTemporarilyVisible::nLock = 0;
149 static bool lcl_IsAllowed(const SwWrtShell* rSh)
151 if (rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() && rSh->IsEndPara())
153 SwTextNode* pTextNode = rSh->GetCursor()->GetPointNode().GetTextNode();
154 if (pTextNode && pTextNode->IsOutline())
156 // disallow if this is an outline node having folded content
157 if (!pTextNode->GetAttrOutlineContentVisible())
158 return false;
161 return true;
164 #define BITFLD_INI_LIST \
165 m_bClearMark = \
166 m_bIns = true;\
167 m_bAddMode = \
168 m_bBlockMode = \
169 m_bExtMode = \
170 m_bInSelect = \
171 m_bLayoutMode = \
172 m_bSelWrd = \
173 m_bSelLn = \
174 m_bRetainSelection = false; \
175 m_bIsInClickToEdit = false;
177 static SvxAutoCorrect* lcl_IsAutoCorr()
179 SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
180 if( pACorr && !pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
181 ACFlags::AddNonBrkSpace | ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
182 ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr | ACFlags::Autocorrect |
183 ACFlags::SetDOIAttr ))
184 pACorr = nullptr;
185 return pACorr;
188 void SwWrtShell::NoEdit(bool bHideCursor)
190 if(bHideCursor)
191 HideCursor();
194 void SwWrtShell::Edit()
196 if (CanInsert())
198 ShowCursor();
202 bool SwWrtShell::IsEndWrd()
204 SwMvContext aMvContext(this);
205 if(IsEndPara() && !IsSttPara())
206 return true;
208 return IsEndWord();
211 // Insert string
212 void SwWrtShell::InsertByWord( const OUString & rStr)
214 if( rStr.isEmpty() )
215 return;
217 bool bDelim = GetAppCharClass().isLetterNumeric( rStr, 0 );
218 sal_Int32 nPos = 0, nStt = 0;
219 for( ; nPos < rStr.getLength(); nPos++ )
221 bool bTmpDelim = GetAppCharClass().isLetterNumeric( rStr, nPos );
222 if( bTmpDelim != bDelim )
224 Insert( rStr.copy( nStt, nPos - nStt ));
225 nStt = nPos;
228 if( nStt != nPos )
229 Insert( rStr.copy( nStt, nPos - nStt ));
232 void SwWrtShell::Insert( const OUString &rStr )
234 ResetCursorStack();
235 if( !CanInsert() )
236 return;
238 bool bStarted = false;
239 bool bHasSel = HasSelection(),
240 bCallIns = m_bIns /*|| bHasSel*/;
241 bool bDeleted = false;
243 if( bHasSel || ( !m_bIns && IsInHiddenRange(/*bSelect=*/true) ) )
245 // Only here parenthesizing, because the normal
246 // insert is already in parentheses at Editshell.
247 StartAllAction();
249 SwRewriter aRewriter;
251 aRewriter.AddRule(UndoArg1, GetCursorDescr());
252 aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
254 OUString aTmpStr = SwResId(STR_START_QUOTE) +
255 rStr + SwResId(STR_END_QUOTE);
257 aRewriter.AddRule(UndoArg3, aTmpStr);
260 StartUndo(SwUndoId::REPLACE, &aRewriter);
261 bStarted = true;
262 Push();
263 // let's interpret a selection within the same node as "replace"
264 bDeleted = DelRight(GetCursor()->GetPoint()->GetNode() == GetCursor()->GetMark()->GetNode());
265 Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if tracking changes)
266 NormalizePam(false); // tdf#127635 put point at the end of deletion
267 ClearMark();
270 bCallIns ?
271 SwEditShell::Insert2( rStr, bDeleted ) : SwEditShell::Overwrite( rStr );
273 // Check whether node is content control
274 SwTextContentControl* pTextContentControl = CursorInsideContentControl();
275 if (pTextContentControl)
277 std::shared_ptr<SwContentControl> pContentControl =
278 pTextContentControl->GetContentControl().GetContentControl();
279 if (pContentControl)
281 // Set showingPlcHdr to false as node has been edited
282 pContentControl->SetShowingPlaceHolder(false);
286 if( bStarted )
288 EndUndo();
289 EndAllAction();
293 // Maximum height limit not possible, because the maximum height
294 // of the current frame can not be obtained.
296 void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter,
297 const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr,
298 RndStdIds nAnchorType )
300 ResetCursorStack();
301 if ( !CanInsert() )
302 return;
304 StartAllAction();
306 SwRewriter aRewriter;
307 aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC));
309 StartUndo(SwUndoId::INSERT, &aRewriter);
311 if ( HasSelection() )
312 DelRight();
313 // Inserted graphics in its own paragraph,
314 // if at the end of a non-empty paragraph.
315 //For i120928,avoid to split node
317 EnterSelFrameMode();
319 bool bSetGrfSize = true;
320 bool bOwnMgr = false;
322 if ( !pFrameMgr )
324 bOwnMgr = true;
325 pFrameMgr = new SwFlyFrameAttrMgr( true, this, Frmmgr_Type::GRF, nullptr );
327 // CAUTION
328 // GetAttrSet makes an adjustment
329 // While pasting is a SwFrameSize present
330 // because of the DEF-Framesize
331 // These must be removed explicitly for the optimal size.
332 pFrameMgr->DelAttr(RES_FRM_SIZE);
334 if (nAnchorType != RndStdIds::FLY_AT_PARA)
335 // Something other than at-para was requested.
336 pFrameMgr->SetAnchor(nAnchorType);
338 else
340 Size aSz( pFrameMgr->GetSize() );
341 if ( !aSz.Width() || !aSz.Height() )
343 aSz.setWidth(o3tl::toTwips(1, o3tl::Length::cm));
344 aSz.setHeight(o3tl::toTwips(1, o3tl::Length::cm));
345 pFrameMgr->SetSize( aSz );
347 else if ( aSz.Width() != DFLT_WIDTH && aSz.Height() != DFLT_HEIGHT )
348 bSetGrfSize = false;
350 pFrameMgr->SetHeightSizeType(SwFrameSize::Fixed);
353 // during change tracking, insert the image anchored as character
354 // (to create an SwRangeRedline on its anchor point)
355 if ( IsRedlineOn() && nAnchorType != RndStdIds::FLY_AS_CHAR )
356 pFrameMgr->SetAnchor( RndStdIds::FLY_AS_CHAR );
358 // Insert the graphic
359 SwFEShell::Insert(rPath, rFilter, &rGrf, &pFrameMgr->GetAttrSet());
360 if ( bOwnMgr )
361 pFrameMgr->UpdateAttrMgr();
363 if( bSetGrfSize )
365 Size aSizePixel = rGrf.GetSizePixel();
366 Size aBound = GetGraphicDefaultSize();
368 sal_Int32 nPreferredDPI = mxDoc->getIDocumentSettingAccess().getImagePreferredDPI();
369 Size aGrfSize;
371 if (nPreferredDPI > 0)
373 auto nWidth = o3tl::toTwips(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in);
374 auto nHeight = o3tl::toTwips(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in);
375 aGrfSize = Size(nWidth, nHeight);
377 else
379 GetGrfSize(aGrfSize);
382 // Add the margin attributes to GrfSize,
383 // because these counts at the margin additionally
384 aGrfSize.AdjustWidth(pFrameMgr->CalcWidthBorder() );
385 aGrfSize.AdjustHeight(pFrameMgr->CalcHeightBorder() );
387 const BigInt aTempWidth( aGrfSize.Width() );
388 const BigInt aTempHeight( aGrfSize.Height());
390 // Fit width if necessary, scale down the height proportional thereafter.
391 if( aGrfSize.Width() > aBound.Width() )
393 aGrfSize.setWidth( aBound.Width() );
394 aGrfSize.setHeight( BigInt(aBound.Width()) * aTempHeight / aTempWidth );
396 // Fit height if necessary, scale down the width proportional thereafter.
397 if( aGrfSize.Height() > aBound.Height() )
399 aGrfSize.setHeight( aBound.Height() );
400 aGrfSize.setWidth( BigInt(aBound.Height()) * aTempWidth / aTempHeight );
402 pFrameMgr->SetSize( aGrfSize );
403 pFrameMgr->UpdateFlyFrame();
405 if ( bOwnMgr )
406 delete pFrameMgr;
408 EndUndo();
409 EndAllAction();
412 // Insert an OLE-Object into the CORE.
413 // if no object is transferred, then one will be created.
415 void SwWrtShell::InsertObject( const svt::EmbeddedObjectRef& xRef, SvGlobalName const *pName,
416 sal_uInt16 nSlotId )
418 ResetCursorStack();
419 if( !CanInsert() )
420 return;
422 if( !xRef.is() )
424 // temporary storage
425 svt::EmbeddedObjectRef xObj;
426 uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetTemporaryStorage();
427 bool bDoVerb = true;
428 if ( pName )
430 comphelper::EmbeddedObjectContainer aCnt( xStor );
431 OUString aName;
432 // TODO/LATER: get aspect?
433 xObj.Assign( aCnt.CreateEmbeddedObject( pName->GetByteSequence(), aName ), embed::Aspects::MSOLE_CONTENT );
435 else
437 SvObjectServerList aServerList;
438 switch (nSlotId)
440 case SID_INSERT_OBJECT:
442 if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
444 std::unique_ptr<weld::MessageDialog> xError(
445 Application::CreateMessageDialog(
446 nullptr, VclMessageType::Warning, VclButtonsType::Ok,
447 SvtResId(STR_WARNING_ACTIVE_CONTENT_DISABLED)));
448 xError->run();
449 break;
451 aServerList.FillInsertObjects();
452 aServerList.Remove( SwDocShell::Factory().GetClassId() );
453 [[fallthrough]];
456 // TODO/LATER: recording! Convert properties to items
457 case SID_INSERT_FLOATINGFRAME:
459 SfxSlotPool* pSlotPool = SwModule::get()->GetSlotPool();
460 const SfxSlot* pSlot = pSlotPool->GetSlot(nSlotId);
461 OUString aCmd = pSlot->GetCommand();
462 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
463 ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(pFact->CreateInsertObjectDialog(GetFrameWeld(mxDoc->GetDocShell()),
464 aCmd, xStor, &aServerList));
465 if (pDlg)
467 pDlg->Execute();
468 bDoVerb = pDlg->IsCreateNew();
469 OUString aIconMediaType;
470 uno::Reference< io::XInputStream > xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
471 xObj.Assign( pDlg->GetObject(),
472 xIconMetaFile.is() ? embed::Aspects::MSOLE_ICON : embed::Aspects::MSOLE_CONTENT );
473 if ( xIconMetaFile.is() )
474 xObj.SetGraphicStream( xIconMetaFile, aIconMediaType );
477 break;
480 default:
481 break;
485 if ( xObj.is() )
487 if( InsertOleObject( xObj ) && bDoVerb )
489 SfxInPlaceClient* pClient = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
490 if ( !pClient )
492 pClient = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
493 SetCheckForOLEInCaption( true );
496 if ( xObj.GetViewAspect() == embed::Aspects::MSOLE_ICON )
498 SwRect aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
499 aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
500 MapMode aMapMode( MapUnit::MapTwip );
501 Size aSize = xObj.GetSize( &aMapMode );
502 aArea.Width( aSize.Width() );
503 aArea.Height( aSize.Height() );
504 RequestObjectResize( aArea, xObj.GetObject() );
506 else
507 CalcAndSetScale( xObj );
509 //#50270# We don't need to handle error, this is handled by the
510 //DoVerb in the SfxViewShell
511 pClient->DoVerb(embed::EmbedVerbs::MS_OLEVERB_SHOW);
513 // TODO/LATER: set document name - should be done in Client
517 else
519 if( HasSelection() )
520 DelRight();
521 InsertOleObject( xRef );
525 // Insert object into the Core.
526 // From ClipBoard or Insert
528 bool SwWrtShell::InsertOleObject( const svt::EmbeddedObjectRef& xRef, SwFlyFrameFormat **pFlyFrameFormat )
530 //tdf#125100 Ensure that ole object is initially shown as pictogram
531 comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mxDoc->GetDocShell()->getEmbeddedObjectContainer();
532 bool bSaveUserAllowsLinkUpdate = rEmbeddedObjectContainer.getUserAllowsLinkUpdate();
533 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
535 ResetCursorStack();
536 StartAllAction();
538 StartUndo(SwUndoId::INSERT);
540 //Some differences between StarMath and any other objects:
541 //1. Selections should be deleted. For StarMath the Text should be
542 // passed to the Object
543 //2. If the cursor is at the end of a non empty paragraph a paragraph
544 // break should be inserted. StarMath objects are character bound and
545 // no break should be inserted.
546 //3. If an selection is passed to a StarMath object, this object should
547 // not be activated. false should be returned then.
548 bool bStarMath = true;
549 bool bActivate = true;
551 // set parent to get correct VisArea(in case of object needing parent printer)
552 uno::Reference < container::XChild > xChild( xRef.GetObject(), uno::UNO_QUERY );
553 if ( xChild.is() )
554 xChild->setParent( mxDoc->GetDocShell()->GetModel() );
556 SvGlobalName aCLSID( xRef->getClassID() );
557 bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
558 if( IsSelection() )
560 if( bStarMath )
562 OUString aMathData;
563 GetSelectedText( aMathData, ParaBreakType::ToOnlyCR );
565 if( !aMathData.isEmpty() && svt::EmbeddedObjectRef::TryRunningState( xRef.GetObject() ) )
567 uno::Reference < beans::XPropertySet > xSet( xRef->getComponent(), uno::UNO_QUERY );
568 if ( xSet.is() )
572 xSet->setPropertyValue(u"Formula"_ustr, uno::Any( aMathData ) );
573 bActivate = false;
575 catch (const uno::Exception&)
581 DelRight();
584 if ( !bStarMath )
585 SwFEShell::SplitNode( false, false );
587 EnterSelFrameMode();
589 const SvGlobalName* pName = nullptr;
590 SvGlobalName aObjClsId;
591 if (xRef.is())
593 aObjClsId = SvGlobalName(xRef.GetObject()->getClassID());
594 pName = &aObjClsId;
596 SwFlyFrameAttrMgr aFrameMgr( true, this, Frmmgr_Type::OLE, pName );
597 aFrameMgr.SetHeightSizeType(SwFrameSize::Fixed);
599 SwRect aBound;
600 CalcBoundRect( aBound, aFrameMgr.GetAnchor() );
602 //The Size should be suggested by the OLE server
603 MapMode aMapMode( MapUnit::MapTwip );
604 Size aSz = xRef.GetSize( &aMapMode );
606 //Object size can be limited
607 if ( aSz.Width() > aBound.Width() )
609 //Always limit proportional.
610 aSz.setHeight( aSz.Height() * aBound.Width() / aSz.Width() );
611 aSz.setWidth( aBound.Width() );
613 aFrameMgr.SetSize( aSz );
614 SwFlyFrameFormat *pFormat = SwFEShell::InsertObject( xRef, &aFrameMgr.GetAttrSet() );
616 // --> #i972#
617 if ( bStarMath && mxDoc->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT ) )
618 AlignFormulaToBaseline( xRef.GetObject() );
620 if (pFlyFrameFormat)
621 *pFlyFrameFormat = pFormat;
623 if ( SotExchange::IsChart( aCLSID ) )
625 const uno::Reference< embed::XEmbeddedObject >& xEmbeddedObj = xRef.GetObject();
626 if ( xEmbeddedObj.is() )
628 bool bDisableDataTableDialog = false;
629 svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
630 uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
631 if ( xProps.is() &&
632 ( xProps->getPropertyValue(u"DisableDataTableDialog"_ustr) >>= bDisableDataTableDialog ) &&
633 bDisableDataTableDialog )
635 xProps->setPropertyValue(u"DisableDataTableDialog"_ustr,
636 uno::Any( false ) );
637 xProps->setPropertyValue(u"DisableComplexChartTypes"_ustr,
638 uno::Any( false ) );
639 uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY );
640 if ( xModifiable.is() )
642 xModifiable->setModified( true );
648 EndAllAction();
649 GetView().AutoCaption(OLE_CAP, &aCLSID);
651 SwRewriter aRewriter;
653 if ( bStarMath )
654 aRewriter.AddRule(UndoArg1, SwResId(STR_MATH_FORMULA));
655 else if ( SotExchange::IsChart( aCLSID ) )
656 aRewriter.AddRule(UndoArg1, SwResId(STR_CHART));
657 else
658 aRewriter.AddRule(UndoArg1, SwResId(STR_OLE));
660 EndUndo(SwUndoId::INSERT, &aRewriter);
662 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(bSaveUserAllowsLinkUpdate);
664 return bActivate;
667 // The current selected OLE object will be loaded with the
668 // verb into the server.
669 void SwWrtShell::LaunchOLEObj(sal_Int32 nVerb)
671 if ( GetCntType() != CNT_OLE ||
672 GetView().GetViewFrame().GetFrame().IsInPlace() )
673 return;
675 svt::EmbeddedObjectRef& xRef = GetOLEObject();
676 OSL_ENSURE( xRef.is(), "OLE not found" );
678 // LOK: we don't want to handle any other embedded objects than
679 // charts, there are too many problems with eg. embedded spreadsheets
680 // (like it creates a separate view for the calc sheet)
681 if (comphelper::LibreOfficeKit::isActive())
683 const auto classId = xRef->getClassID();
684 if (!SotExchange::IsChart(classId) && !SotExchange::IsMath(classId))
685 return;
688 SfxInPlaceClient* pCli = GetView().FindIPClient( xRef.GetObject(), &GetView().GetEditWin() );
689 if ( !pCli )
690 pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xRef );
692 uno::Reference<lang::XInitialization> xOLEInit(xRef.GetObject(), uno::UNO_QUERY);
693 if (xOLEInit.is())
695 uno::Sequence<beans::PropertyValue> aArguments
696 = { comphelper::makePropertyValue(u"ReadOnly"_ustr, pCli->IsProtected()) };
697 xOLEInit->initialize({ uno::Any(aArguments) });
700 static_cast<SwOleClient*>(pCli)->SetInDoVerb( true );
702 CalcAndSetScale( xRef );
703 pCli->DoVerb( nVerb );
705 static_cast<SwOleClient*>(pCli)->SetInDoVerb( false );
706 CalcAndSetScale( xRef );
709 void SwWrtShell::MoveObjectIfActive( svt::EmbeddedObjectRef& xObj, const Point& rOffset )
713 sal_Int32 nState = xObj->getCurrentState();
714 if ( nState == css::embed::EmbedStates::INPLACE_ACTIVE
715 || nState == css::embed::EmbedStates::UI_ACTIVE )
717 SfxInPlaceClient* pCli =
718 GetView().FindIPClient( xObj.GetObject(), &(GetView().GetEditWin()) );
719 if ( pCli )
721 tools::Rectangle aArea = pCli->GetObjArea();
722 aArea += rOffset;
723 pCli->SetObjArea( aArea );
727 catch (const uno::Exception&)
732 void SwWrtShell::CalcAndSetScale( svt::EmbeddedObjectRef& xObj,
733 const SwRect *pFlyPrtRect,
734 const SwRect *pFlyFrameRect,
735 const bool bNoTextFramePrtAreaChanged )
737 // Setting the scale of the client. This arises from the difference
738 // between the VisArea of the object and the ObjArea.
739 OSL_ENSURE( xObj.is(), "ObjectRef not valid" );
741 sal_Int64 nAspect = xObj.GetViewAspect();
742 if ( nAspect == embed::Aspects::MSOLE_ICON )
743 return; // the replacement image is completely controlled by container in this case
745 sal_Int64 nMisc = 0;
746 bool bLinkingChart = false;
750 nMisc = xObj->getStatus( nAspect );
752 // This can surely only be a non-active object, if desired they
753 // get the new size set as VisArea (StarChart).
754 if( embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE & nMisc )
756 // TODO/MBA: testing
757 SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
758 : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
759 if( !aRect.IsEmpty() )
761 // TODO/LEAN: getMapUnit can switch object to running state
762 // xObj.TryRunningState();
764 MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
766 // TODO/LATER: needs complete VisArea?!
767 Size aSize( OutputDevice::LogicToLogic(aRect.SVRect(), MapMode(MapUnit::MapTwip), MapMode(aUnit)).GetSize() );
768 awt::Size aSz;
769 aSz.Width = aSize.Width();
770 aSz.Height = aSize.Height();
772 // Action 'setVisualAreaSize' doesn't have to turn on the
773 // modified state of the document, either.
774 bool bModified = false;
775 uno::Reference<util::XModifiable> xModifiable(xObj->getComponent(), uno::UNO_QUERY);
776 if (xModifiable.is())
777 bModified = xModifiable->isModified();
778 xObj->setVisualAreaSize( nAspect, aSz );
779 xModifiable.set(xObj->getComponent(), uno::UNO_QUERY);
780 if (xModifiable.is() && xModifiable->isModified() && !bModified)
781 xModifiable->setModified(bModified);
783 // #i48419# - action 'UpdateReplacement' doesn't
784 // have to change the modified state of the document.
785 // This is only a workaround for the defect, that this action
786 // modifies a document after load, because unnecessarily the
787 // replacement graphic is updated, in spite of the fact that
788 // nothing has been changed.
789 // If the replacement graphic changes by this action, the document
790 // will be already modified via other mechanisms.
792 bool bResetEnableSetModified(false);
793 if ( GetDoc()->GetDocShell()->IsEnableSetModified() )
795 GetDoc()->GetDocShell()->EnableSetModified( false );
796 bResetEnableSetModified = true;
799 //#i79576# don't destroy chart replacement images on load
800 //#i79578# don't request a new replacement image for charts to often
801 //a chart sends a modified call to the framework if it was changed
802 //thus the replacement update is already handled elsewhere
803 if ( !SotExchange::IsChart( xObj->getClassID() ) )
804 xObj.UpdateReplacement();
806 if ( bResetEnableSetModified )
808 GetDoc()->GetDocShell()->EnableSetModified();
813 // TODO/LATER: this is only a workaround,
814 uno::Reference< chart2::XChartDocument > xChartDocument( xObj->getComponent(), uno::UNO_QUERY );
815 bLinkingChart = ( xChartDocument.is() && !xChartDocument->hasInternalDataProvider() );
818 catch (const uno::Exception&)
820 // TODO/LATER: handle the error
821 return;
824 SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
825 if ( !pCli )
827 if ( (embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY & nMisc)
828 || bLinkingChart
829 // --> OD #i117189# - refine condition for non-resizable objects
830 // non-resizable objects need to be set the size back by this method
831 || ( bNoTextFramePrtAreaChanged && nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
833 pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
835 else
836 return;
839 // TODO/LEAN: getMapUnit can switch object to running state
840 // xObj.TryRunningState();
842 awt::Size aSize;
845 aSize = xObj->getVisualAreaSize( nAspect );
847 catch (const embed::NoVisualAreaSizeException&)
849 OSL_FAIL("Can't get visual area size!" );
850 // the scaling will not be done
852 catch (const uno::Exception&)
854 // TODO/LATER: handle the error
855 OSL_FAIL("Can't get visual area size!" );
856 return;
859 Size _aVisArea( aSize.Width, aSize.Height );
861 Fraction aScaleWidth( 1, 1 );
862 Fraction aScaleHeight( 1, 1 );
864 bool bUseObjectSize = false;
866 // As long as there comes no reasonable size from the object,
867 // nothing can be scaled.
868 if( _aVisArea.Width() && _aVisArea.Height() )
870 const MapMode aTmp( MapUnit::MapTwip );
871 MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
872 _aVisArea = OutputDevice::LogicToLogic(_aVisArea, MapMode(aUnit), aTmp);
873 Size aObjArea;
874 if ( pFlyPrtRect )
875 aObjArea = pFlyPrtRect->SSize();
876 else
877 aObjArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ).SSize();
879 // differ the aObjArea and _aVisArea by 1 Pixel then set new VisArea
880 tools::Long nX, nY;
881 SwSelPaintRects::Get1PixelInLogic( *this, &nX, &nY );
882 if( !( _aVisArea.Width() - nX <= aObjArea.Width() &&
883 _aVisArea.Width() + nX >= aObjArea.Width() &&
884 _aVisArea.Height()- nY <= aObjArea.Height()&&
885 _aVisArea.Height()+ nY >= aObjArea.Height() ))
887 if ( nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE )
889 // the object must not be scaled,
890 // the size stored in object must be used for restoring
891 bUseObjectSize = true;
893 else
895 aScaleWidth = Fraction( aObjArea.Width(), _aVisArea.Width() );
896 aScaleHeight = Fraction( aObjArea.Height(), _aVisArea.Height());
901 // Now is the favorable time to set the ObjArea.
902 // The Scaling must be considered.
903 SwRect aArea;
904 if ( pFlyPrtRect )
906 aArea = *pFlyPrtRect;
907 aArea += pFlyFrameRect->Pos();
909 else
911 aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
912 aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
915 if ( bUseObjectSize )
917 // --> this moves non-resizable object so that when adding borders the baseline remains the same
918 const SwFlyFrameFormat *pFlyFrameFormat = dynamic_cast< const SwFlyFrameFormat * >( GetFlyFrameFormat() );
919 OSL_ENSURE( pFlyFrameFormat, "Could not find fly frame." );
920 if ( pFlyFrameFormat )
922 const Point &rPoint = pFlyFrameFormat->GetLastFlyFramePrtRectPos();
923 SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
924 : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
925 aArea += rPoint - aRect.Pos(); // adjust area by diff of printing area position in order to keep baseline alignment correct.
927 aArea.Width ( _aVisArea.Width() );
928 aArea.Height( _aVisArea.Height() );
929 RequestObjectResize( aArea, xObj.GetObject() );
931 else
933 double nWidth(pCli->GetScaleWidth());
934 double nHeight(pCli->GetScaleHeight());
935 if (nWidth && nHeight)
937 aArea.Width ( aArea.Width() / nWidth );
938 aArea.Height( aArea.Height() / nHeight );
942 pCli->SetObjAreaAndScale( aArea.SVRect(), aScaleWidth, aScaleHeight );
945 void SwWrtShell::ConnectObj( svt::EmbeddedObjectRef& xObj, const SwRect &rPrt,
946 const SwRect &rFrame )
948 SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin());
949 if ( !pCli )
950 new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
951 CalcAndSetScale( xObj, &rPrt, &rFrame );
954 // Insert hard page break;
955 // Selections will be overwritten
956 void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optional<sal_uInt16>& oPgNum )
958 if (!lcl_IsAllowed(this))
959 return;
961 ResetCursorStack();
962 if( CanInsert() )
964 SwActContext aActContext(this);
965 StartUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
967 if ( !IsCursorInTable() )
969 if(HasSelection())
970 DelRight();
971 SwFEShell::SplitNode();
972 // delete the numbered attribute of the last line if the last line is empty
973 GetDoc()->ClearLineNumAttrs( *GetCursor()->GetPoint() );
976 const SwPageDesc *pDesc = pPageDesc
977 ? FindPageDescByName( *pPageDesc, true ) : nullptr;
978 if( pDesc )
980 SwFormatPageDesc aDesc( pDesc );
981 aDesc.SetNumOffset( oPgNum );
982 SetAttrItem( aDesc );
984 else
985 SetAttrItem( SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK) );
986 EndUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
988 collectUIInformation(u"BREAK_PAGE"_ustr, u"parameter"_ustr);
991 // Insert enclosing characters
992 // Selections will be overwritten
993 void SwWrtShell::InsertEnclosingChars(std::u16string_view sStartStr, std::u16string_view sEndStr)
995 for (SwPaM& rPaM : SwWrtShell::GetCursor()->GetRingContainer())
997 const OUString aStr = sStartStr + rPaM.GetText() + sEndStr;
998 SwViewShell::getIDocumentContentOperations().ReplaceRange(rPaM, aStr, false);
1002 // Insert hard page break;
1003 // Selections will be overwritten
1005 void SwWrtShell::InsertLineBreak(std::optional<SwLineBreakClear> oClear)
1007 if (!lcl_IsAllowed(this))
1008 return;
1010 ResetCursorStack();
1011 if( CanInsert() )
1013 if(HasSelection())
1014 DelRight();
1016 const sal_Unicode cIns = 0x0A;
1017 SwLineBreakClear eClear = SwLineBreakClear::NONE;
1018 if (oClear.has_value())
1020 eClear = *oClear;
1022 SvxAutoCorrect* pACorr = lcl_IsAutoCorr();
1023 if (pACorr && eClear == SwLineBreakClear::NONE)
1024 AutoCorrect( *pACorr, cIns );
1025 else
1027 if (eClear == SwLineBreakClear::NONE)
1029 SwWrtShell::Insert(OUString(cIns));
1031 else
1033 SwFormatLineBreak aLineBreak(eClear);
1034 SetAttrItem(aLineBreak);
1040 // Insert hard column break;
1041 // Selections will be overwritten
1043 void SwWrtShell::InsertColumnBreak()
1045 if (!lcl_IsAllowed(this))
1046 return;
1048 SwActContext aActContext(this);
1049 ResetCursorStack();
1050 if( !CanInsert() )
1051 return;
1053 StartUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
1055 if ( !IsCursorInTable() )
1057 if(HasSelection())
1058 DelRight();
1059 SwFEShell::SplitNode( false, false );
1061 SetAttrItem(SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
1063 EndUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
1066 void SwWrtShell::InsertContentControl(SwContentControlType eType)
1068 if (!lcl_IsAllowed(this))
1070 return;
1073 ResetCursorStack();
1074 if (!CanInsert())
1076 return;
1079 auto pContentControl = std::make_shared<SwContentControl>(nullptr);
1081 // Make Random ID... check if it is unique
1082 // warning: possible infinite loop if there would be billions of content controls.
1083 SwContentControlManager& pManager = GetDoc()->GetContentControlManager();
1084 size_t nCCCount = pManager.GetCount();
1085 sal_Int32 nIdToCheck;
1086 nIdToCheck
1087 = comphelper::rng::uniform_uint_distribution(1, std::numeric_limits<sal_Int32>::max());
1088 size_t nIdx = 0;
1089 while (nIdx < nCCCount)
1091 sal_Int32 nID
1092 = pManager.UnsortedGet(nIdx)->GetContentControl().GetContentControl()->GetId();
1093 if (nID == nIdToCheck)
1095 nIdToCheck = comphelper::rng::uniform_uint_distribution(
1096 1, std::numeric_limits<sal_Int32>::max());
1097 nIdx = 0;
1099 else
1100 nIdx++;
1102 pContentControl->SetId(nIdToCheck);
1104 OUString aPlaceholder;
1105 switch (eType)
1107 case SwContentControlType::RICH_TEXT:
1108 case SwContentControlType::PLAIN_TEXT:
1110 pContentControl->SetShowingPlaceHolder(true);
1111 if (eType == SwContentControlType::PLAIN_TEXT)
1113 pContentControl->SetPlainText(true);
1115 if (!HasSelection())
1117 aPlaceholder = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER);
1119 break;
1121 case SwContentControlType::CHECKBOX:
1123 pContentControl->SetCheckbox(true);
1124 // Ballot Box with X
1125 pContentControl->SetCheckedState(u"\u2612"_ustr);
1126 // Ballot Box
1127 pContentControl->SetUncheckedState(u"\u2610"_ustr);
1128 aPlaceholder = u"\u2610"_ustr;
1129 break;
1131 case SwContentControlType::COMBO_BOX:
1132 case SwContentControlType::DROP_DOWN_LIST:
1134 if (eType == SwContentControlType::COMBO_BOX)
1136 pContentControl->SetComboBox(true);
1138 else if (eType == SwContentControlType::DROP_DOWN_LIST)
1140 pContentControl->SetDropDown(true);
1143 pContentControl->SetShowingPlaceHolder(true);
1144 if (!HasSelection())
1146 aPlaceholder = SwResId(STR_DROPDOWN_CONTENT_CONTROL_PLACEHOLDER);
1148 SwContentControlListItem aListItem;
1149 aListItem.m_aValue = aPlaceholder;
1150 pContentControl->SetListItems({ std::move(aListItem) });
1151 break;
1153 case SwContentControlType::PICTURE:
1155 // Set up the picture content control.
1156 pContentControl->SetShowingPlaceHolder(true);
1157 pContentControl->SetPicture(true);
1159 // Create the placeholder bitmap.
1160 BitmapEx aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
1161 Color aColor = SvtOptionsDrawinglayer::getHilightColor();
1162 aColor.IncreaseLuminance(255 * 0.75);
1163 aBitmap.Erase(aColor);
1164 SwRewriter aRewriter;
1165 aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME));
1166 StartUndo(SwUndoId::INSERT, &aRewriter);
1167 LockPaint(LockPaintReason::InsertGraphic);
1168 StartAction();
1169 InsertGraphic(OUString(), OUString(), aBitmap, nullptr, RndStdIds::FLY_AS_CHAR);
1171 // Set properties on the bitmap.
1172 SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet(GetDoc()->GetAttrPool());
1173 GetFlyFrameAttr(aSet);
1174 SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000);
1175 aSet.Put(aSize);
1176 SetFlyFrameAttr(aSet);
1177 SwFrameFormat* pFrameFormat = GetFlyFrameFormat();
1178 EndAction();
1179 UnlockPaint();
1180 EndUndo();
1182 // Go after the anchor position.
1183 UnSelectFrame();
1184 LeaveSelFrameMode();
1186 SwCursor* pCursor = getShellCursor(true);
1187 pCursor->DeleteMark();
1188 const SwFormatAnchor& rFormatAnchor = pFrameFormat->GetAnchor();
1189 pCursor->GetPoint()->Assign( *rFormatAnchor.GetAnchorContentNode(), rFormatAnchor.GetAnchorContentOffset() + 1);
1192 // Select before the anchor position.
1193 Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1194 break;
1196 case SwContentControlType::DATE:
1198 pContentControl->SetShowingPlaceHolder(true);
1199 pContentControl->SetDate(true);
1200 SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
1201 sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
1202 const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);
1203 pContentControl->SetDateFormat(pFormat->GetFormatstring());
1204 pContentControl->SetDateLanguage(LanguageTag(pFormat->GetLanguage()).getBcp47());
1205 if (!HasSelection())
1207 aPlaceholder = SwResId(STR_DATE_CONTENT_CONTROL_PLACEHOLDER);
1209 break;
1212 if (aPlaceholder.getLength())
1214 Insert(aPlaceholder);
1215 Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(),
1216 /*bBasicCall=*/false);
1219 const RedlineFlags oldRedlineFlags = getIDocumentRedlineAccess().GetRedlineFlags();
1220 getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::Ignore);
1221 SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL);
1222 SetAttrItem(aContentControl);
1223 getIDocumentRedlineAccess().SetRedlineFlags(oldRedlineFlags);
1226 // Insert footnote
1227 // rStr - optional footnote mark
1229 void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit )
1231 ResetCursorStack();
1232 if( !CanInsert() )
1233 return;
1235 if(HasSelection())
1237 //collapse cursor to the end
1238 if(!IsCursorPtAtEnd())
1239 SwapPam();
1240 ClearMark();
1242 SwPosition aPos = *GetCursor()->GetPoint();
1243 SwFormatFootnote aFootNote( bEndNote );
1244 if(!rStr.isEmpty())
1245 aFootNote.SetNumStr( rStr );
1247 SetAttrItem(aFootNote);
1249 if( bEdit )
1251 // For editing the footnote text.
1252 Left(SwCursorSkipMode::Chars, false, 1, false );
1253 GotoFootnoteText();
1255 m_aNavigationMgr.addEntry(aPos);
1258 // tdf#141634
1259 static bool lcl_FoldedOutlineNodeEndOfParaSplit(SwWrtShell *pThis)
1261 SwTextNode* pTextNode = pThis->GetCursor()->GetPointNode().GetTextNode();
1262 if (pTextNode && pTextNode->IsOutline())
1264 if (!pTextNode->GetAttrOutlineContentVisible())
1266 const SwNodes& rNodes = pThis->GetNodes();
1267 const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
1268 SwOutlineNodes::size_type nPos;
1269 (void) rOutlineNodes.Seek_Entry(pTextNode, &nPos);
1271 SwNode* pSttNd = rOutlineNodes[nPos];
1273 // determine end node of folded outline content
1274 SwNode* pEndNd = &rNodes.GetEndOfContent();
1275 if (rOutlineNodes.size() > nPos + 1)
1276 pEndNd = rOutlineNodes[nPos + 1];
1278 if (pThis->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
1280 // get the next outline node after the folded outline content (iPos)
1281 // it is the next outline node with the same level or less
1282 int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
1283 SwOutlineNodes::size_type iPos = nPos;
1284 while (++iPos < rOutlineNodes.size() &&
1285 rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel);
1287 // get the correct end node
1288 // the outline node may be in frames, headers, footers special section of doc model
1289 SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
1290 while (pStartOfSectionNodeSttNd->StartOfSectionNode()
1291 != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
1293 pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
1295 pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
1297 if (iPos < rOutlineNodes.size())
1299 SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
1300 while (pStartOfSectionNode->StartOfSectionNode()
1301 != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
1303 pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
1305 if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
1306 pEndNd = rOutlineNodes[iPos];
1310 // table, text box, header, footer
1311 if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
1313 // insert before section end node
1314 if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
1316 SwNodeIndex aIdx(*pSttNd->EndOfSectionNode());
1317 while (aIdx.GetNode().IsEndNode())
1318 --aIdx;
1319 ++aIdx;
1320 pEndNd = &aIdx.GetNode();
1323 // if pSttNd isn't in table but pEndNd is then insert after table
1324 else if (pEndNd->GetTableBox())
1326 pEndNd = pEndNd->FindTableNode();
1327 SwNodeIndex aIdx(*pEndNd, -1);
1328 // account for nested tables
1329 while (aIdx.GetNode().GetTableBox())
1331 pEndNd = aIdx.GetNode().FindTableNode();
1332 aIdx.Assign(*pEndNd, -1);
1334 aIdx.Assign(*pEndNd->EndOfSectionNode(), +1);
1335 pEndNd = &aIdx.GetNode();
1337 // end node determined
1339 // now insert the new outline node
1340 SwDoc* pDoc = pThis->GetDoc();
1342 // insert at end of tablebox doesn't work correct without
1343 MakeAllOutlineContentTemporarilyVisible a(pDoc);
1345 SwTextNode* pNd = pDoc->GetNodes().MakeTextNode(*pEndNd, pTextNode->GetTextColl(), true);
1347 (void) rOutlineNodes.Seek_Entry(pNd, &nPos);
1348 pThis->GotoOutline(nPos);
1350 if (pDoc->GetIDocumentUndoRedo().DoesUndo())
1352 pDoc->GetIDocumentUndoRedo().ClearRedo();
1353 pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsert>(*pNd));
1354 pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoFormatColl>
1355 (SwPaM(*pNd), pNd->GetTextColl(), true, true));
1358 pThis->SetModified();
1359 return true;
1362 return false;
1365 // SplitNode; also, because
1366 // - of deleting selected content;
1367 // - of reset of the Cursorstack if necessary.
1369 void SwWrtShell::SplitNode( bool bAutoFormat )
1371 ResetCursorStack();
1372 if( !CanInsert() )
1373 return;
1375 SwActContext aActContext(this);
1377 m_rView.GetEditWin().FlushInBuffer();
1378 StartUndo(SwUndoId::SPLITNODE);
1380 bool bHasSel = HasSelection();
1381 if (bHasSel)
1382 DelRight();
1384 bool bHandled = false;
1385 if (GetViewOptions()->IsShowOutlineContentVisibilityButton() && IsEndPara())
1386 bHandled = lcl_FoldedOutlineNodeEndOfParaSplit(this);
1388 if (!bHandled)
1389 SwFEShell::SplitNode( bAutoFormat );
1391 EndUndo(SwUndoId::SPLITNODE);
1394 // Turn on numbering
1395 // Parameter: Optional specification of a name for the named list;
1396 // this indicates a position if it is possible to convert them
1397 // into a number and less than nMaxRules.
1399 // To test the CharFormats at the numbering
1400 // external void SetNumChrFormat( SwWrtShell*, SwNumRules& );
1402 // -> #i40041#
1403 // Preconditions (as far as OD has figured out):
1404 // - <SwEditShell::HasNumber()> is false, if <bNum> is true
1405 // - <SwEditShell::HasBullet()> is false, if <bNum> is false
1406 // Behavior of method is determined by the current situation at the current
1407 // cursor position in the document.
1408 void SwWrtShell::NumOrBulletOn(bool bNum)
1410 StartUndo(SwUndoId::NUMORNONUM);
1412 const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
1414 // - activate outline rule respectively turning on outline rule for
1415 // current text node. But, only for turning on a numbering (<bNum> == true).
1416 // - overwrite found numbering rule at current cursor position, if
1417 // no numbering rule can be retrieved from the paragraph style.
1418 bool bContinueFoundNumRule( false );
1419 bool bActivateOutlineRule( false );
1420 int nActivateOutlineLvl( MAXLEVEL ); // only relevant, if <bActivateOutlineRule> == true
1421 SwTextFormatColl * pColl = GetCurTextFormatColl();
1422 if ( pColl )
1424 // retrieve numbering rule at paragraph
1425 // style, which is found at current cursor position in the document.
1426 SwNumRule* pCollRule = mxDoc->FindNumRulePtr(pColl->GetNumRule().GetValue());
1427 // #125993# - The outline numbering rule isn't allowed
1428 // to be derived from a parent paragraph style to a derived one.
1429 // Thus check, if the found outline numbering rule is directly
1430 // set at the paragraph style <pColl>. If not, set <pCollRule> to NULL
1431 if ( pCollRule && pCollRule == GetDoc()->GetOutlineNumRule() )
1433 const SwNumRule* pDirectCollRule =
1434 mxDoc->FindNumRulePtr(pColl->GetNumRule( false ).GetValue());
1435 if ( !pDirectCollRule )
1437 pCollRule = nullptr;
1441 if ( !pCollRule )
1443 pNumRule = pCollRule;
1445 // no activation or continuation of outline numbering in Writer/Web document
1446 else if ( bNum &&
1447 !dynamic_cast<SwWebDocShell*>(GetDoc()->GetDocShell()) &&
1448 pCollRule == GetDoc()->GetOutlineNumRule() )
1450 if ( pNumRule == pCollRule )
1452 // check, if text node at current cursor positioned is counted.
1453 // If not, let it been counted. Then it has to be checked,
1454 // of the outline numbering has to be activated or continued.
1455 SwTextNode const*const pTextNode = sw::GetParaPropsNode(
1456 *GetLayout(), GetCursor()->GetPoint()->GetNode());
1457 if ( pTextNode && !pTextNode->IsCountedInList() )
1459 // check, if numbering of the outline level of the paragraph
1460 // style is active. If not, activate this outline level.
1461 nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1462 OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
1463 "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
1464 if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
1465 pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1466 == SVX_NUM_NUMBER_NONE )
1468 // activate outline numbering
1469 bActivateOutlineRule = true;
1471 else
1473 // turning on outline numbering at current cursor position
1474 bContinueFoundNumRule = true;
1477 else
1479 // #i101234#
1480 // activate outline numbering, because from the precondition
1481 // it's known, that <SwEdit::HasNumber()> == false
1482 bActivateOutlineRule = true;
1483 nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1486 else if ( !pNumRule )
1488 // #i101234#
1489 // Check, if corresponding list level of the outline numbering
1490 // has already a numbering format set.
1491 nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1492 if ( pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1493 == SVX_NUM_NUMBER_NONE )
1495 // activate outline numbering, because from the precondition
1496 // it's known, that <SwEdit::HasNumber()> == false
1497 bActivateOutlineRule = true;
1499 else
1501 // turning on outline numbering at current cursor position
1502 bContinueFoundNumRule = true;
1505 else
1507 // check, if numbering of the outline level of the paragraph
1508 // style is active. If not, activate this outline level.
1509 nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
1510 OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
1511 "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
1512 if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
1513 pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
1514 == SVX_NUM_NUMBER_NONE )
1516 // activate outline numbering
1517 bActivateOutlineRule = true;
1519 else
1521 // turning on outline numbering at current cursor position
1522 bContinueFoundNumRule = true;
1525 pNumRule = pCollRule;
1529 // Only automatic numbering/bullet rules should be changed.
1530 // Note: The outline numbering rule is also an automatic one. It's only
1531 // changed, if it has to be activated.
1532 if ( pNumRule )
1534 if ( !pNumRule->IsAutoRule() )
1536 pNumRule = nullptr;
1538 else if ( pNumRule == GetDoc()->GetOutlineNumRule() &&
1539 !bActivateOutlineRule && !bContinueFoundNumRule )
1541 pNumRule = nullptr;
1545 // Search for a previous numbering/bullet rule to continue it.
1546 OUString sContinuedListId;
1547 if ( !pNumRule )
1549 pNumRule = GetDoc()->SearchNumRule( *GetCursor()->GetPoint(),
1550 false, bNum, false, 0,
1551 sContinuedListId, GetLayout() );
1552 bContinueFoundNumRule = pNumRule != nullptr;
1555 if (pNumRule)
1557 SwNumRule aNumRule(*pNumRule);
1559 // do not change found numbering/bullet rule, if it should only be continued.
1560 if ( !bContinueFoundNumRule )
1562 SwTextNode const*const pTextNode = sw::GetParaPropsNode(
1563 *GetLayout(), GetCursor()->GetPoint()->GetNode());
1565 if (pTextNode)
1567 // use above retrieve outline level, if outline numbering has to be activated.
1568 int nLevel = bActivateOutlineRule
1569 ? nActivateOutlineLvl
1570 : pTextNode->GetActualListLevel();
1572 if (nLevel < 0)
1573 nLevel = 0;
1575 if (nLevel >= MAXLEVEL)
1576 nLevel = MAXLEVEL - 1;
1578 SwNumFormat aFormat(aNumRule.Get(o3tl::narrowing<sal_uInt16>(nLevel)));
1580 if (bNum)
1581 aFormat.SetNumberingType(SVX_NUM_ARABIC);
1582 else
1584 // #i63395# Only apply user defined default bullet font
1585 if ( numfunc::IsDefBulletFontUserDefined() )
1587 const vcl::Font* pFnt = &numfunc::GetDefBulletFont();
1588 aFormat.SetBulletFont( pFnt );
1590 aFormat.SetBulletChar( numfunc::GetBulletChar(static_cast<sal_uInt8>(nLevel)));
1591 aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1592 // #i93908# clear suffix for bullet lists
1593 aFormat.SetListFormat(u""_ustr, u""_ustr, nLevel);
1595 aNumRule.Set(o3tl::narrowing<sal_uInt16>(nLevel), aFormat);
1599 // reset indent attribute on applying list style
1600 SetCurNumRule( aNumRule, false, sContinuedListId, true );
1602 else
1604 // #i95907#
1605 const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
1606 numfunc::GetDefaultPositionAndSpaceMode() );
1607 SwNumRule aNumRule( GetUniqueNumRuleName(), ePosAndSpaceMode );
1608 // Append the character template at the numbering.
1609 SwCharFormat* pChrFormat;
1610 SwDocShell* pDocSh = GetView().GetDocShell();
1612 if (bNum)
1614 pChrFormat = GetCharFormatFromPool( RES_POOLCHR_NUM_LEVEL );
1616 else
1618 pChrFormat = GetCharFormatFromPool( RES_POOLCHR_BULLET_LEVEL );
1621 const SwTextNode *const pTextNode = sw::GetParaPropsNode(*GetLayout(),
1622 GetCursor()->GetPoint()->GetNode());
1623 const SwTwips nWidthOfTabs = pTextNode
1624 ? pTextNode->GetWidthOfLeadingTabs()
1625 : 0;
1626 GetDoc()->getIDocumentContentOperations().RemoveLeadingWhiteSpace(*GetCursor());
1628 const bool bHtml = dynamic_cast<SwWebDocShell*>( pDocSh ) != nullptr;
1629 const bool bRightToLeft = IsInRightToLeftText();
1630 for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
1632 SwNumFormat aFormat( aNumRule.Get( nLvl ) );
1633 aFormat.SetCharFormat( pChrFormat );
1635 if (! bNum)
1637 uno::Sequence<OUString> aBulletSymbols(
1638 officecfg::Office::Common::BulletsNumbering::DefaultBullets::get());
1639 uno::Sequence<OUString> aBulletSymbolsFonts(
1640 officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::get());
1641 aFormat.SetBulletChar(aBulletSymbols[0].toChar());
1642 vcl::Font aFont;
1643 aFont.SetFamilyName(aBulletSymbolsFonts[0]);
1644 aFormat.SetBulletFont(&aFont);
1645 aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1646 // #i93908# clear suffix for bullet lists
1647 aFormat.SetListFormat(u""_ustr, u""_ustr, nLvl);
1650 // #i95907#
1651 if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1653 if(bHtml && nLvl)
1655 // 1/2" for HTML
1656 aFormat.SetAbsLSpace(nLvl * 720);
1658 else if ( nWidthOfTabs > 0 )
1660 aFormat.SetAbsLSpace(nWidthOfTabs + nLvl * 720);
1664 // #i38904# Default alignment for
1665 // numbering/bullet should be rtl in rtl paragraph:
1666 if ( bRightToLeft )
1668 aFormat.SetNumAdjust( SvxAdjust::Right );
1671 aNumRule.Set( nLvl, aFormat );
1674 // #i95907#
1675 if ( pTextNode &&
1676 ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
1679 const SwTwips nTextNodeIndent = pTextNode->GetAdditionalIndentForStartingNewList();
1680 if ( ( nTextNodeIndent + nWidthOfTabs ) != 0 )
1682 // #i111172#/fdo#85666
1683 // If text node is already inside a list, assure that the indents
1684 // are the same. Thus, adjust the indent change value by subtracting
1685 // indents of to be applied list style.
1686 SwTwips nIndentChange = nTextNodeIndent + nWidthOfTabs;
1687 if ( pTextNode->GetNumRule() )
1689 int nLevel = pTextNode->GetActualListLevel();
1691 if (nLevel < 0)
1692 nLevel = 0;
1694 if (nLevel >= MAXLEVEL)
1695 nLevel = MAXLEVEL - 1;
1697 const SwNumFormat& aFormat( aNumRule.Get( nLevel ) );
1698 if ( aFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1700 nIndentChange -= aFormat.GetIndentAt() + aFormat.GetFirstLineIndent();
1703 aNumRule.ChangeIndent( nIndentChange );
1706 // reset indent attribute on applying list style
1707 // start new list
1708 SetCurNumRule( aNumRule, true, OUString(), true );
1711 EndUndo(SwUndoId::NUMORNONUM);
1713 // <- #i40041#
1715 void SwWrtShell::NumOn()
1717 NumOrBulletOn(true);
1720 void SwWrtShell::NumOrBulletOff()
1722 const SwNumRule * pCurNumRule = GetNumRuleAtCurrCursorPos();
1724 if (!pCurNumRule)
1725 return;
1727 DelNumRules();
1729 // #126346# - Cursor can not be anymore in front of
1730 // a label, because numbering/bullet is switched off.
1731 SetInFrontOfLabel( false );
1733 // <- #i29560#
1735 // Request Default-Bulletlist
1737 void SwWrtShell::BulletOn()
1739 NumOrBulletOn(false);
1742 SelectionType SwWrtShell::GetSelectionType() const
1744 // ContentType cannot be determined within a Start-/EndAction.
1745 // Because there is no invalid value TEXT will be returned.
1746 // The value does not matter, it may be updated in EndAction anyway.
1748 if (ActionPend())
1749 return IsSelFrameMode() ? SelectionType::Frame : SelectionType::Text;
1751 SwView &_rView = const_cast<SwView&>(GetView());
1752 if (_rView.GetPostItMgr() && _rView.GetPostItMgr()->HasActiveSidebarWin() )
1753 return SelectionType::PostIt;
1755 // Inserting a frame is not a DrawMode
1756 SelectionType nCnt;
1757 if ( !_rView.GetEditWin().IsFrameAction() &&
1758 (GetSelectedObjCount() || (_rView.IsDrawMode() && !IsFrameSelected()) ))
1760 if (GetDrawView()->IsTextEdit())
1761 nCnt = SelectionType::DrawObjectEditMode;
1762 else
1764 if (GetView().IsFormMode()) // Only Form selected
1765 nCnt = SelectionType::DbForm;
1766 else
1767 nCnt = SelectionType::DrawObject; // Any draw object
1769 if (_rView.IsBezierEditMode())
1770 nCnt |= SelectionType::Ornament;
1771 else if( GetDrawView()->GetContext() == SdrViewContext::Media )
1772 nCnt |= SelectionType::Media;
1774 if (svx::checkForSelectedCustomShapes( GetDrawView(), true /* bOnlyExtruded */ ))
1776 nCnt |= SelectionType::ExtrudedCustomShape;
1779 if (svx::checkForSelectedFontWork( GetDrawView() ))
1781 nCnt |= SelectionType::FontWork;
1785 return nCnt;
1788 nCnt = static_cast<SelectionType>(GetCntType());
1790 if ( IsFrameSelected() )
1792 if (_rView.IsDrawMode())
1793 _rView.LeaveDrawCreate(); // clean up (Bug #45639)
1794 if ( !(nCnt & (SelectionType::Graphic | SelectionType::Ole)) )
1795 return SelectionType::Frame;
1798 if ( IsCursorInTable() )
1799 nCnt |= SelectionType::Table;
1801 if ( IsTableMode() )
1803 nCnt |= SelectionType::Table | SelectionType::TableCell;
1804 SwTable::SearchType eTableSel = GetEnhancedTableSelection();
1805 if ( eTableSel == SwTable::SEARCH_ROW )
1806 nCnt |= SelectionType::TableRow;
1807 else if ( eTableSel == SwTable::SEARCH_COL )
1808 nCnt |= SelectionType::TableCol;
1811 // Do not pop up numbering toolbar, if the text node has a numbering of type SVX_NUM_NUMBER_NONE.
1812 const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
1813 if ( pNumRule )
1815 const SwTextNode* pTextNd =
1816 sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->GetNode());
1818 if ( pTextNd && pTextNd->IsInList() )
1820 int nLevel = pTextNd->GetActualListLevel();
1822 if (nLevel < 0)
1823 nLevel = 0;
1825 if (nLevel >= MAXLEVEL)
1826 nLevel = MAXLEVEL - 1;
1828 const SwNumFormat& rFormat = pNumRule->Get(nLevel);
1829 if ( SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType() )
1830 nCnt |= SelectionType::NumberList;
1834 return nCnt;
1837 // Find the text collection with the name rCollname
1838 // Returns: Pointer at the collection or 0, if no
1839 // text collection with this name exists, or
1840 // this is a default template.
1842 SwTextFormatColl *SwWrtShell::GetParaStyle(const OUString &rCollName, GetStyle eCreate )
1844 SwTextFormatColl* pColl = FindTextFormatCollByName( rCollName );
1845 if( !pColl && GETSTYLE_NOCREATE != eCreate )
1847 sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCollName, SwGetPoolIdFromName::TxtColl );
1848 if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
1849 pColl = GetTextCollFromPool( nId );
1851 return pColl;
1854 // Find the text collection with the name rCollname
1855 // Returns: Pointer at the collection or 0, if no
1856 // character template with this name exists, or
1857 // this is a default template or template is automatic.
1859 SwCharFormat *SwWrtShell::GetCharStyle(const OUString &rFormatName, GetStyle eCreate )
1861 SwCharFormat* pFormat = FindCharFormatByName( rFormatName );
1862 if( !pFormat && GETSTYLE_NOCREATE != eCreate )
1864 sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rFormatName, SwGetPoolIdFromName::ChrFmt );
1865 if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
1866 pFormat = static_cast<SwCharFormat*>(GetFormatFromPool( nId ));
1868 return pFormat;
1871 // Find the table format with the name rFormatname
1872 // Returns: Pointer at the collection or 0, if no
1873 // frame format with this name exists or
1874 // this is a default format or the format is automatic.
1876 SwFrameFormat *SwWrtShell::GetTableStyle(std::u16string_view rFormatName)
1878 for( size_t i = GetTableFrameFormatCount(); i; )
1880 SwFrameFormat *pFormat = &GetTableFrameFormat( --i );
1881 if( !pFormat->IsDefault() &&
1882 pFormat->GetName() == rFormatName && IsUsed( *pFormat ) )
1883 return pFormat;
1885 return nullptr;
1888 void SwWrtShell::addCurrentPosition() {
1889 SwPaM* pPaM = GetCursor();
1890 m_aNavigationMgr.addEntry(*pPaM->GetPoint());
1893 // Applying templates
1895 void SwWrtShell::SetPageStyle(const OUString &rCollName)
1897 if( !SwCursorShell::HasSelection() && !IsSelFrameMode() && !GetSelectedObjCount() )
1899 SwPageDesc* pDesc = FindPageDescByName( rCollName, true );
1900 if( pDesc )
1901 ChgCurPageDesc( *pDesc );
1905 // Access templates
1907 OUString const & SwWrtShell::GetCurPageStyle() const
1909 return GetPageDesc(GetCurPageDesc( false/*bCalcFrame*/ )).GetName();
1912 // Change the current template referring to the existing change.
1914 void SwWrtShell::QuickUpdateStyle()
1916 SwTextFormatColl *pColl = GetCurTextFormatColl();
1918 // Default cannot be changed
1919 if(pColl && !pColl->IsDefault())
1921 FillByEx(pColl);
1922 // Also apply the template to remove hard attribute assignment.
1923 SetTextFormatColl(pColl);
1927 void SwWrtShell::AutoUpdatePara(SwTextFormatColl* pColl, const SfxItemSet& rStyleSet, SwPaM* pPaM )
1929 SwPaM* pCursor = pPaM ? pPaM : GetCursor( );
1930 SfxItemSetFixed<
1931 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1932 RES_PARATR_BEGIN, RES_PARATR_END - 1,
1933 RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1934 SID_ATTR_TABSTOP_DEFAULTS,SID_ATTR_TABSTOP_OFFSET,
1935 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
1936 SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
1937 SID_ATTR_PARA_PAGENUM, SID_ATTR_PARA_PAGENUM> aCoreSet( GetAttrPool() );
1938 GetPaMAttr( pCursor, aCoreSet );
1939 bool bReset = false;
1941 // ITEM: SfxItemIter and removing SfxPoolItems:
1942 std::vector<sal_uInt16> aDeleteWhichIDs;
1944 for (SfxItemIter aIter(aCoreSet); !aIter.IsAtEnd(); aIter.NextItem())
1946 if(!IsInvalidItem(aIter.GetCurItem()))
1948 if (SfxItemState::SET == aIter.GetItemState() &&
1949 SfxItemState::SET == rStyleSet.GetItemState(aIter.GetCurWhich()))
1951 aDeleteWhichIDs.push_back(aIter.GetCurWhich());
1952 bReset = true;
1957 for (auto nDelWhich : aDeleteWhichIDs)
1958 aCoreSet.ClearItem(nDelWhich);
1960 StartAction();
1961 if(bReset)
1963 ResetAttr({}, pCursor);
1964 SetAttrSet(aCoreSet, SetAttrMode::DEFAULT, pCursor);
1966 mxDoc->ChgFormat(*pColl, rStyleSet );
1967 EndAction();
1970 void SwWrtShell::AutoUpdateFrame( SwFrameFormat* pFormat, const SfxItemSet& rStyleSet )
1972 StartAction();
1974 ResetFlyFrameAttr( &rStyleSet );
1975 pFormat->SetFormatAttr( rStyleSet );
1977 EndAction();
1980 void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Unicode cChar )
1982 ResetCursorStack();
1983 if(!CanInsert())
1984 return;
1986 bool bStarted = false;
1987 SwRewriter aRewriter;
1989 if(HasSelection())
1991 // Only parentheses here, because the regular insert
1992 // is already clipped to the editshell
1993 StartAllAction();
1995 OUString aTmpStr1 = SwResId(STR_START_QUOTE) +
1996 GetSelText() +
1997 SwResId(STR_END_QUOTE);
1998 OUString aTmpStr3 = SwResId(STR_START_QUOTE) +
1999 OUStringChar(cChar) +
2000 SwResId(STR_END_QUOTE);
2001 aRewriter.AddRule( UndoArg1, aTmpStr1 );
2002 aRewriter.AddRule( UndoArg2, SwResId(STR_YIELDS) );
2003 aRewriter.AddRule( UndoArg3, aTmpStr3 );
2005 StartUndo( SwUndoId::REPLACE, &aRewriter );
2006 bStarted = true;
2007 DelRight(true);
2009 SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
2011 if(bStarted)
2013 EndAllAction();
2014 EndUndo( SwUndoId::REPLACE, &aRewriter );
2018 // Some kind of controlled copy ctor
2020 SwWrtShell::SwWrtShell( SwWrtShell& rSh, vcl::Window *_pWin, SwView &rShell )
2021 : SwFEShell(rSh, _pWin)
2022 , m_rView(rShell)
2023 , m_aNavigationMgr(*this)
2025 BITFLD_INI_LIST
2026 CurrShell aCurr( this );
2028 SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
2029 SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
2031 // place the cursor on the first field...
2032 Fieldmark *pBM = nullptr;
2033 if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
2034 GotoFieldmark(pBM);
2038 SwWrtShell::SwWrtShell( SwDoc& rDoc, vcl::Window *_pWin, SwView &rShell,
2039 const SwViewOption *pViewOpt )
2040 : SwFEShell(rDoc, _pWin, pViewOpt)
2041 , m_rView(rShell)
2042 , m_aNavigationMgr(*this)
2044 BITFLD_INI_LIST
2045 CurrShell aCurr( this );
2046 SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
2047 SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
2049 // place the cursor on the first field...
2050 Fieldmark *pBM = nullptr;
2051 if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
2052 GotoFieldmark(pBM);
2056 SwWrtShell::~SwWrtShell()
2058 CurrShell aCurr( this );
2059 while(IsModePushed())
2060 PopMode();
2061 while(PopCursor(false))
2063 SwTransferable::ClearSelection( *this );
2066 bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
2068 ::std::optional<SwCallLink> aLink(std::in_place, *this);
2069 return Pop(eDelete, aLink);
2072 bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::optional<SwCallLink>& roLink)
2074 bool bRet = SwCursorShell::Pop(eDelete, roLink);
2075 if( bRet && IsSelection() )
2077 m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
2078 m_fnKillSel = &SwWrtShell::ResetSelect;
2080 return bRet;
2083 bool SwWrtShell::CanInsert()
2085 if(IsSelFrameMode())
2087 return false;
2090 if(GetSelectedObjCount())
2092 return false;
2095 if(GetView().GetDrawFuncPtr())
2097 return false;
2100 if(GetView().GetPostItMgr()->GetActiveSidebarWin())
2102 return false;
2105 return true;
2108 void SwWrtShell::ChgDBData(const SwDBData& aDBData)
2110 SwEditShell::ChgDBData(aDBData);
2111 //notify the db-beamer if available
2112 GetView().NotifyDBChanged();
2115 OUString SwWrtShell::GetSelDescr() const
2117 OUString aResult;
2119 SelectionType nSelType = GetSelectionType();
2120 switch (nSelType)
2122 case SelectionType::Graphic:
2123 aResult = SwResId(STR_GRAPHIC);
2125 break;
2126 case SelectionType::Frame:
2128 const SwFrameFormat * pFrameFormat = GetSelectedFrameFormat();
2130 if (pFrameFormat)
2131 aResult = pFrameFormat->GetDescription();
2133 break;
2134 case SelectionType::DrawObject:
2136 aResult = SwResId(STR_DRAWING_OBJECTS);
2138 break;
2139 default:
2140 if (mxDoc)
2141 aResult = GetCursorDescr();
2144 return aResult;
2147 void SwWrtShell::ApplyViewOptions( const SwViewOption &rOpt )
2149 SwFEShell::ApplyViewOptions( rOpt );
2150 //#i115062# invalidate meta character slot
2151 GetView().GetViewFrame().GetBindings().Invalidate( FN_VIEW_META_CHARS );
2154 void SwWrtShell::SetReadonlyOption(bool bSet)
2156 GetView().GetEditWin().GetFrameControlsManager().SetReadonlyControls( bSet );
2157 SwViewShell::SetReadonlyOption( bSet );
2160 // Switch on/off header or footer of a page style - if an empty name is
2161 // given all styles are changed
2163 void SwWrtShell::ChangeHeaderOrFooter(
2164 std::u16string_view rStyleName, bool bHeader, bool bOn, bool bShowWarning)
2166 SdrView *const pSdrView = GetDrawView();
2167 if (pSdrView && pSdrView->IsTextEdit())
2168 { // tdf#107474 deleting header may delete active drawing object
2169 pSdrView->SdrEndTextEdit(true);
2171 addCurrentPosition();
2172 StartAllAction();
2173 StartUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
2174 bool bExecute = true;
2175 bool bCursorSet = false;
2176 for( size_t nFrom = 0, nTo = GetPageDescCnt();
2177 nFrom < nTo; ++nFrom )
2179 SwPageDesc aDesc( GetPageDesc( nFrom ));
2180 OUString sTmp(aDesc.GetName());
2181 if( rStyleName.empty() || rStyleName == sTmp )
2183 bool bChgd = false;
2185 if( bShowWarning && !bOn && GetActiveView() && GetActiveView() == &GetView() &&
2186 ( (bHeader && aDesc.GetMaster().GetHeader().IsActive()) ||
2187 (!bHeader && aDesc.GetMaster().GetFooter().IsActive()) ) )
2189 bShowWarning = false;
2190 //Actions have to be closed while the dialog is showing
2191 EndAllAction();
2193 weld::Window* pParent = GetView().GetFrameWeld();
2194 short nResult;
2195 if (bHeader) {
2196 nResult = DeleteHeaderDialog(pParent).run();
2197 } else {
2198 nResult = DeleteFooterDialog(pParent).run();
2201 bExecute = nResult == RET_YES;
2202 StartAllAction();
2203 if (nResult == RET_YES)
2204 ToggleHeaderFooterEdit();
2206 if( bExecute )
2208 bChgd = true;
2209 SwFrameFormat &rMaster = aDesc.GetMaster();
2210 if(bHeader)
2211 rMaster.SetFormatAttr( SwFormatHeader( bOn ));
2212 else
2213 rMaster.SetFormatAttr( SwFormatFooter( bOn ));
2214 if( bOn )
2216 // keep in sync with FN_PGNUMBER_WIZARD
2217 constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
2218 SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm, bHeader ? constTwips_5mm : 0, RES_UL_SPACE );
2219 SwFrameFormat* pFormat = bHeader ?
2220 const_cast<SwFrameFormat*>(rMaster.GetHeader().GetHeaderFormat()) :
2221 const_cast<SwFrameFormat*>(rMaster.GetFooter().GetFooterFormat());
2222 pFormat->SetFormatAttr( aUL );
2223 XFillStyleItem aFill(drawing::FillStyle_NONE);
2224 pFormat->SetFormatAttr(aFill);
2227 if( bChgd )
2229 ChgPageDesc( nFrom, aDesc );
2231 if( !bCursorSet && bOn )
2233 if ( !IsHeaderFooterEdit() )
2234 ToggleHeaderFooterEdit();
2235 bCursorSet = SetCursorInHdFt(
2236 rStyleName.empty() ? SIZE_MAX : nFrom,
2237 bHeader );
2242 EndUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
2243 EndAllAction();
2246 void SwWrtShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow )
2248 SwViewShell::SetShowHeaderFooterSeparator( eControl, bShow );
2249 if ( !bShow )
2250 GetView().GetEditWin().GetFrameControlsManager().HideControls( eControl );
2253 void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
2255 SwPostItField* pPostIt = dynamic_cast<SwPostItField*>(rFieldMgr.GetCurField());
2256 bool bNew = !(pPostIt && pPostIt->GetTyp()->Which() == SwFieldIds::Postit);
2257 if (bNew || GetView().GetPostItMgr()->IsAnswer() || comphelper::LibreOfficeKit::isActive())
2259 const SvxPostItAuthorItem* pAuthorItem = rReq.GetArg<SvxPostItAuthorItem>(SID_ATTR_POSTIT_AUTHOR);
2260 OUString sAuthor;
2261 if ( pAuthorItem )
2262 sAuthor = pAuthorItem->GetValue();
2263 else
2265 SwModule* mod = SwModule::get();
2266 std::size_t nAuthor = mod->GetRedlineAuthor();
2267 sAuthor = mod->GetRedlineAuthor(nAuthor);
2270 const SvxPostItTextItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
2271 OUString sText;
2272 if ( pTextItem )
2273 sText = pTextItem->GetValue();
2275 std::optional<OutlinerParaObject> oTextPara;
2276 if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_HTML))
2278 SwDocShell* pDocSh = GetView().GetDocShell();
2279 Outliner aOutliner(&pDocSh->GetPool(), OutlinerMode::TextObject);
2280 SwPostItHelper::ImportHTML(aOutliner, pHtmlItem->GetValue());
2281 oTextPara = aOutliner.CreateParaObject();
2282 sText = aOutliner.GetEditEngine().GetText();
2285 // If we have a text already registered for answer, use that
2286 SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
2287 if (OutlinerParaObject* pAnswer = pPostItMgr->IsAnswer())
2289 if (!pPostItMgr->GetAnswerText().isEmpty())
2291 sText = GetView().GetPostItMgr()->GetAnswerText();
2292 pPostItMgr->RegisterAnswerText(OUString());
2294 const EditTextObject& rTextObject = pAnswer->GetTextObject();
2295 if (rTextObject.GetParagraphCount() != 1 || !rTextObject.GetText(0).isEmpty())
2297 oTextPara = *pAnswer;
2298 sText = rTextObject.GetText();
2302 if ( HasSelection() && !IsTableMode() )
2304 KillPams();
2307 // #i120513# Inserting a comment into an autocompletion crashes
2308 // --> suggestion has to be removed before
2309 GetView().GetEditWin().StopQuickHelp();
2311 SwInsertField_Data aData(SwFieldTypesEnum::Postit, 0, sAuthor, sText, 0);
2313 if (IsSelFrameMode())
2315 SwFlyFrame* pFly = GetSelectedFlyFrame();
2317 // Remember the anchor of the selected object before deletion.
2318 std::optional<SwPosition> oAnchor;
2319 if (pFly)
2321 SwFrameFormat* pFormat = pFly->GetFormat();
2322 if (pFormat)
2324 RndStdIds eAnchorId = pFormat->GetAnchor().GetAnchorId();
2325 if ((eAnchorId == RndStdIds::FLY_AS_CHAR || eAnchorId == RndStdIds::FLY_AT_CHAR) && pFormat->GetAnchor().GetAnchorNode())
2327 oAnchor.emplace(*pFormat->GetAnchor().GetContentAnchor());
2332 // A frame is selected, end frame selection.
2333 EnterStdMode();
2334 GetView().AttrChangedNotify(nullptr);
2336 // Set up text selection, so the anchor of the frame will be the anchor of the
2337 // comment.
2338 if (pFly)
2340 if (oAnchor)
2341 *GetCurrentShellCursor().GetPoint() = *oAnchor;
2342 SwFrameFormat* pFormat = pFly->GetFormat();
2343 if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
2345 Right(SwCursorSkipMode::Cells, /*bSelect=*/true, 1, /*bBasicCall=*/false, /*bVisual=*/true);
2347 else if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR)
2349 aData.m_oAnnotationRange.emplace(*GetCurrentShellCursor().Start(),
2350 *GetCurrentShellCursor().End());
2355 // Defer broadcast of postit field update from layout until oTextPara has been
2356 // applied to the field's associated postit window
2357 if (oTextPara)
2358 StartAction();
2360 rFieldMgr.InsertField( aData );
2362 Push();
2363 SwCursorShell::Left(1, SwCursorSkipMode::Chars);
2364 pPostIt = static_cast<SwPostItField*>(rFieldMgr.GetCurField());
2366 if (pPostIt && oTextPara)
2367 pPostIt->SetTextObject(*oTextPara);
2369 Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position
2371 if (oTextPara)
2372 EndAction();
2375 // Client has disabled annotations rendering, no need to
2376 // focus the postit field
2377 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
2378 return;
2380 if (pPostIt)
2382 SwFieldType* pType = GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
2383 if(auto pFormat = pType->FindFormatForField(pPostIt))
2384 pFormat->Broadcast( SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::FOCUS, &GetView() ) );
2388 bool SwWrtShell::IsOutlineContentVisible(const size_t nPos)
2390 const SwOutlineNodes& rOutlineNodes = GetDoc()->GetNodes().GetOutLineNds();
2391 const SwNode* pOutlineNode = rOutlineNodes[nPos];
2393 // no layout frame means outline folding is set to include sub levels and the outline node has
2394 // a parent outline node with outline content visible attribute false (folded outline content)
2395 if (!pOutlineNode->GetTextNode()->getLayoutFrame(GetLayout()))
2396 return false;
2398 // try the next node to determine if this outline node has visible content
2399 SwNodeIndex aIdx(*pOutlineNode, +1);
2400 if (aIdx.GetNode() == aIdx.GetNodes().GetEndOfContent()) // end of regular content
2401 return false;
2403 if (aIdx.GetNode().IsTextNode() || aIdx.GetNode().IsTableNode() ||
2404 aIdx.GetNode().IsSectionNode())
2406 // * sublevels treated as outline content
2407 // If next node (aIdx) doesn't have a layout frame
2408 // then this outline node does not have visible outline content.
2409 // * sublevels NOT treated as outline content
2410 // If the next node (aIdx) is the next outline node
2411 // then return the outline content visible attribute value.
2412 if (!GetViewOptions()->IsTreatSubOutlineLevelsAsContent() &&
2413 nPos + 1 < rOutlineNodes.size() &&
2414 rOutlineNodes[nPos + 1] == &aIdx.GetNode())
2415 return GetAttrOutlineContentVisible(nPos);
2417 if (aIdx.GetNode().IsTextNode())
2418 return aIdx.GetNode().GetTextNode()->getLayoutFrame(GetLayout());
2419 if (aIdx.GetNode().IsTableNode())
2421 SwTable& rTable = aIdx.GetNode().GetTableNode()->GetTable();
2422 return rTable.HasLayout();
2424 if (aIdx.GetNode().IsSectionNode())
2426 const auto pFormat = aIdx.GetNode().GetSectionNode()->GetSection().GetFormat();
2427 return pFormat && pFormat->IsVisible();
2431 return true;
2434 void SwWrtShell::MakeOutlineLevelsVisible(const int nLevel)
2436 MakeAllOutlineContentTemporarilyVisible a(GetDoc());
2438 m_rView.SetMaxOutlineLevelShown(nLevel);
2440 bool bDocChanged = false;
2442 const SwOutlineNodes& rOutlineNodes = GetNodes().GetOutLineNds();
2444 // Make all missing frames.
2445 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
2447 SwNode* pNode = rOutlineNodes[nPos];
2448 if (!pNode->GetTextNode()->getLayoutFrame(GetLayout()))
2450 SwNodeIndex aIdx(*pNode, +1);
2451 // Make the outline paragraph frame
2452 MakeFrames(GetDoc(), *pNode, aIdx.GetNode());
2453 // Make the outline content visible but don't set the outline visible attribute and
2454 // don't make outline content made visible not visible that have outline visible
2455 // attribute false. Visibility will be taken care of when
2456 // MakeAllOutlineContentTemporarilyVisible goes out of scope.
2457 MakeOutlineContentVisible(nPos, true, false);
2458 bDocChanged = true;
2461 // Remove outline paragraph frame and outline content frames above given level.
2462 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
2464 SwNode* pNode = rOutlineNodes[nPos];
2465 auto nOutlineLevel = pNode->GetTextNode()->GetAttrOutlineLevel();
2466 if (nOutlineLevel > nLevel)
2468 // Remove the outline content but don't set the outline visible attribute. Visibility
2469 // will be taken care of when MakeAllOutlineContentTemporarilyVisible goes out of scope.
2470 MakeOutlineContentVisible(nPos, false, false);
2471 // Remove the outline paragraph frame.
2472 pNode->GetTextNode()->DelFrames(GetLayout());
2473 bDocChanged = true;
2477 // Broadcast DocChanged if document layout has changed so the Navigator will be updated.
2478 if (bDocChanged)
2479 GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
2482 void SwWrtShell::MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible, bool bSetAttrOutlineVisibility)
2484 const SwNodes& rNodes = GetNodes();
2485 const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
2487 SwNode* pSttNd = rOutlineNodes[nPos];
2489 // determine end node
2490 SwNode* pEndNd = &rNodes.GetEndOfContent();
2491 if (rOutlineNodes.size() > nPos + 1)
2492 pEndNd = rOutlineNodes[nPos + 1];
2494 if (GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
2496 // get the last outline node to include (iPos)
2497 int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
2498 int nMaxOutlineLevelShown = m_rView.GetMaxOutlineLevelShown();
2499 SwOutlineNodes::size_type iPos = nPos;
2500 while (++iPos < rOutlineNodes.size() &&
2501 rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel &&
2502 rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() <= nMaxOutlineLevelShown);
2504 // get the correct end node
2505 // the outline node may be in frames, headers, footers special section of doc model
2506 SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
2507 while (pStartOfSectionNodeSttNd->StartOfSectionNode()
2508 != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
2510 pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
2512 pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
2514 if (iPos < rOutlineNodes.size())
2516 SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
2517 while (pStartOfSectionNode->StartOfSectionNode()
2518 != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
2520 pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
2522 if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
2523 pEndNd = rOutlineNodes[iPos];
2527 // table, text box, header, footer
2528 if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
2530 // limit to within section
2531 if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
2532 pEndNd = pSttNd->EndOfSectionNode();
2534 // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
2535 else if (pEndNd->GetTableBox())
2537 pEndNd = &rNodes.GetEndOfContent();
2538 for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
2540 if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
2542 pEndNd = rOutlineNodes[nOutlinePos];
2543 break;
2547 // end node determined
2549 // Remove content frames from the next node after the starting outline node to
2550 // the determined ending node. Always do this to prevent the chance of duplicate
2551 // frames being made. They will be remade below if needed.
2552 SwNodeIndex aIdx(*pSttNd, +1);
2553 while (aIdx != *pEndNd)
2555 SwNode* pNd = &aIdx.GetNode();
2556 if (pNd->IsContentNode())
2557 pNd->GetContentNode()->DelFrames(nullptr);
2558 else if (pNd->IsTableNode())
2559 pNd->GetTableNode()->DelFrames(nullptr);
2560 ++aIdx;
2563 if (bMakeVisible) // make outline nodes outline content visible
2565 // reset the index marker and make frames
2566 aIdx.Assign(*pSttNd, +1);
2567 MakeFrames(GetDoc(), aIdx.GetNode(), *pEndNd);
2569 if (bSetAttrOutlineVisibility)
2571 pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true);
2573 // make outline content made visible that have outline visible attribute false not visible
2574 while (aIdx != *pEndNd)
2576 SwNode* pNd = &aIdx.GetNode();
2577 if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline())
2579 SwTextNode* pTextNd = pNd->GetTextNode();
2580 if (!pTextNd->GetAttrOutlineContentVisible())
2582 SwOutlineNodes::size_type iPos;
2583 if (rOutlineNodes.Seek_Entry(pTextNd, &iPos))
2585 if (pTextNd->getLayoutFrame(nullptr))
2586 MakeOutlineContentVisible(iPos, false);
2590 ++aIdx;
2594 else if (bSetAttrOutlineVisibility)
2595 pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
2598 // make content visible or not visible only if needed
2599 void SwWrtShell::InvalidateOutlineContentVisibility()
2601 GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
2603 const SwOutlineNodes& rOutlineNds = GetNodes().GetOutLineNds();
2604 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
2606 bool bIsOutlineContentVisible = IsOutlineContentVisible(nPos);
2607 bool bOutlineContentVisibleAttr = rOutlineNds[nPos]->GetTextNode()->GetAttrOutlineContentVisible();
2608 if (!bIsOutlineContentVisible && bOutlineContentVisibleAttr)
2609 MakeOutlineContentVisible(nPos);
2610 else if (bIsOutlineContentVisible && !bOutlineContentVisibleAttr)
2611 MakeOutlineContentVisible(nPos, false);
2615 void SwWrtShell::MakeAllFoldedOutlineContentVisible(bool bMakeVisible)
2617 if (bMakeVisible)
2619 // make all content visible
2621 // When shortcut is assigned to the show outline content visibility button and used to
2622 // toggle the feature and the mouse pointer is on an outline frame the button will not
2623 // be removed. An easy way to make sure the button does not remain shown is to use the
2624 // HideControls function.
2625 GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
2627 // temporarily set outline content visible attribute true for folded outline nodes
2628 std::vector<SwNode*> aFoldedOutlineNodeArray;
2629 for (SwNode* pNd: GetNodes().GetOutLineNds())
2631 if (!pNd->GetTextNode()->GetAttrOutlineContentVisible())
2633 aFoldedOutlineNodeArray.push_back(pNd);
2634 pNd->GetTextNode()->SetAttrOutlineContentVisible(true);
2638 StartAction();
2639 InvalidateOutlineContentVisibility();
2640 EndAction();
2642 // restore outline content visible attribute for folded outline nodes
2643 for (SwNode* pNd: aFoldedOutlineNodeArray)
2644 pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
2646 else
2648 AssureStdMode();
2650 // Get the outline position of the cursor so the cursor can be place at a visible outline
2651 // node if it is not visible after InvalidateOutlineContentVisiblity below.
2652 SwOutlineNodes::size_type nPos = GetOutlinePos();
2654 StartAction();
2655 InvalidateOutlineContentVisibility();
2656 EndAction();
2658 // If needed, find a visible outline node to place the cursor.
2659 if (nPos != SwOutlineNodes::npos && !IsOutlineContentVisible(nPos))
2661 while (nPos != SwOutlineNodes::npos &&
2662 !GetNodes().GetOutLineNds()[nPos]->GetTextNode()->getLayoutFrame(GetLayout()))
2663 --nPos;
2664 if (nPos != SwOutlineNodes::npos)
2665 GotoOutline(nPos);
2668 GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
2671 bool SwWrtShell::GetAttrOutlineContentVisible(const size_t nPos) const
2673 return GetNodes().GetOutLineNds()[nPos]->GetTextNode()->GetAttrOutlineContentVisible();
2676 bool SwWrtShell::HasFoldedOutlineContentSelected() const
2678 // No need to check for selection over folded outline content when there are no outline nodes.
2679 if (GetDoc()->GetNodes().GetOutLineNds().empty())
2680 return false;
2681 for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
2683 SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint());
2684 aPaM.Normalize();
2685 SwNodeIndex aPointIdx(aPaM.GetPoint()->GetNode());
2686 SwNodeIndex aMarkIdx(aPaM.GetMark()->GetNode());
2687 // Prevent crash in the for loop below by adjusting the mark if it is set to the end of
2688 // content node.
2689 if (aMarkIdx.GetNode() == GetDoc()->GetNodes().GetEndOfContent())
2690 --aMarkIdx;
2691 if (aPointIdx == aMarkIdx)
2692 continue;
2693 // Return true if any nodes in PaM are folded outline content nodes.
2694 SwOutlineNodes::size_type nPos;
2695 for (SwNodeIndex aIdx = aPointIdx; aIdx <= aMarkIdx; ++aIdx)
2697 // To allow delete when the start of the selection is at the start of a
2698 // paragraph and the end of the selection is at the start of a paragraph and there
2699 // are no folded outline content nodes in between.
2700 if (aIdx == aMarkIdx && aPaM.GetPoint()->GetContentIndex() == 0 &&
2701 aPaM.GetMark()->GetContentIndex() == 0)
2702 return false;
2704 if (GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(&(aIdx.GetNode()), &nPos) &&
2705 !GetAttrOutlineContentVisible(nPos))
2706 return true;
2709 return false;
2712 void SwWrtShell::InfoReadOnlyDialog(bool bAsync) const
2714 if (bAsync)
2716 auto xInfo = std::make_shared<weld::MessageDialogController>(
2717 GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui", "InfoReadonlyDialog");
2718 if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
2719 HasFoldedOutlineContentSelected())
2721 xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2722 xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2724 weld::DialogController::runAsync(xInfo, [](int) {});
2726 else
2728 std::unique_ptr<weld::Builder>
2729 xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(),
2730 u"modules/swriter/ui/inforeadonlydialog.ui"_ustr));
2731 std::unique_ptr<weld::MessageDialog>
2732 xInfo(xBuilder->weld_message_dialog(u"InfoReadonlyDialog"_ustr));
2733 if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
2734 HasFoldedOutlineContentSelected())
2736 xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2737 xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2739 xInfo->run();
2743 bool SwWrtShell::WarnHiddenSectionDialog() const
2745 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
2746 GetView().GetFrameWeld(), u"modules/swriter/ui/warnhiddensectiondialog.ui"_ustr));
2747 std::unique_ptr<weld::MessageDialog> xQuery(
2748 xBuilder->weld_message_dialog(u"WarnHiddenSectionDialog"_ustr));
2749 if (GetViewOptions()->IsShowOutlineContentVisibilityButton()
2750 && HasFoldedOutlineContentSelected())
2752 xQuery->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
2753 xQuery->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
2756 return (RET_YES == xQuery->run());
2759 bool SwWrtShell::WarnSwitchToDesignModeDialog() const
2761 std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(nullptr,
2762 VclMessageType::Question, VclButtonsType::YesNo, SwResId(STR_A11Y_DESIGN_MODE_PRIMARY)));
2763 xQuery->set_default_response(RET_YES);
2764 xQuery->set_title(SwResId(STR_A11Y_DESIGN_MODE_TITLE));
2765 xQuery->set_secondary_text(SwResId(STR_A11Y_DESIGN_MODE_SECONDARY));
2767 return (RET_YES == xQuery->run());
2770 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */