File: | home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx |
Warning: | line 3105, column 9 Potential leak of memory pointed to by 'pContact' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | #include <DocumentContentOperationsManager.hxx> | |||
20 | #include <doc.hxx> | |||
21 | #include <IDocumentUndoRedo.hxx> | |||
22 | #include <IDocumentMarkAccess.hxx> | |||
23 | #include <IDocumentState.hxx> | |||
24 | #include <IDocumentLayoutAccess.hxx> | |||
25 | #include <IDocumentStylePoolAccess.hxx> | |||
26 | #include <IDocumentSettingAccess.hxx> | |||
27 | #include <UndoManager.hxx> | |||
28 | #include <docary.hxx> | |||
29 | #include <textboxhelper.hxx> | |||
30 | #include <dcontact.hxx> | |||
31 | #include <grfatr.hxx> | |||
32 | #include <numrule.hxx> | |||
33 | #include <charfmt.hxx> | |||
34 | #include <ndgrf.hxx> | |||
35 | #include <ndnotxt.hxx> | |||
36 | #include <ndole.hxx> | |||
37 | #include <breakit.hxx> | |||
38 | #include <frmfmt.hxx> | |||
39 | #include <fmtanchr.hxx> | |||
40 | #include <fmtcntnt.hxx> | |||
41 | #include <fmtinfmt.hxx> | |||
42 | #include <fmtpdsc.hxx> | |||
43 | #include <fmtcnct.hxx> | |||
44 | #include <SwStyleNameMapper.hxx> | |||
45 | #include <redline.hxx> | |||
46 | #include <txtfrm.hxx> | |||
47 | #include <rootfrm.hxx> | |||
48 | #include <frmtool.hxx> | |||
49 | #include <unocrsr.hxx> | |||
50 | #include <mvsave.hxx> | |||
51 | #include <ndtxt.hxx> | |||
52 | #include <poolfmt.hxx> | |||
53 | #include <paratr.hxx> | |||
54 | #include <txatbase.hxx> | |||
55 | #include <UndoRedline.hxx> | |||
56 | #include <undobj.hxx> | |||
57 | #include <UndoBookmark.hxx> | |||
58 | #include <UndoDelete.hxx> | |||
59 | #include <UndoSplitMove.hxx> | |||
60 | #include <UndoOverwrite.hxx> | |||
61 | #include <UndoInsert.hxx> | |||
62 | #include <UndoAttribute.hxx> | |||
63 | #include <rolbck.hxx> | |||
64 | #include <acorrect.hxx> | |||
65 | #include <bookmrk.hxx> | |||
66 | #include <ftnidx.hxx> | |||
67 | #include <txtftn.hxx> | |||
68 | #include <hints.hxx> | |||
69 | #include <fmtflcnt.hxx> | |||
70 | #include <docedt.hxx> | |||
71 | #include <frameformats.hxx> | |||
72 | #include <o3tl/safeint.hxx> | |||
73 | #include <sal/log.hxx> | |||
74 | #include <unotools/charclass.hxx> | |||
75 | #include <unotools/configmgr.hxx> | |||
76 | #include <sfx2/Metadatable.hxx> | |||
77 | #include <sot/exchange.hxx> | |||
78 | #include <svl/stritem.hxx> | |||
79 | #include <svl/itemiter.hxx> | |||
80 | #include <svx/svdobj.hxx> | |||
81 | #include <svx/svdouno.hxx> | |||
82 | #include <tools/globname.hxx> | |||
83 | #include <editeng/formatbreakitem.hxx> | |||
84 | #include <com/sun/star/i18n/Boundary.hpp> | |||
85 | #include <com/sun/star/i18n/WordType.hpp> | |||
86 | #include <com/sun/star/i18n/XBreakIterator.hpp> | |||
87 | #include <com/sun/star/embed/XEmbeddedObject.hpp> | |||
88 | ||||
89 | #include <tuple> | |||
90 | #include <memory> | |||
91 | ||||
92 | #include <editsh.hxx> | |||
93 | #include <viewopt.hxx> | |||
94 | #include <wrtsh.hxx> | |||
95 | ||||
96 | using namespace ::com::sun::star::i18n; | |||
97 | ||||
98 | namespace | |||
99 | { | |||
100 | // Copy method from SwDoc | |||
101 | // Prevent copying into Flys that are anchored in the range | |||
102 | bool lcl_ChkFlyFly( SwDoc& rDoc, sal_uLong nSttNd, sal_uLong nEndNd, | |||
103 | sal_uLong nInsNd ) | |||
104 | { | |||
105 | const SwFrameFormats& rFrameFormatTable = *rDoc.GetSpzFrameFormats(); | |||
106 | ||||
107 | for( size_t n = 0; n < rFrameFormatTable.size(); ++n ) | |||
108 | { | |||
109 | SwFrameFormat const*const pFormat = rFrameFormatTable[n]; | |||
110 | SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor(); | |||
111 | SwPosition const*const pAPos = pAnchor->GetContentAnchor(); | |||
112 | if (pAPos && | |||
113 | ((RndStdIds::FLY_AS_CHAR == pAnchor->GetAnchorId()) || | |||
114 | (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()) || | |||
115 | (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId()) || | |||
116 | (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId())) && | |||
117 | nSttNd <= pAPos->nNode.GetIndex() && | |||
118 | pAPos->nNode.GetIndex() < nEndNd ) | |||
119 | { | |||
120 | const SwFormatContent& rContent = pFormat->GetContent(); | |||
121 | SwStartNode* pSNd; | |||
122 | if( !rContent.GetContentIdx() || | |||
123 | nullptr == ( pSNd = rContent.GetContentIdx()->GetNode().GetStartNode() )) | |||
124 | continue; | |||
125 | ||||
126 | if( pSNd->GetIndex() < nInsNd && | |||
127 | nInsNd < pSNd->EndOfSectionIndex() ) | |||
128 | // Do not copy ! | |||
129 | return true; | |||
130 | ||||
131 | if( lcl_ChkFlyFly( rDoc, pSNd->GetIndex(), | |||
132 | pSNd->EndOfSectionIndex(), nInsNd ) ) | |||
133 | // Do not copy ! | |||
134 | return true; | |||
135 | } | |||
136 | } | |||
137 | ||||
138 | return false; | |||
139 | } | |||
140 | ||||
141 | SwNodeIndex InitDelCount(SwPaM const& rSourcePaM, sal_uLong & rDelCount) | |||
142 | { | |||
143 | SwNodeIndex const& rStart(rSourcePaM.Start()->nNode); | |||
144 | // Special handling for SwDoc::AppendDoc | |||
145 | if (rSourcePaM.GetDoc().GetNodes().GetEndOfExtras().GetIndex() + 1 | |||
146 | == rStart.GetIndex()) | |||
147 | { | |||
148 | rDelCount = 1; | |||
149 | return SwNodeIndex(rStart, +1); | |||
150 | } | |||
151 | else | |||
152 | { | |||
153 | rDelCount = 0; | |||
154 | return rStart; | |||
155 | } | |||
156 | } | |||
157 | ||||
158 | /* | |||
159 | The CopyBookmarks function has to copy bookmarks from the source to the destination nodes | |||
160 | array. It is called after a call of the CopyNodes(..) function. But this function does not copy | |||
161 | every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied | |||
162 | if the corresponding end/start node is outside the copied pam. | |||
163 | The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node | |||
164 | index inside the pam. | |||
165 | rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number | |||
166 | of "non-copy" nodes between rPam.Start() and rLastIdx. | |||
167 | nNewIdx is the new position of interest. | |||
168 | */ | |||
169 | void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const sal_uLong nNewIdx, sal_uLong& rDelCount ) | |||
170 | { | |||
171 | sal_uLong nStart = rPam.Start()->nNode.GetIndex(); | |||
172 | sal_uLong nEnd = rPam.End()->nNode.GetIndex(); | |||
173 | if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward? | |||
174 | { | |||
175 | // We never copy the StartOfContent node | |||
176 | do // count "non-copy" nodes | |||
177 | { | |||
178 | SwNode& rNode = rLastIdx.GetNode(); | |||
179 | if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd ) | |||
180 | || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) ) | |||
181 | { | |||
182 | ++rDelCount; | |||
183 | } | |||
184 | ++rLastIdx; | |||
185 | } | |||
186 | while( rLastIdx.GetIndex() < nNewIdx ); | |||
187 | } | |||
188 | else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now, | |||
189 | // no move backward needed | |||
190 | { | |||
191 | while( rLastIdx.GetIndex() > nNewIdx ) | |||
192 | { | |||
193 | SwNode& rNode = rLastIdx.GetNode(); | |||
194 | if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd ) | |||
195 | || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) ) | |||
196 | { | |||
197 | --rDelCount; | |||
198 | } | |||
199 | rLastIdx--; | |||
200 | } | |||
201 | } | |||
202 | } | |||
203 | ||||
204 | void lcl_SetCpyPos( const SwPosition& rOrigPos, | |||
205 | const SwPosition& rOrigStt, | |||
206 | const SwPosition& rCpyStt, | |||
207 | SwPosition& rChgPos, | |||
208 | sal_uLong nDelCount ) | |||
209 | { | |||
210 | sal_uLong nNdOff = rOrigPos.nNode.GetIndex(); | |||
211 | nNdOff -= rOrigStt.nNode.GetIndex(); | |||
212 | nNdOff -= nDelCount; | |||
213 | sal_Int32 nContentPos = rOrigPos.nContent.GetIndex(); | |||
214 | ||||
215 | // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos> | |||
216 | rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex(); | |||
217 | if( !nNdOff ) | |||
218 | { | |||
219 | // just adapt the content index | |||
220 | if( nContentPos > rOrigStt.nContent.GetIndex() ) | |||
221 | nContentPos -= rOrigStt.nContent.GetIndex(); | |||
222 | else | |||
223 | nContentPos = 0; | |||
224 | nContentPos += rCpyStt.nContent.GetIndex(); | |||
225 | } | |||
226 | rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetContentNode(), nContentPos ); | |||
227 | } | |||
228 | ||||
229 | } | |||
230 | ||||
231 | namespace sw | |||
232 | { | |||
233 | // TODO: use SaveBookmark (from DelBookmarks) | |||
234 | void CopyBookmarks(const SwPaM& rPam, SwPosition& rCpyPam) | |||
235 | { | |||
236 | const SwDoc& rSrcDoc = rPam.GetDoc(); | |||
237 | SwDoc& rDestDoc = rCpyPam.GetDoc(); | |||
238 | const IDocumentMarkAccess* const pSrcMarkAccess = rSrcDoc.getIDocumentMarkAccess(); | |||
239 | ::sw::UndoGuard const undoGuard(rDestDoc.GetIDocumentUndoRedo()); | |||
240 | ||||
241 | const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); | |||
242 | SwPosition const*const pCpyStt = &rCpyPam; | |||
243 | ||||
244 | std::vector< const ::sw::mark::IMark* > vMarksToCopy; | |||
245 | for ( IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getAllMarksBegin(); | |||
246 | ppMark != pSrcMarkAccess->getAllMarksEnd(); | |||
247 | ++ppMark ) | |||
248 | { | |||
249 | const ::sw::mark::IMark* const pMark = *ppMark; | |||
250 | ||||
251 | const SwPosition& rMarkStart = pMark->GetMarkStart(); | |||
252 | const SwPosition& rMarkEnd = pMark->GetMarkEnd(); | |||
253 | // only include marks that are in the range and not touching both start and end | |||
254 | // - not for annotation or checkbox marks. | |||
255 | const bool bIsNotOnBoundary = | |||
256 | pMark->IsExpanded() | |||
257 | ? (rMarkStart != rStt || rMarkEnd != rEnd) // rMarkStart != rMarkEnd | |||
258 | : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd | |||
259 | const IDocumentMarkAccess::MarkType aMarkType = IDocumentMarkAccess::GetType(*pMark); | |||
260 | if ( rMarkStart >= rStt && rMarkEnd <= rEnd | |||
261 | && ( bIsNotOnBoundary | |||
262 | || aMarkType == IDocumentMarkAccess::MarkType::ANNOTATIONMARK | |||
263 | || aMarkType == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK | |||
264 | || aMarkType == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK | |||
265 | || aMarkType == IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK | |||
266 | || aMarkType == IDocumentMarkAccess::MarkType::DATE_FIELDMARK)) | |||
267 | { | |||
268 | vMarksToCopy.push_back(pMark); | |||
269 | } | |||
270 | } | |||
271 | // We have to count the "non-copied" nodes... | |||
272 | sal_uLong nDelCount; | |||
273 | SwNodeIndex aCorrIdx(InitDelCount(rPam, nDelCount)); | |||
274 | for(const sw::mark::IMark* const pMark : vMarksToCopy) | |||
275 | { | |||
276 | SwPaM aTmpPam(*pCpyStt); | |||
277 | lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount); | |||
278 | lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount); | |||
279 | if(pMark->IsExpanded()) | |||
280 | { | |||
281 | aTmpPam.SetMark(); | |||
282 | lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount); | |||
283 | lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount); | |||
284 | } | |||
285 | ||||
286 | ::sw::mark::IMark* const pNewMark = rDestDoc.getIDocumentMarkAccess()->makeMark( | |||
287 | aTmpPam, | |||
288 | pMark->GetName(), | |||
289 | IDocumentMarkAccess::GetType(*pMark), | |||
290 | ::sw::mark::InsertMode::CopyText); | |||
291 | // Explicitly try to get exactly the same name as in the source | |||
292 | // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name | |||
293 | rDestDoc.getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName()); | |||
294 | ||||
295 | // copying additional attributes for bookmarks or fieldmarks | |||
296 | ::sw::mark::IBookmark* const pNewBookmark = | |||
297 | dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark); | |||
298 | const ::sw::mark::IBookmark* const pOldBookmark = | |||
299 | dynamic_cast< const ::sw::mark::IBookmark* >(pMark); | |||
300 | if (pNewBookmark && pOldBookmark) | |||
301 | { | |||
302 | pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode()); | |||
303 | pNewBookmark->SetShortName(pOldBookmark->GetShortName()); | |||
304 | pNewBookmark->Hide(pOldBookmark->IsHidden()); | |||
305 | pNewBookmark->SetHideCondition(pOldBookmark->GetHideCondition()); | |||
306 | } | |||
307 | ::sw::mark::IFieldmark* const pNewFieldmark = | |||
308 | dynamic_cast< ::sw::mark::IFieldmark* const >(pNewMark); | |||
309 | const ::sw::mark::IFieldmark* const pOldFieldmark = | |||
310 | dynamic_cast< const ::sw::mark::IFieldmark* >(pMark); | |||
311 | if (pNewFieldmark && pOldFieldmark) | |||
312 | { | |||
313 | pNewFieldmark->SetFieldname(pOldFieldmark->GetFieldname()); | |||
314 | pNewFieldmark->SetFieldHelptext(pOldFieldmark->GetFieldHelptext()); | |||
315 | ::sw::mark::IFieldmark::parameter_map_t* pNewParams = pNewFieldmark->GetParameters(); | |||
316 | const ::sw::mark::IFieldmark::parameter_map_t* pOldParams = pOldFieldmark->GetParameters(); | |||
317 | for (const auto& rEntry : *pOldParams ) | |||
318 | { | |||
319 | pNewParams->insert( rEntry ); | |||
320 | } | |||
321 | } | |||
322 | ||||
323 | ::sfx2::Metadatable const*const pMetadatable( | |||
324 | dynamic_cast< ::sfx2::Metadatable const* >(pMark)); | |||
325 | ::sfx2::Metadatable *const pNewMetadatable( | |||
326 | dynamic_cast< ::sfx2::Metadatable * >(pNewMark)); | |||
327 | if (pMetadatable && pNewMetadatable) | |||
328 | { | |||
329 | pNewMetadatable->RegisterAsCopyOf(*pMetadatable); | |||
330 | } | |||
331 | } | |||
332 | } | |||
333 | } // namespace sw | |||
334 | ||||
335 | namespace | |||
336 | { | |||
337 | void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam ) | |||
338 | { | |||
339 | const SwDoc& rSrcDoc = rPam.GetDoc(); | |||
340 | const SwRedlineTable& rTable = rSrcDoc.getIDocumentRedlineAccess().GetRedlineTable(); | |||
341 | if( rTable.empty() ) | |||
342 | return; | |||
343 | ||||
344 | SwDoc& rDestDoc = rCpyPam.GetDoc(); | |||
345 | SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End(); | |||
346 | std::unique_ptr<SwPaM> pDelPam; | |||
347 | const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); | |||
348 | // We have to count the "non-copied" nodes | |||
349 | sal_uLong nDelCount; | |||
350 | SwNodeIndex aCorrIdx(InitDelCount(rPam, nDelCount)); | |||
351 | ||||
352 | SwRedlineTable::size_type n = 0; | |||
353 | rSrcDoc.getIDocumentRedlineAccess().GetRedline( *pStt, &n ); | |||
354 | for( ; n < rTable.size(); ++n ) | |||
355 | { | |||
356 | const SwRangeRedline* pRedl = rTable[ n ]; | |||
357 | if( RedlineType::Delete == pRedl->GetType() && pRedl->IsVisible() ) | |||
358 | { | |||
359 | const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); | |||
360 | ||||
361 | SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); | |||
362 | switch( eCmpPos ) | |||
363 | { | |||
364 | case SwComparePosition::CollideEnd: | |||
365 | case SwComparePosition::Before: | |||
366 | // Pos1 is before Pos2 | |||
367 | break; | |||
368 | ||||
369 | case SwComparePosition::CollideStart: | |||
370 | case SwComparePosition::Behind: | |||
371 | // Pos1 is after Pos2 | |||
372 | n = rTable.size(); | |||
373 | break; | |||
374 | ||||
375 | default: | |||
376 | { | |||
377 | pDelPam.reset(new SwPaM( *pCpyStt, pDelPam.release() )); | |||
378 | if( *pStt < *pRStt ) | |||
379 | { | |||
380 | lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount ); | |||
381 | lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt, | |||
382 | *pDelPam->GetPoint(), nDelCount ); | |||
383 | } | |||
384 | pDelPam->SetMark(); | |||
385 | ||||
386 | if( *pEnd < *pREnd ) | |||
387 | *pDelPam->GetPoint() = *pCpyEnd; | |||
388 | else | |||
389 | { | |||
390 | lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount ); | |||
391 | lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt, | |||
392 | *pDelPam->GetPoint(), nDelCount ); | |||
393 | } | |||
394 | ||||
395 | if (pDelPam->GetNext() && *pDelPam->GetNext()->End() == *pDelPam->Start()) | |||
396 | { | |||
397 | *pDelPam->GetNext()->End() = *pDelPam->End(); | |||
398 | pDelPam.reset(pDelPam->GetNext()); | |||
399 | } | |||
400 | } | |||
401 | } | |||
402 | } | |||
403 | } | |||
404 | ||||
405 | if( !pDelPam ) | |||
406 | return; | |||
407 | ||||
408 | RedlineFlags eOld = rDestDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
409 | rDestDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld | RedlineFlags::Ignore ); | |||
410 | ||||
411 | ::sw::UndoGuard const undoGuard(rDestDoc.GetIDocumentUndoRedo()); | |||
412 | ||||
413 | do { | |||
414 | rDestDoc.getIDocumentContentOperations().DeleteAndJoin( *pDelPam->GetNext() ); | |||
415 | if( !pDelPam->IsMultiSelection() ) | |||
416 | break; | |||
417 | delete pDelPam->GetNext(); | |||
418 | } while( true ); | |||
419 | ||||
420 | rDestDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
421 | } | |||
422 | ||||
423 | void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange const & rCpyRg ) | |||
424 | { | |||
425 | SwDoc& rSrcDoc = rRg.aStart.GetNode().GetDoc(); | |||
426 | if( !rSrcDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) | |||
427 | { | |||
428 | SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); | |||
429 | SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd ); | |||
430 | lcl_DeleteRedlines( aRgTmp, aCpyTmp ); | |||
431 | } | |||
432 | } | |||
433 | ||||
434 | void lcl_ChainFormats( SwFlyFrameFormat *pSrc, SwFlyFrameFormat *pDest ) | |||
435 | { | |||
436 | SwFormatChain aSrc( pSrc->GetChain() ); | |||
437 | if ( !aSrc.GetNext() ) | |||
438 | { | |||
439 | aSrc.SetNext( pDest ); | |||
440 | pSrc->SetFormatAttr( aSrc ); | |||
441 | } | |||
442 | SwFormatChain aDest( pDest->GetChain() ); | |||
443 | if ( !aDest.GetPrev() ) | |||
444 | { | |||
445 | aDest.SetPrev( pSrc ); | |||
446 | pDest->SetFormatAttr( aDest ); | |||
447 | } | |||
448 | } | |||
449 | ||||
450 | // #i86492# | |||
451 | bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam ) | |||
452 | { | |||
453 | bool bRet = false; | |||
454 | ||||
455 | const SwTextNode* pTextNd = rPam.Start()->nNode.GetNode().GetTextNode(); | |||
456 | const SwTextNode* pEndTextNd = rPam.End()->nNode.GetNode().GetTextNode(); | |||
457 | if ( pTextNd && pTextNd->IsInList() && | |||
458 | pEndTextNd && pEndTextNd->IsInList() ) | |||
459 | { | |||
460 | bRet = true; | |||
461 | SwNodeIndex aIdx(rPam.Start()->nNode); | |||
462 | ||||
463 | do | |||
464 | { | |||
465 | ++aIdx; | |||
466 | pTextNd = aIdx.GetNode().GetTextNode(); | |||
467 | ||||
468 | if ( !pTextNd || !pTextNd->IsInList() ) | |||
469 | { | |||
470 | bRet = false; | |||
471 | break; | |||
472 | } | |||
473 | } while (pTextNd != pEndTextNd); | |||
474 | } | |||
475 | ||||
476 | return bRet; | |||
477 | } | |||
478 | ||||
479 | bool lcl_MarksWholeNode(const SwPaM & rPam) | |||
480 | { | |||
481 | bool bResult = false; | |||
482 | const SwPosition* pStt = rPam.Start(); | |||
483 | const SwPosition* pEnd = rPam.End(); | |||
484 | ||||
485 | if (nullptr != pStt && nullptr != pEnd) | |||
486 | { | |||
487 | const SwTextNode* pSttNd = pStt->nNode.GetNode().GetTextNode(); | |||
488 | const SwTextNode* pEndNd = pEnd->nNode.GetNode().GetTextNode(); | |||
489 | ||||
490 | if (nullptr != pSttNd && nullptr != pEndNd && | |||
491 | pStt->nContent.GetIndex() == 0 && | |||
492 | pEnd->nContent.GetIndex() == pEndNd->Len()) | |||
493 | { | |||
494 | bResult = true; | |||
495 | } | |||
496 | } | |||
497 | ||||
498 | return bResult; | |||
499 | } | |||
500 | } | |||
501 | ||||
502 | //local functions originally from sw/source/core/doc/docedt.cxx | |||
503 | namespace sw | |||
504 | { | |||
505 | void CalcBreaks(std::vector<std::pair<sal_uLong, sal_Int32>> & rBreaks, | |||
506 | SwPaM const & rPam, bool const isOnlyFieldmarks) | |||
507 | { | |||
508 | sal_uLong const nStartNode(rPam.Start()->nNode.GetIndex()); | |||
509 | sal_uLong const nEndNode(rPam.End()->nNode.GetIndex()); | |||
510 | SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes()); | |||
511 | IDocumentMarkAccess const& rIDMA(*rPam.GetDoc().getIDocumentMarkAccess()); | |||
512 | ||||
513 | std::stack<std::tuple<sw::mark::IFieldmark const*, bool, sal_uLong, sal_Int32>> startedFields; | |||
514 | ||||
515 | for (sal_uLong n = nStartNode; n <= nEndNode; ++n) | |||
516 | { | |||
517 | SwNode *const pNode(rNodes[n]); | |||
518 | if (pNode->IsTextNode()) | |||
519 | { | |||
520 | SwTextNode & rTextNode(*pNode->GetTextNode()); | |||
521 | sal_Int32 const nStart(n == nStartNode | |||
522 | ? rPam.Start()->nContent.GetIndex() | |||
523 | : 0); | |||
524 | sal_Int32 const nEnd(n == nEndNode | |||
525 | ? rPam.End()->nContent.GetIndex() | |||
526 | : rTextNode.Len()); | |||
527 | for (sal_Int32 i = nStart; i < nEnd; ++i) | |||
528 | { | |||
529 | const sal_Unicode c(rTextNode.GetText()[i]); | |||
530 | switch (c) | |||
531 | { | |||
532 | // note: CH_TXT_ATR_FORMELEMENT does not need handling | |||
533 | // not sure how CH_TXT_ATR_INPUTFIELDSTART/END are currently handled | |||
534 | case CH_TXTATR_INWORDu'\xFFF9': | |||
535 | case CH_TXTATR_BREAKWORDu'\x0001': | |||
536 | { | |||
537 | // META hints only have dummy char at the start, not | |||
538 | // at the end, so no need to check in nStartNode | |||
539 | if (n == nEndNode && !isOnlyFieldmarks) | |||
540 | { | |||
541 | SwTextAttr const*const pAttr(rTextNode.GetTextAttrForCharAt(i)); | |||
542 | if (pAttr && pAttr->End() && (nEnd < *pAttr->End())) | |||
543 | { | |||
544 | assert(pAttr->HasDummyChar())(static_cast <bool> (pAttr->HasDummyChar()) ? void ( 0) : __assert_fail ("pAttr->HasDummyChar()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 544, __extension__ __PRETTY_FUNCTION__)); | |||
545 | rBreaks.emplace_back(n, i); | |||
546 | } | |||
547 | } | |||
548 | break; | |||
549 | } | |||
550 | case CH_TXT_ATR_FIELDSTARTu'\x0007': | |||
551 | { | |||
552 | auto const pFieldMark(rIDMA.getFieldmarkAt(SwPosition(rTextNode, i))); | |||
553 | startedFields.emplace(pFieldMark, false, 0, 0); | |||
554 | break; | |||
555 | } | |||
556 | case CH_TXT_ATR_FIELDSEPu'\x0003': | |||
557 | { | |||
558 | if (startedFields.empty()) | |||
559 | { | |||
560 | rBreaks.emplace_back(n, i); | |||
561 | } | |||
562 | else | |||
563 | { // no way to find the field via MarkManager... | |||
564 | assert(std::get<0>(startedFields.top())->IsCoveringPosition(SwPosition(rTextNode, i)))(static_cast <bool> (std::get<0>(startedFields.top ())->IsCoveringPosition(SwPosition(rTextNode, i))) ? void ( 0) : __assert_fail ("std::get<0>(startedFields.top())->IsCoveringPosition(SwPosition(rTextNode, i))" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 564, __extension__ __PRETTY_FUNCTION__)); | |||
565 | std::get<1>(startedFields.top()) = true; | |||
566 | std::get<2>(startedFields.top()) = n; | |||
567 | std::get<3>(startedFields.top()) = i; | |||
568 | } | |||
569 | break; | |||
570 | } | |||
571 | case CH_TXT_ATR_FIELDENDu'\x0008': | |||
572 | { | |||
573 | if (startedFields.empty()) | |||
574 | { | |||
575 | rBreaks.emplace_back(n, i); | |||
576 | } | |||
577 | else | |||
578 | { // fieldmarks must not overlap => stack | |||
579 | assert(std::get<0>(startedFields.top()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i)))(static_cast <bool> (std::get<0>(startedFields.top ()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i))) ? void (0) : __assert_fail ("std::get<0>(startedFields.top()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i))" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 579, __extension__ __PRETTY_FUNCTION__)); | |||
580 | startedFields.pop(); | |||
581 | } | |||
582 | break; | |||
583 | } | |||
584 | } | |||
585 | } | |||
586 | } | |||
587 | else if (pNode->IsStartNode()) | |||
588 | { | |||
589 | if (pNode->EndOfSectionIndex() <= nEndNode) | |||
590 | { // fieldmark cannot overlap node section | |||
591 | n = pNode->EndOfSectionIndex(); | |||
592 | } | |||
593 | } | |||
594 | else | |||
595 | { // EndNode can actually happen with sections :( | |||
596 | assert(pNode->IsEndNode() || pNode->IsNoTextNode())(static_cast <bool> (pNode->IsEndNode() || pNode-> IsNoTextNode()) ? void (0) : __assert_fail ("pNode->IsEndNode() || pNode->IsNoTextNode()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 596, __extension__ __PRETTY_FUNCTION__)); | |||
597 | } | |||
598 | } | |||
599 | while (!startedFields.empty()) | |||
600 | { | |||
601 | SwPosition const& rStart(std::get<0>(startedFields.top())->GetMarkStart()); | |||
602 | std::pair<sal_uLong, sal_Int32> const pos( | |||
603 | rStart.nNode.GetIndex(), rStart.nContent.GetIndex()); | |||
604 | auto it = std::lower_bound(rBreaks.begin(), rBreaks.end(), pos); | |||
605 | assert(it == rBreaks.end() || *it != pos)(static_cast <bool> (it == rBreaks.end() || *it != pos) ? void (0) : __assert_fail ("it == rBreaks.end() || *it != pos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 605, __extension__ __PRETTY_FUNCTION__)); | |||
606 | rBreaks.insert(it, pos); | |||
607 | if (std::get<1>(startedFields.top())) | |||
608 | { | |||
609 | std::pair<sal_uLong, sal_Int32> const posSep( | |||
610 | std::get<2>(startedFields.top()), | |||
611 | std::get<3>(startedFields.top())); | |||
612 | it = std::lower_bound(rBreaks.begin(), rBreaks.end(), posSep); | |||
613 | assert(it == rBreaks.end() || *it != posSep)(static_cast <bool> (it == rBreaks.end() || *it != posSep ) ? void (0) : __assert_fail ("it == rBreaks.end() || *it != posSep" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 613, __extension__ __PRETTY_FUNCTION__)); | |||
614 | rBreaks.insert(it, posSep); | |||
615 | } | |||
616 | startedFields.pop(); | |||
617 | } | |||
618 | } | |||
619 | } | |||
620 | ||||
621 | namespace | |||
622 | { | |||
623 | ||||
624 | bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & rDocumentContentOperations, SwPaM & rPam, | |||
625 | bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false) | |||
626 | { | |||
627 | std::vector<std::pair<sal_uLong, sal_Int32>> Breaks; | |||
628 | ||||
629 | sw::CalcBreaks(Breaks, rPam); | |||
630 | ||||
631 | if (Breaks.empty()) | |||
632 | { | |||
633 | return (rDocumentContentOperations.*pFunc)(rPam, bForceJoinNext); | |||
634 | } | |||
635 | ||||
636 | // Deletion must be split into several parts if the text node | |||
637 | // contains a text attribute with end and with dummy character | |||
638 | // and the selection does not contain the text attribute completely, | |||
639 | // but overlaps its start (left), where the dummy character is. | |||
640 | ||||
641 | SwPosition const & rSelectionEnd( *rPam.End() ); | |||
642 | ||||
643 | bool bRet( true ); | |||
644 | // iterate from end to start, to avoid invalidating the offsets! | |||
645 | auto iter( Breaks.rbegin() ); | |||
646 | sal_uLong nOffset(0); | |||
647 | SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes()); | |||
648 | SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node! | |||
649 | SwPosition & rEnd( *aPam.End() ); | |||
650 | SwPosition & rStart( *aPam.Start() ); | |||
651 | ||||
652 | while (iter != Breaks.rend()) | |||
653 | { | |||
654 | rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1); | |||
655 | if (rStart < rEnd) // check if part is empty | |||
656 | { | |||
657 | bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext); | |||
658 | nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes... | |||
659 | } | |||
660 | rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second); | |||
661 | ++iter; | |||
662 | } | |||
663 | ||||
664 | rStart = *rPam.Start(); // set to original start | |||
665 | if (rStart < rEnd) // check if part is empty | |||
666 | { | |||
667 | bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext); | |||
668 | } | |||
669 | ||||
670 | return bRet; | |||
671 | } | |||
672 | ||||
673 | bool lcl_StrLenOverflow( const SwPaM& rPam ) | |||
674 | { | |||
675 | // If we try to merge two paragraphs we have to test if afterwards | |||
676 | // the string doesn't exceed the allowed string length | |||
677 | if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) | |||
678 | { | |||
679 | const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End(); | |||
680 | const SwTextNode* pEndNd = pEnd->nNode.GetNode().GetTextNode(); | |||
681 | if( (nullptr != pEndNd) && pStt->nNode.GetNode().IsTextNode() ) | |||
682 | { | |||
683 | const sal_uInt64 nSum = pStt->nContent.GetIndex() + | |||
684 | pEndNd->GetText().getLength() - pEnd->nContent.GetIndex(); | |||
685 | return nSum > o3tl::make_unsigned(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)); | |||
686 | } | |||
687 | } | |||
688 | return false; | |||
689 | } | |||
690 | ||||
691 | struct SaveRedline | |||
692 | { | |||
693 | SwRangeRedline* pRedl; | |||
694 | sal_uInt32 nStt, nEnd; | |||
695 | sal_Int32 nSttCnt; | |||
696 | sal_Int32 nEndCnt; | |||
697 | ||||
698 | SaveRedline( SwRangeRedline* pR, const SwNodeIndex& rSttIdx ) | |||
699 | : pRedl(pR) | |||
700 | , nEnd(0) | |||
701 | , nEndCnt(0) | |||
702 | { | |||
703 | const SwPosition* pStt = pR->Start(), | |||
704 | * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark(); | |||
705 | sal_uInt32 nSttIdx = rSttIdx.GetIndex(); | |||
706 | nStt = pStt->nNode.GetIndex() - nSttIdx; | |||
707 | nSttCnt = pStt->nContent.GetIndex(); | |||
708 | if( pR->HasMark() ) | |||
709 | { | |||
710 | nEnd = pEnd->nNode.GetIndex() - nSttIdx; | |||
711 | nEndCnt = pEnd->nContent.GetIndex(); | |||
712 | } | |||
713 | ||||
714 | pRedl->GetPoint()->nNode = 0; | |||
715 | pRedl->GetPoint()->nContent.Assign( nullptr, 0 ); | |||
716 | pRedl->GetMark()->nNode = 0; | |||
717 | pRedl->GetMark()->nContent.Assign( nullptr, 0 ); | |||
718 | } | |||
719 | ||||
720 | SaveRedline( SwRangeRedline* pR, const SwPosition& rPos ) | |||
721 | : pRedl(pR) | |||
722 | , nEnd(0) | |||
723 | , nEndCnt(0) | |||
724 | { | |||
725 | const SwPosition* pStt = pR->Start(), | |||
726 | * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark(); | |||
727 | sal_uInt32 nSttIdx = rPos.nNode.GetIndex(); | |||
728 | nStt = pStt->nNode.GetIndex() - nSttIdx; | |||
729 | nSttCnt = pStt->nContent.GetIndex(); | |||
730 | if( nStt == 0 ) | |||
731 | nSttCnt = nSttCnt - rPos.nContent.GetIndex(); | |||
732 | if( pR->HasMark() ) | |||
733 | { | |||
734 | nEnd = pEnd->nNode.GetIndex() - nSttIdx; | |||
735 | nEndCnt = pEnd->nContent.GetIndex(); | |||
736 | if( nEnd == 0 ) | |||
737 | nEndCnt = nEndCnt - rPos.nContent.GetIndex(); | |||
738 | } | |||
739 | ||||
740 | pRedl->GetPoint()->nNode = 0; | |||
741 | pRedl->GetPoint()->nContent.Assign( nullptr, 0 ); | |||
742 | pRedl->GetMark()->nNode = 0; | |||
743 | pRedl->GetMark()->nContent.Assign( nullptr, 0 ); | |||
744 | } | |||
745 | ||||
746 | void SetPos( sal_uInt32 nInsPos ) | |||
747 | { | |||
748 | pRedl->GetPoint()->nNode = nInsPos + nStt; | |||
749 | pRedl->GetPoint()->nContent.Assign( pRedl->GetContentNode(), nSttCnt ); | |||
750 | if( pRedl->HasMark() ) | |||
751 | { | |||
752 | pRedl->GetMark()->nNode = nInsPos + nEnd; | |||
753 | pRedl->GetMark()->nContent.Assign( pRedl->GetContentNode(false), nEndCnt ); | |||
754 | } | |||
755 | } | |||
756 | ||||
757 | void SetPos( const SwPosition& aPos ) | |||
758 | { | |||
759 | pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt; | |||
760 | pRedl->GetPoint()->nContent.Assign( pRedl->GetContentNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) ); | |||
761 | if( pRedl->HasMark() ) | |||
762 | { | |||
763 | pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd; | |||
764 | pRedl->GetMark()->nContent.Assign( pRedl->GetContentNode(false), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) ); | |||
765 | } | |||
766 | } | |||
767 | }; | |||
768 | ||||
769 | typedef std::vector< SaveRedline > SaveRedlines_t; | |||
770 | ||||
771 | void lcl_SaveRedlines(const SwPaM& aPam, SaveRedlines_t& rArr) | |||
772 | { | |||
773 | SwDoc& rDoc = aPam.GetNode().GetDoc(); | |||
774 | ||||
775 | const SwPosition* pStart = aPam.Start(); | |||
776 | const SwPosition* pEnd = aPam.End(); | |||
777 | ||||
778 | // get first relevant redline | |||
779 | SwRedlineTable::size_type nCurrentRedline; | |||
780 | rDoc.getIDocumentRedlineAccess().GetRedline( *pStart, &nCurrentRedline ); | |||
781 | if( nCurrentRedline > 0) | |||
782 | nCurrentRedline--; | |||
783 | ||||
784 | // redline mode RedlineFlags::Ignore|RedlineFlags::On; save old mode | |||
785 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
786 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On ); | |||
787 | ||||
788 | // iterate over relevant redlines and decide for each whether it should | |||
789 | // be saved, or split + saved | |||
790 | SwRedlineTable& rRedlineTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); | |||
791 | for( ; nCurrentRedline < rRedlineTable.size(); nCurrentRedline++ ) | |||
792 | { | |||
793 | SwRangeRedline* pCurrent = rRedlineTable[ nCurrentRedline ]; | |||
794 | SwComparePosition eCompare = | |||
795 | ComparePosition( *pCurrent->Start(), *pCurrent->End(), | |||
796 | *pStart, *pEnd); | |||
797 | ||||
798 | // we must save this redline if it overlaps aPam | |||
799 | // (we may have to split it, too) | |||
800 | if( eCompare == SwComparePosition::OverlapBehind || | |||
801 | eCompare == SwComparePosition::OverlapBefore || | |||
802 | eCompare == SwComparePosition::Outside || | |||
803 | eCompare == SwComparePosition::Inside || | |||
804 | eCompare == SwComparePosition::Equal ) | |||
805 | { | |||
806 | rRedlineTable.Remove( nCurrentRedline-- ); | |||
807 | ||||
808 | // split beginning, if necessary | |||
809 | if( eCompare == SwComparePosition::OverlapBefore || | |||
810 | eCompare == SwComparePosition::Outside ) | |||
811 | { | |||
812 | SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent ); | |||
813 | *pNewRedline->End() = *pStart; | |||
814 | *pCurrent->Start() = *pStart; | |||
815 | rDoc.getIDocumentRedlineAccess().AppendRedline( pNewRedline, true ); | |||
816 | } | |||
817 | ||||
818 | // split end, if necessary | |||
819 | if( eCompare == SwComparePosition::OverlapBehind || | |||
820 | eCompare == SwComparePosition::Outside ) | |||
821 | { | |||
822 | SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent ); | |||
823 | *pNewRedline->Start() = *pEnd; | |||
824 | *pCurrent->End() = *pEnd; | |||
825 | rDoc.getIDocumentRedlineAccess().AppendRedline( pNewRedline, true ); | |||
826 | } | |||
827 | ||||
828 | // save the current redline | |||
829 | rArr.emplace_back( pCurrent, *pStart ); | |||
830 | } | |||
831 | } | |||
832 | ||||
833 | // restore old redline mode | |||
834 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
835 | } | |||
836 | ||||
837 | void lcl_RestoreRedlines(SwDoc& rDoc, const SwPosition& rPos, SaveRedlines_t& rArr) | |||
838 | { | |||
839 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
840 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On ); | |||
841 | ||||
842 | for(SaveRedline & rSvRedLine : rArr) | |||
843 | { | |||
844 | rSvRedLine.SetPos( rPos ); | |||
845 | rDoc.getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true ); | |||
846 | } | |||
847 | ||||
848 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
849 | } | |||
850 | ||||
851 | void lcl_SaveRedlines(const SwNodeRange& rRg, SaveRedlines_t& rArr) | |||
852 | { | |||
853 | SwDoc& rDoc = rRg.aStart.GetNode().GetDoc(); | |||
854 | SwRedlineTable::size_type nRedlPos; | |||
855 | SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--; | |||
856 | aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetContentNode(), 0 ); | |||
857 | if( rDoc.getIDocumentRedlineAccess().GetRedline( aSrchPos, &nRedlPos ) && nRedlPos ) | |||
858 | --nRedlPos; | |||
859 | else if( nRedlPos >= rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() ) | |||
860 | return ; | |||
861 | ||||
862 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
863 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On ); | |||
864 | SwRedlineTable& rRedlTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); | |||
865 | ||||
866 | do { | |||
867 | SwRangeRedline* pTmp = rRedlTable[ nRedlPos ]; | |||
868 | ||||
869 | const SwPosition* pRStt = pTmp->Start(), | |||
870 | * pREnd = pTmp->GetMark() == pRStt | |||
871 | ? pTmp->GetPoint() : pTmp->GetMark(); | |||
872 | ||||
873 | if( pRStt->nNode < rRg.aStart ) | |||
874 | { | |||
875 | if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd ) | |||
876 | { | |||
877 | // Create a copy and set the end of the original to the end of the MoveArea. | |||
878 | // The copy is moved too. | |||
879 | SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp ); | |||
880 | SwPosition* pTmpPos = pNewRedl->Start(); | |||
881 | pTmpPos->nNode = rRg.aStart; | |||
882 | pTmpPos->nContent.Assign( | |||
883 | pTmpPos->nNode.GetNode().GetContentNode(), 0 ); | |||
884 | ||||
885 | rArr.emplace_back(pNewRedl, rRg.aStart); | |||
886 | ||||
887 | pTmpPos = pTmp->End(); | |||
888 | pTmpPos->nNode = rRg.aEnd; | |||
889 | pTmpPos->nContent.Assign( | |||
890 | pTmpPos->nNode.GetNode().GetContentNode(), 0 ); | |||
891 | } | |||
892 | else if( pREnd->nNode == rRg.aStart ) | |||
893 | { | |||
894 | SwPosition* pTmpPos = pTmp->End(); | |||
895 | pTmpPos->nNode = rRg.aEnd; | |||
896 | pTmpPos->nContent.Assign( | |||
897 | pTmpPos->nNode.GetNode().GetContentNode(), 0 ); | |||
898 | } | |||
899 | } | |||
900 | else if( pRStt->nNode < rRg.aEnd ) | |||
901 | { | |||
902 | rRedlTable.Remove( nRedlPos-- ); | |||
903 | if( pREnd->nNode < rRg.aEnd || | |||
904 | ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) ) | |||
905 | { | |||
906 | // move everything | |||
907 | rArr.emplace_back( pTmp, rRg.aStart ); | |||
908 | } | |||
909 | else | |||
910 | { | |||
911 | // split | |||
912 | SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp ); | |||
913 | SwPosition* pTmpPos = pNewRedl->End(); | |||
914 | pTmpPos->nNode = rRg.aEnd; | |||
915 | pTmpPos->nContent.Assign( | |||
916 | pTmpPos->nNode.GetNode().GetContentNode(), 0 ); | |||
917 | ||||
918 | rArr.emplace_back( pNewRedl, rRg.aStart ); | |||
919 | ||||
920 | pTmpPos = pTmp->Start(); | |||
921 | pTmpPos->nNode = rRg.aEnd; | |||
922 | pTmpPos->nContent.Assign( | |||
923 | pTmpPos->nNode.GetNode().GetContentNode(), 0 ); | |||
924 | rDoc.getIDocumentRedlineAccess().AppendRedline( pTmp, true ); | |||
925 | } | |||
926 | } | |||
927 | else | |||
928 | break; | |||
929 | ||||
930 | } while( ++nRedlPos < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() ); | |||
931 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
932 | } | |||
933 | ||||
934 | void lcl_RestoreRedlines(SwDoc& rDoc, sal_uInt32 const nInsPos, SaveRedlines_t& rArr) | |||
935 | { | |||
936 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
937 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On ); | |||
938 | ||||
939 | for(SaveRedline & rSvRedLine : rArr) | |||
940 | { | |||
941 | rSvRedLine.SetPos( nInsPos ); | |||
942 | rDoc.getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true ); | |||
943 | if (rSvRedLine.pRedl->GetType() == RedlineType::Delete) | |||
944 | { | |||
945 | UpdateFramesForAddDeleteRedline(rDoc, *rSvRedLine.pRedl); | |||
946 | } | |||
947 | } | |||
948 | ||||
949 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
950 | } | |||
951 | ||||
952 | bool lcl_SaveFootnote( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd, | |||
953 | const SwNodeIndex& rInsPos, | |||
954 | SwFootnoteIdxs& rFootnoteArr, SwFootnoteIdxs& rSaveArr, | |||
955 | const SwIndex* pSttCnt = nullptr, const SwIndex* pEndCnt = nullptr ) | |||
956 | { | |||
957 | bool bUpdateFootnote = false; | |||
958 | const SwNodes& rNds = rInsPos.GetNodes(); | |||
959 | const bool bDelFootnote = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() && | |||
960 | rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex(); | |||
961 | const bool bSaveFootnote = !bDelFootnote && | |||
962 | rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex(); | |||
963 | if( !rFootnoteArr.empty() ) | |||
964 | { | |||
965 | ||||
966 | size_t nPos = 0; | |||
967 | rFootnoteArr.SeekEntry( rSttNd, &nPos ); | |||
968 | SwTextFootnote* pSrch; | |||
969 | const SwNode* pFootnoteNd; | |||
970 | ||||
971 | // Delete/save all that come after it | |||
972 | while( nPos < rFootnoteArr.size() && ( pFootnoteNd = | |||
973 | &( pSrch = rFootnoteArr[ nPos ] )->GetTextNode())->GetIndex() | |||
974 | <= rEndNd.GetIndex() ) | |||
975 | { | |||
976 | const sal_Int32 nFootnoteSttIdx = pSrch->GetStart(); | |||
977 | if( ( pEndCnt && pSttCnt ) | |||
978 | ? (( &rSttNd.GetNode() == pFootnoteNd && | |||
979 | pSttCnt->GetIndex() > nFootnoteSttIdx) || | |||
980 | ( &rEndNd.GetNode() == pFootnoteNd && | |||
981 | nFootnoteSttIdx >= pEndCnt->GetIndex() )) | |||
982 | : ( &rEndNd.GetNode() == pFootnoteNd )) | |||
983 | { | |||
984 | ++nPos; // continue searching | |||
985 | } | |||
986 | else | |||
987 | { | |||
988 | // delete it | |||
989 | if( bDelFootnote ) | |||
990 | { | |||
991 | SwTextNode& rTextNd = const_cast<SwTextNode&>(pSrch->GetTextNode()); | |||
992 | SwIndex aIdx( &rTextNd, nFootnoteSttIdx ); | |||
993 | rTextNd.EraseText( aIdx, 1 ); | |||
994 | } | |||
995 | else | |||
996 | { | |||
997 | pSrch->DelFrames(nullptr); | |||
998 | rFootnoteArr.erase( rFootnoteArr.begin() + nPos ); | |||
999 | if( bSaveFootnote ) | |||
1000 | rSaveArr.insert( pSrch ); | |||
1001 | } | |||
1002 | bUpdateFootnote = true; | |||
1003 | } | |||
1004 | } | |||
1005 | ||||
1006 | while( nPos-- && ( pFootnoteNd = &( pSrch = rFootnoteArr[ nPos ] )-> | |||
1007 | GetTextNode())->GetIndex() >= rSttNd.GetIndex() ) | |||
1008 | { | |||
1009 | const sal_Int32 nFootnoteSttIdx = pSrch->GetStart(); | |||
1010 | if( !pEndCnt || !pSttCnt || | |||
1011 | ! (( &rSttNd.GetNode() == pFootnoteNd && | |||
1012 | pSttCnt->GetIndex() > nFootnoteSttIdx ) || | |||
1013 | ( &rEndNd.GetNode() == pFootnoteNd && | |||
1014 | nFootnoteSttIdx >= pEndCnt->GetIndex() )) ) | |||
1015 | { | |||
1016 | if( bDelFootnote ) | |||
1017 | { | |||
1018 | // delete it | |||
1019 | SwTextNode& rTextNd = const_cast<SwTextNode&>(pSrch->GetTextNode()); | |||
1020 | SwIndex aIdx( &rTextNd, nFootnoteSttIdx ); | |||
1021 | rTextNd.EraseText( aIdx, 1 ); | |||
1022 | } | |||
1023 | else | |||
1024 | { | |||
1025 | pSrch->DelFrames(nullptr); | |||
1026 | rFootnoteArr.erase( rFootnoteArr.begin() + nPos ); | |||
1027 | if( bSaveFootnote ) | |||
1028 | rSaveArr.insert( pSrch ); | |||
1029 | } | |||
1030 | bUpdateFootnote = true; | |||
1031 | } | |||
1032 | } | |||
1033 | } | |||
1034 | // When moving from redline section into document content section, e.g. | |||
1035 | // after loading a document with (delete-)redlines, the footnote array | |||
1036 | // has to be adjusted... (#i70572) | |||
1037 | if( bSaveFootnote ) | |||
1038 | { | |||
1039 | SwNodeIndex aIdx( rSttNd ); | |||
1040 | while( aIdx < rEndNd ) // Check the moved section | |||
1041 | { | |||
1042 | SwNode* pNode = &aIdx.GetNode(); | |||
1043 | if( pNode->IsTextNode() ) // Looking for text nodes... | |||
1044 | { | |||
1045 | SwpHints *pHints = pNode->GetTextNode()->GetpSwpHints(); | |||
1046 | if( pHints && pHints->HasFootnote() ) //...with footnotes | |||
1047 | { | |||
1048 | bUpdateFootnote = true; // Heureka | |||
1049 | const size_t nCount = pHints->Count(); | |||
1050 | for( size_t i = 0; i < nCount; ++i ) | |||
1051 | { | |||
1052 | SwTextAttr *pAttr = pHints->Get( i ); | |||
1053 | if ( pAttr->Which() == RES_TXTATR_FTN ) | |||
1054 | { | |||
1055 | rSaveArr.insert( static_cast<SwTextFootnote*>(pAttr) ); | |||
1056 | } | |||
1057 | } | |||
1058 | } | |||
1059 | } | |||
1060 | ++aIdx; | |||
1061 | } | |||
1062 | } | |||
1063 | return bUpdateFootnote; | |||
1064 | } | |||
1065 | ||||
1066 | bool lcl_MayOverwrite( const SwTextNode *pNode, const sal_Int32 nPos ) | |||
1067 | { | |||
1068 | sal_Unicode const cChr = pNode->GetText()[nPos]; | |||
1069 | switch (cChr) | |||
1070 | { | |||
1071 | case CH_TXTATR_BREAKWORDu'\x0001': | |||
1072 | case CH_TXTATR_INWORDu'\xFFF9': | |||
1073 | return !pNode->GetTextAttrForCharAt(nPos);// how could there be none? | |||
1074 | case CH_TXT_ATR_INPUTFIELDSTARTu'\x0004': | |||
1075 | case CH_TXT_ATR_INPUTFIELDENDu'\x0005': | |||
1076 | case CH_TXT_ATR_FIELDSTARTu'\x0007': | |||
1077 | case CH_TXT_ATR_FIELDSEPu'\x0003': | |||
1078 | case CH_TXT_ATR_FIELDENDu'\x0008': | |||
1079 | case CH_TXT_ATR_FORMELEMENTu'\x0006': | |||
1080 | return false; | |||
1081 | default: | |||
1082 | return true; | |||
1083 | } | |||
1084 | } | |||
1085 | ||||
1086 | void lcl_SkipAttr( const SwTextNode *pNode, SwIndex &rIdx, sal_Int32 &rStart ) | |||
1087 | { | |||
1088 | if( !lcl_MayOverwrite( pNode, rStart ) ) | |||
1089 | { | |||
1090 | // skip all special attributes | |||
1091 | do { | |||
1092 | ++rIdx; | |||
1093 | rStart = rIdx.GetIndex(); | |||
1094 | } while (rStart < pNode->GetText().getLength() | |||
1095 | && !lcl_MayOverwrite(pNode, rStart) ); | |||
1096 | } | |||
1097 | } | |||
1098 | ||||
1099 | bool lcl_GetTokenToParaBreak( OUString& rStr, OUString& rRet, bool bRegExpRplc ) | |||
1100 | { | |||
1101 | if( bRegExpRplc ) | |||
1102 | { | |||
1103 | sal_Int32 nPos = 0; | |||
1104 | const OUString sPara("\\n"); | |||
1105 | for (;;) | |||
1106 | { | |||
1107 | nPos = rStr.indexOf( sPara, nPos ); | |||
1108 | if (nPos<0) | |||
1109 | { | |||
1110 | break; | |||
1111 | } | |||
1112 | // Has this been escaped? | |||
1113 | if( nPos && '\\' == rStr[nPos-1]) | |||
1114 | { | |||
1115 | ++nPos; | |||
1116 | if( nPos >= rStr.getLength() ) | |||
1117 | { | |||
1118 | break; | |||
1119 | } | |||
1120 | } | |||
1121 | else | |||
1122 | { | |||
1123 | rRet = rStr.copy( 0, nPos ); | |||
1124 | rStr = rStr.copy( nPos + sPara.getLength() ); | |||
1125 | return true; | |||
1126 | } | |||
1127 | } | |||
1128 | } | |||
1129 | rRet = rStr; | |||
1130 | rStr.clear(); | |||
1131 | return false; | |||
1132 | } | |||
1133 | } | |||
1134 | ||||
1135 | namespace //local functions originally from docfmt.cxx | |||
1136 | { | |||
1137 | ||||
1138 | bool lcl_ApplyOtherSet( | |||
1139 | SwContentNode & rNode, | |||
1140 | SwHistory *const pHistory, | |||
1141 | SfxItemSet const& rOtherSet, | |||
1142 | SfxItemSet const& rFirstSet, | |||
1143 | SfxItemSet const& rPropsSet, | |||
1144 | SwRootFrame const*const pLayout, | |||
1145 | SwNodeIndex *const o_pIndex = nullptr) | |||
1146 | { | |||
1147 | assert(rOtherSet.Count())(static_cast <bool> (rOtherSet.Count()) ? void (0) : __assert_fail ("rOtherSet.Count()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1147, __extension__ __PRETTY_FUNCTION__)); | |||
1148 | ||||
1149 | bool ret(false); | |||
1150 | SwTextNode *const pTNd = rNode.GetTextNode(); | |||
1151 | sw::MergedPara const* pMerged(nullptr); | |||
1152 | if (pLayout && pLayout->IsHideRedlines() && pTNd) | |||
1153 | { | |||
1154 | SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>( | |||
1155 | pTNd->getLayoutFrame(pLayout))); | |||
1156 | if (pTextFrame) | |||
1157 | { | |||
1158 | pMerged = pTextFrame->GetMergedPara(); | |||
1159 | } | |||
1160 | if (pMerged) | |||
1161 | { | |||
1162 | if (rFirstSet.Count()) | |||
1163 | { | |||
1164 | if (pHistory) | |||
1165 | { | |||
1166 | SwRegHistory aRegH(pMerged->pFirstNode, *pMerged->pFirstNode, pHistory); | |||
1167 | ret = pMerged->pFirstNode->SetAttr(rFirstSet); | |||
1168 | } | |||
1169 | else | |||
1170 | { | |||
1171 | ret = pMerged->pFirstNode->SetAttr(rFirstSet); | |||
1172 | } | |||
1173 | } | |||
1174 | if (rPropsSet.Count()) | |||
1175 | { | |||
1176 | if (pHistory) | |||
1177 | { | |||
1178 | SwRegHistory aRegH(pMerged->pParaPropsNode, *pMerged->pParaPropsNode, pHistory); | |||
1179 | ret = pMerged->pParaPropsNode->SetAttr(rPropsSet) || ret; | |||
1180 | } | |||
1181 | else | |||
1182 | { | |||
1183 | ret = pMerged->pParaPropsNode->SetAttr(rPropsSet) || ret; | |||
1184 | } | |||
1185 | } | |||
1186 | if (o_pIndex) | |||
1187 | { | |||
1188 | *o_pIndex = *pMerged->pLastNode; // skip hidden | |||
1189 | } | |||
1190 | } | |||
1191 | } | |||
1192 | ||||
1193 | // input cursor can't be on hidden node, and iteration skips them | |||
1194 | assert(!pLayout || !pLayout->IsHideRedlines()(static_cast <bool> (!pLayout || !pLayout->IsHideRedlines () || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden) ? void (0) : __assert_fail ("!pLayout || !pLayout->IsHideRedlines() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1195, __extension__ __PRETTY_FUNCTION__)) | |||
1195 | || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden)(static_cast <bool> (!pLayout || !pLayout->IsHideRedlines () || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden) ? void (0) : __assert_fail ("!pLayout || !pLayout->IsHideRedlines() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1195, __extension__ __PRETTY_FUNCTION__)); | |||
1196 | ||||
1197 | if (!pMerged) | |||
1198 | { | |||
1199 | if (pHistory) | |||
1200 | { | |||
1201 | SwRegHistory aRegH(&rNode, rNode, pHistory); | |||
1202 | ret = rNode.SetAttr( rOtherSet ); | |||
1203 | } | |||
1204 | else | |||
1205 | { | |||
1206 | ret = rNode.SetAttr( rOtherSet ); | |||
1207 | } | |||
1208 | } | |||
1209 | return ret; | |||
1210 | } | |||
1211 | ||||
1212 | #define DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } if ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1213 | ||||
1214 | /// Insert Hints according to content types; | |||
1215 | // Is used in SwDoc::Insert(..., SwFormatHint &rHt) | |||
1216 | ||||
1217 | bool lcl_InsAttr( | |||
1218 | SwDoc& rDoc, | |||
1219 | const SwPaM &rRg, | |||
1220 | const SfxItemSet& rChgSet, | |||
1221 | const SetAttrMode nFlags, | |||
1222 | SwUndoAttr *const pUndo, | |||
1223 | SwRootFrame const*const pLayout, | |||
1224 | const bool bExpandCharToPara, | |||
1225 | SwTextAttr **ppNewTextAttr) | |||
1226 | { | |||
1227 | // Divide the Sets (for selections in Nodes) | |||
1228 | const SfxItemSet* pCharSet = nullptr; | |||
1229 | const SfxItemSet* pOtherSet = nullptr; | |||
1230 | bool bDelete = false; | |||
1231 | bool bCharAttr = false; | |||
1232 | bool bOtherAttr = false; | |||
1233 | ||||
1234 | // Check, if we can work with rChgSet or if we have to create additional SfxItemSets | |||
1235 | if ( 1 == rChgSet.Count() ) | |||
1236 | { | |||
1237 | SfxItemIter aIter( rChgSet ); | |||
1238 | const SfxPoolItem* pItem = aIter.GetCurItem(); | |||
1239 | if (pItem && !IsInvalidItem(pItem)) | |||
1240 | { | |||
1241 | const sal_uInt16 nWhich = pItem->Which(); | |||
1242 | ||||
1243 | if ( isCHRATR(nWhich) || | |||
1244 | (RES_TXTATR_CHARFMT == nWhich) || | |||
1245 | (RES_TXTATR_INETFMT == nWhich) || | |||
1246 | (RES_TXTATR_AUTOFMT == nWhich) || | |||
1247 | (RES_TXTATR_UNKNOWN_CONTAINER == nWhich) ) | |||
1248 | { | |||
1249 | pCharSet = &rChgSet; | |||
1250 | bCharAttr = true; | |||
1251 | } | |||
1252 | ||||
1253 | if ( isPARATR(nWhich) | |||
1254 | || isPARATR_LIST(nWhich) | |||
1255 | || isFRMATR(nWhich) | |||
1256 | || isGRFATR(nWhich) | |||
1257 | || isUNKNOWNATR(nWhich) | |||
1258 | || isDrawingLayerAttribute(nWhich) ) | |||
1259 | { | |||
1260 | pOtherSet = &rChgSet; | |||
1261 | bOtherAttr = true; | |||
1262 | } | |||
1263 | } | |||
1264 | } | |||
1265 | ||||
1266 | // Build new itemset if either | |||
1267 | // - rChgSet.Count() > 1 or | |||
1268 | // - The attribute in rChgSet does not belong to one of the above categories | |||
1269 | if ( !bCharAttr && !bOtherAttr ) | |||
1270 | { | |||
1271 | SfxItemSet* pTmpCharItemSet = new SfxItemSet( | |||
1272 | rDoc.GetAttrPool(), | |||
1273 | svl::Items< | |||
1274 | RES_CHRATR_BEGIN, RES_CHRATR_END - 1, | |||
1275 | RES_TXTATR_AUTOFMT, RES_TXTATR_CHARFMT, | |||
1276 | RES_TXTATR_UNKNOWN_CONTAINER, | |||
1277 | RES_TXTATR_UNKNOWN_CONTAINER>{}); | |||
1278 | ||||
1279 | SfxItemSet* pTmpOtherItemSet = new SfxItemSet( | |||
1280 | rDoc.GetAttrPool(), | |||
1281 | svl::Items< | |||
1282 | RES_PARATR_BEGIN, RES_GRFATR_END - 1, | |||
1283 | RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1, | |||
1284 | // FillAttribute support: | |||
1285 | XATTR_FILL_FIRST, XATTR_FILL_LAST>{}); | |||
1286 | ||||
1287 | pTmpCharItemSet->Put( rChgSet ); | |||
1288 | pTmpOtherItemSet->Put( rChgSet ); | |||
1289 | ||||
1290 | pCharSet = pTmpCharItemSet; | |||
1291 | pOtherSet = pTmpOtherItemSet; | |||
1292 | ||||
1293 | bDelete = true; | |||
1294 | } | |||
1295 | ||||
1296 | SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : nullptr; | |||
1297 | bool bRet = false; | |||
1298 | const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End(); | |||
1299 | SwContentNode* pNode = pStt->nNode.GetNode().GetContentNode(); | |||
1300 | ||||
1301 | if( pNode && pNode->IsTextNode() ) | |||
1302 | { | |||
1303 | // tdf#127606 at editing, remove different formatting of DOCX-like numbering symbol | |||
1304 | if (pLayout && pNode->GetTextNode()->getIDocumentSettingAccess()-> | |||
1305 | get(DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING )) | |||
1306 | { | |||
1307 | SwContentNode* pEndNode = pEnd->nNode.GetNode().GetContentNode(); | |||
1308 | SwContentNode* pCurrentNode = pEndNode; | |||
1309 | auto nStartIndex = pNode->GetIndex(); | |||
1310 | auto nEndIndex = pEndNode->GetIndex(); | |||
1311 | SwNodeIndex aIdx( pEnd->nNode.GetNode() ); | |||
1312 | while ( pCurrentNode != nullptr && nStartIndex <= pCurrentNode->GetIndex() ) | |||
1313 | { | |||
1314 | if (pCurrentNode->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT) && | |||
1315 | // remove character formatting only on wholly selected paragraphs | |||
1316 | (nStartIndex < pCurrentNode->GetIndex() || pStt->nContent.GetIndex() == 0) && | |||
1317 | (pCurrentNode->GetIndex() < nEndIndex || pEnd->nContent.GetIndex() == pEndNode->Len())) | |||
1318 | { | |||
1319 | pCurrentNode->ResetAttr(RES_PARATR_LIST_AUTOFMT); | |||
1320 | // reset also paragraph marker | |||
1321 | SwIndex nIdx( pCurrentNode, pCurrentNode->Len() ); | |||
1322 | pCurrentNode->GetTextNode()->RstTextAttr(nIdx, 1); | |||
1323 | } | |||
1324 | pCurrentNode = SwNodes::GoPrevious( &aIdx ); | |||
1325 | } | |||
1326 | } | |||
1327 | // #i27615# | |||
1328 | if (rRg.IsInFrontOfLabel()) | |||
1329 | { | |||
1330 | SwTextNode * pTextNd = pNode->GetTextNode(); | |||
1331 | if (pLayout) | |||
1332 | { | |||
1333 | pTextNd = sw::GetParaPropsNode(*pLayout, *pTextNd); | |||
1334 | } | |||
1335 | SwNumRule * pNumRule = pTextNd->GetNumRule(); | |||
1336 | ||||
1337 | if ( !pNumRule ) | |||
1338 | { | |||
1339 | OSL_FAIL( "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "1339" ": "), "%s", "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect." ); } } while (false); | |||
1340 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1341 | return false; | |||
1342 | } | |||
1343 | ||||
1344 | int nLevel = pTextNd->GetActualListLevel(); | |||
1345 | ||||
1346 | if (nLevel < 0) | |||
1347 | nLevel = 0; | |||
1348 | ||||
1349 | if (nLevel >= MAXLEVEL) | |||
1350 | nLevel = MAXLEVEL - 1; | |||
1351 | ||||
1352 | SwNumFormat aNumFormat = pNumRule->Get(static_cast<sal_uInt16>(nLevel)); | |||
1353 | SwCharFormat * pCharFormat = | |||
1354 | rDoc.FindCharFormatByName(aNumFormat.GetCharFormatName()); | |||
1355 | ||||
1356 | if (pCharFormat) | |||
1357 | { | |||
1358 | if (pHistory) | |||
1359 | pHistory->Add(pCharFormat->GetAttrSet(), *pCharFormat); | |||
1360 | ||||
1361 | if ( pCharSet ) | |||
1362 | pCharFormat->SetFormatAttr(*pCharSet); | |||
1363 | } | |||
1364 | ||||
1365 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1366 | return true; | |||
1367 | } | |||
1368 | ||||
1369 | const SwIndex& rSt = pStt->nContent; | |||
1370 | ||||
1371 | // Attributes without an end do not have a range | |||
1372 | if ( !bCharAttr && !bOtherAttr ) | |||
1373 | { | |||
1374 | SfxItemSet aTextSet( rDoc.GetAttrPool(), | |||
1375 | svl::Items<RES_TXTATR_NOEND_BEGIN, RES_TXTATR_NOEND_END-1>{} ); | |||
1376 | aTextSet.Put( rChgSet ); | |||
1377 | if( aTextSet.Count() ) | |||
1378 | { | |||
1379 | SwRegHistory history( pNode, *pNode, pHistory ); | |||
1380 | bRet = history.InsertItems( | |||
1381 | aTextSet, rSt.GetIndex(), rSt.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr ) || bRet; | |||
1382 | ||||
1383 | if (bRet && (rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() | |||
1384 | && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()))) | |||
1385 | { | |||
1386 | SwPaM aPam( pStt->nNode, pStt->nContent.GetIndex()-1, | |||
1387 | pStt->nNode, pStt->nContent.GetIndex() ); | |||
1388 | ||||
1389 | if( pUndo ) | |||
1390 | pUndo->SaveRedlineData( aPam, true ); | |||
1391 | ||||
1392 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
1393 | rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true); | |||
1394 | else | |||
1395 | rDoc.getIDocumentRedlineAccess().SplitRedline( aPam ); | |||
1396 | } | |||
1397 | } | |||
1398 | } | |||
1399 | ||||
1400 | // TextAttributes with an end never expand their range | |||
1401 | if ( !bCharAttr && !bOtherAttr ) | |||
1402 | { | |||
1403 | // CharFormat and URL attributes are treated separately! | |||
1404 | // TEST_TEMP ToDo: AutoFormat! | |||
1405 | SfxItemSet aTextSet( | |||
1406 | rDoc.GetAttrPool(), | |||
1407 | svl::Items< | |||
1408 | RES_TXTATR_REFMARK, RES_TXTATR_METAFIELD, | |||
1409 | RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY, | |||
1410 | RES_TXTATR_INPUTFIELD, RES_TXTATR_INPUTFIELD>{}); | |||
1411 | ||||
1412 | aTextSet.Put( rChgSet ); | |||
1413 | if( aTextSet.Count() ) | |||
1414 | { | |||
1415 | const sal_Int32 nInsCnt = rSt.GetIndex(); | |||
1416 | const sal_Int32 nEnd = pStt->nNode == pEnd->nNode | |||
1417 | ? pEnd->nContent.GetIndex() | |||
1418 | : pNode->Len(); | |||
1419 | SwRegHistory history( pNode, *pNode, pHistory ); | |||
1420 | bRet = history.InsertItems( aTextSet, nInsCnt, nEnd, nFlags, ppNewTextAttr ) | |||
1421 | || bRet; | |||
1422 | ||||
1423 | if (bRet && (rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() | |||
1424 | && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()))) | |||
1425 | { | |||
1426 | // Was text content inserted? (RefMark/TOXMarks without an end) | |||
1427 | bool bTextIns = nInsCnt != rSt.GetIndex(); | |||
1428 | // Was content inserted or set over the selection? | |||
1429 | SwPaM aPam( pStt->nNode, bTextIns ? nInsCnt + 1 : nEnd, | |||
1430 | pStt->nNode, nInsCnt ); | |||
1431 | if( pUndo ) | |||
1432 | pUndo->SaveRedlineData( aPam, bTextIns ); | |||
1433 | ||||
1434 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
1435 | rDoc.getIDocumentRedlineAccess().AppendRedline( | |||
1436 | new SwRangeRedline( | |||
1437 | bTextIns ? RedlineType::Insert : RedlineType::Format, aPam ), | |||
1438 | true); | |||
1439 | else if( bTextIns ) | |||
1440 | rDoc.getIDocumentRedlineAccess().SplitRedline( aPam ); | |||
1441 | } | |||
1442 | } | |||
1443 | } | |||
1444 | } | |||
1445 | ||||
1446 | // We always have to set the auto flag for PageDescs that are set at the Node! | |||
1447 | if( pOtherSet && pOtherSet->Count() ) | |||
1448 | { | |||
1449 | SwTableNode* pTableNd; | |||
1450 | const SwFormatPageDesc* pDesc; | |||
1451 | if( SfxItemState::SET == pOtherSet->GetItemState( RES_PAGEDESC, | |||
1452 | false, reinterpret_cast<const SfxPoolItem**>(&pDesc) )) | |||
1453 | { | |||
1454 | if( pNode ) | |||
1455 | { | |||
1456 | // Set auto flag. Only in the template it's without auto! | |||
1457 | SwFormatPageDesc aNew( *pDesc ); | |||
1458 | ||||
1459 | // Tables now also know line breaks | |||
1460 | if( !(nFlags & SetAttrMode::APICALL) && | |||
1461 | nullptr != ( pTableNd = pNode->FindTableNode() ) ) | |||
1462 | { | |||
1463 | SwTableNode* pCurTableNd = pTableNd; | |||
1464 | while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) ) | |||
1465 | pTableNd = pCurTableNd; | |||
1466 | ||||
1467 | // set the table format | |||
1468 | SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat(); | |||
1469 | SwRegHistory aRegH( pFormat, *pTableNd, pHistory ); | |||
1470 | pFormat->SetFormatAttr( aNew ); | |||
1471 | bRet = true; | |||
1472 | } | |||
1473 | else | |||
1474 | { | |||
1475 | SwContentNode * pFirstNode(pNode); | |||
1476 | if (pLayout && pLayout->IsHideRedlines()) | |||
1477 | { | |||
1478 | pFirstNode = sw::GetFirstAndLastNode(*pLayout, pStt->nNode).first; | |||
1479 | } | |||
1480 | SwRegHistory aRegH( pFirstNode, *pFirstNode, pHistory ); | |||
1481 | bRet = pFirstNode->SetAttr( aNew ) || bRet; | |||
1482 | } | |||
1483 | } | |||
1484 | ||||
1485 | // bOtherAttr = true means that pOtherSet == rChgSet. In this case | |||
1486 | // we know, that there is only one attribute in pOtherSet. We cannot | |||
1487 | // perform the following operations, instead we return: | |||
1488 | if ( bOtherAttr ) | |||
1489 | return bRet; | |||
1490 | ||||
1491 | const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_PAGEDESC ); | |||
1492 | if( !pOtherSet->Count() ) | |||
1493 | { | |||
1494 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1495 | return bRet; | |||
1496 | } | |||
1497 | } | |||
1498 | ||||
1499 | // Tables now also know line breaks | |||
1500 | const SvxFormatBreakItem* pBreak; | |||
1501 | if( pNode && !(nFlags & SetAttrMode::APICALL) && | |||
1502 | nullptr != (pTableNd = pNode->FindTableNode() ) && | |||
1503 | SfxItemState::SET == pOtherSet->GetItemState( RES_BREAK, | |||
1504 | false, reinterpret_cast<const SfxPoolItem**>(&pBreak) ) ) | |||
1505 | { | |||
1506 | SwTableNode* pCurTableNd = pTableNd; | |||
1507 | while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) ) | |||
1508 | pTableNd = pCurTableNd; | |||
1509 | ||||
1510 | // set the table format | |||
1511 | SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat(); | |||
1512 | SwRegHistory aRegH( pFormat, *pTableNd, pHistory ); | |||
1513 | pFormat->SetFormatAttr( *pBreak ); | |||
1514 | bRet = true; | |||
1515 | ||||
1516 | // bOtherAttr = true means that pOtherSet == rChgSet. In this case | |||
1517 | // we know, that there is only one attribute in pOtherSet. We cannot | |||
1518 | // perform the following operations, instead we return: | |||
1519 | if ( bOtherAttr ) | |||
1520 | return bRet; | |||
1521 | ||||
1522 | const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_BREAK ); | |||
1523 | if( !pOtherSet->Count() ) | |||
1524 | { | |||
1525 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1526 | return bRet; | |||
1527 | } | |||
1528 | } | |||
1529 | ||||
1530 | { | |||
1531 | // If we have a PoolNumRule, create it if needed | |||
1532 | const SwNumRuleItem* pRule; | |||
1533 | sal_uInt16 nPoolId=0; | |||
1534 | if( SfxItemState::SET == pOtherSet->GetItemState( RES_PARATR_NUMRULE, | |||
1535 | false, reinterpret_cast<const SfxPoolItem**>(&pRule) ) && | |||
1536 | !rDoc.FindNumRulePtr( pRule->GetValue() ) && | |||
1537 | USHRT_MAX(32767 *2 +1) != (nPoolId = SwStyleNameMapper::GetPoolIdFromUIName ( pRule->GetValue(), | |||
1538 | SwGetPoolIdFromName::NumRule )) ) | |||
1539 | rDoc.getIDocumentStylePoolAccess().GetNumRuleFromPool( nPoolId ); | |||
1540 | } | |||
1541 | } | |||
1542 | ||||
1543 | SfxItemSet firstSet(rDoc.GetAttrPool(), | |||
1544 | svl::Items<RES_PAGEDESC, RES_BREAK>{}); | |||
1545 | if (pOtherSet && pOtherSet->Count()) | |||
1546 | { // actually only RES_BREAK is possible here... | |||
1547 | firstSet.Put(*pOtherSet); | |||
1548 | } | |||
1549 | SfxItemSet propsSet(rDoc.GetAttrPool(), | |||
1550 | svl::Items<RES_PARATR_BEGIN, RES_PAGEDESC, | |||
1551 | RES_BREAK+1, RES_FRMATR_END, | |||
1552 | XATTR_FILL_FIRST, XATTR_FILL_LAST+1>{}); | |||
1553 | if (pOtherSet && pOtherSet->Count()) | |||
1554 | { | |||
1555 | propsSet.Put(*pOtherSet); | |||
1556 | } | |||
1557 | ||||
1558 | if( !rRg.HasMark() ) // no range | |||
1559 | { | |||
1560 | if( !pNode ) | |||
1561 | { | |||
1562 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1563 | return bRet; | |||
1564 | } | |||
1565 | ||||
1566 | if( pNode->IsTextNode() && pCharSet && pCharSet->Count() ) | |||
1567 | { | |||
1568 | SwTextNode* pTextNd = pNode->GetTextNode(); | |||
1569 | const SwIndex& rSt = pStt->nContent; | |||
1570 | sal_Int32 nMkPos, nPtPos = rSt.GetIndex(); | |||
1571 | const OUString& rStr = pTextNd->GetText(); | |||
1572 | ||||
1573 | // Special case: if the Cursor is located within a URL attribute, we take over it's area | |||
1574 | SwTextAttr const*const pURLAttr( | |||
1575 | pTextNd->GetTextAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT)); | |||
1576 | if (pURLAttr && !pURLAttr->GetINetFormat().GetValue().isEmpty()) | |||
1577 | { | |||
1578 | nMkPos = pURLAttr->GetStart(); | |||
1579 | nPtPos = *pURLAttr->End(); | |||
1580 | } | |||
1581 | else | |||
1582 | { | |||
1583 | assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt-> GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1583, __extension__ __PRETTY_FUNCTION__)); | |||
1584 | Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary( | |||
1585 | pTextNd->GetText(), nPtPos, | |||
1586 | g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ), | |||
1587 | WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, | |||
1588 | true); | |||
1589 | ||||
1590 | if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos ) | |||
1591 | { | |||
1592 | nMkPos = aBndry.startPos; | |||
1593 | nPtPos = aBndry.endPos; | |||
1594 | } | |||
1595 | else | |||
1596 | nPtPos = nMkPos = rSt.GetIndex(); | |||
1597 | } | |||
1598 | ||||
1599 | // Remove the overriding attributes from the SwpHintsArray, | |||
1600 | // if the selection spans across the whole paragraph. | |||
1601 | // These attributes are inserted as FormatAttributes and | |||
1602 | // never override the TextAttributes! | |||
1603 | if( !(nFlags & SetAttrMode::DONTREPLACE ) && | |||
1604 | pTextNd->HasHints() && !nMkPos && nPtPos == rStr.getLength()) | |||
1605 | { | |||
1606 | SwIndex aSt( pTextNd ); | |||
1607 | if( pHistory ) | |||
1608 | { | |||
1609 | // Save all attributes for the Undo. | |||
1610 | SwRegHistory aRHst( *pTextNd, pHistory ); | |||
1611 | pTextNd->GetpSwpHints()->Register( &aRHst ); | |||
1612 | pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet ); | |||
1613 | if( pTextNd->GetpSwpHints() ) | |||
1614 | pTextNd->GetpSwpHints()->DeRegister(); | |||
1615 | } | |||
1616 | else | |||
1617 | pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet ); | |||
1618 | } | |||
1619 | ||||
1620 | // the SwRegHistory inserts the attribute into the TextNode! | |||
1621 | SwRegHistory history( pNode, *pNode, pHistory ); | |||
1622 | bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags, /*ppNewTextAttr*/nullptr ) | |||
1623 | || bRet; | |||
1624 | ||||
1625 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
1626 | { | |||
1627 | SwPaM aPam( *pNode, nMkPos, *pNode, nPtPos ); | |||
1628 | ||||
1629 | if( pUndo ) | |||
1630 | pUndo->SaveRedlineData( aPam, false ); | |||
1631 | rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Format, aPam ), true); | |||
1632 | } | |||
1633 | } | |||
1634 | if( pOtherSet && pOtherSet->Count() ) | |||
1635 | { | |||
1636 | // Need to check for unique item for DrawingLayer items of type NameOrIndex | |||
1637 | // and evtl. correct that item to ensure unique names for that type. This call may | |||
1638 | // modify/correct entries inside of the given SfxItemSet | |||
1639 | SfxItemSet aTempLocalCopy(*pOtherSet); | |||
1640 | ||||
1641 | rDoc.CheckForUniqueItemForLineFillNameOrIndex(aTempLocalCopy); | |||
1642 | bRet = lcl_ApplyOtherSet(*pNode, pHistory, aTempLocalCopy, firstSet, propsSet, pLayout) || bRet; | |||
1643 | } | |||
1644 | ||||
1645 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1646 | return bRet; | |||
1647 | } | |||
1648 | ||||
1649 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() && pCharSet && pCharSet->Count() ) | |||
1650 | { | |||
1651 | if( pUndo ) | |||
1652 | pUndo->SaveRedlineData( rRg, false ); | |||
1653 | rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Format, rRg ), true); | |||
1654 | } | |||
1655 | ||||
1656 | /* now if range */ | |||
1657 | sal_uLong nNodes = 0; | |||
1658 | ||||
1659 | SwNodeIndex aSt( rDoc.GetNodes() ); | |||
1660 | SwNodeIndex aEnd( rDoc.GetNodes() ); | |||
1661 | SwIndex aCntEnd( pEnd->nContent ); | |||
1662 | ||||
1663 | if( pNode ) | |||
1664 | { | |||
1665 | const sal_Int32 nLen = pNode->Len(); | |||
1666 | if( pStt->nNode != pEnd->nNode ) | |||
1667 | aCntEnd.Assign( pNode, nLen ); | |||
1668 | ||||
1669 | if( pStt->nContent.GetIndex() != 0 || aCntEnd.GetIndex() != nLen ) | |||
1670 | { | |||
1671 | // the SwRegHistory inserts the attribute into the TextNode! | |||
1672 | if( pNode->IsTextNode() && pCharSet && pCharSet->Count() ) | |||
1673 | { | |||
1674 | SwRegHistory history( pNode, *pNode, pHistory ); | |||
1675 | bRet = history.InsertItems(*pCharSet, | |||
1676 | pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr) | |||
1677 | || bRet; | |||
1678 | } | |||
1679 | ||||
1680 | if( pOtherSet && pOtherSet->Count() ) | |||
1681 | { | |||
1682 | bRet = lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout) || bRet; | |||
1683 | } | |||
1684 | ||||
1685 | // Only selection in a Node. | |||
1686 | if( pStt->nNode == pEnd->nNode ) | |||
1687 | { | |||
1688 | //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc, | |||
1689 | //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that | |||
1690 | //current setting attribute set is a character range properties set and comes from a MS Word | |||
1691 | //binary file, and the setting range include a paragraph end position (0X0D); | |||
1692 | //more specifications, as such property inside the character range properties set recorded in | |||
1693 | //MS Word binary file are dealt and inserted into data model (SwDoc) one by one, so we | |||
1694 | //only dealing the scenario that the char properties set with 1 item inside; | |||
1695 | ||||
1696 | if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1 ) | |||
1697 | { | |||
1698 | SwTextNode* pCurrentNd = pStt->nNode.GetNode().GetTextNode(); | |||
1699 | ||||
1700 | if (pCurrentNd) | |||
1701 | { | |||
1702 | pCurrentNd->TryCharSetExpandToNum(*pCharSet); | |||
1703 | ||||
1704 | } | |||
1705 | } | |||
1706 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1707 | return bRet; | |||
1708 | } | |||
1709 | ++nNodes; | |||
1710 | aSt.Assign( pStt->nNode.GetNode(), +1 ); | |||
1711 | } | |||
1712 | else | |||
1713 | aSt = pStt->nNode; | |||
1714 | aCntEnd = pEnd->nContent; // aEnd was changed! | |||
1715 | } | |||
1716 | else | |||
1717 | aSt.Assign( pStt->nNode.GetNode(), +1 ); | |||
1718 | ||||
1719 | // aSt points to the first full Node now | |||
1720 | ||||
1721 | /* | |||
1722 | * The selection spans more than one Node. | |||
1723 | */ | |||
1724 | if( pStt->nNode < pEnd->nNode ) | |||
1725 | { | |||
1726 | pNode = pEnd->nNode.GetNode().GetContentNode(); | |||
1727 | if(pNode) | |||
1728 | { | |||
1729 | if( aCntEnd.GetIndex() != pNode->Len() ) | |||
1730 | { | |||
1731 | // the SwRegHistory inserts the attribute into the TextNode! | |||
1732 | if( pNode->IsTextNode() && pCharSet && pCharSet->Count() ) | |||
1733 | { | |||
1734 | SwRegHistory history( pNode, *pNode, pHistory ); | |||
1735 | (void)history.InsertItems(*pCharSet, | |||
1736 | 0, aCntEnd.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr); | |||
1737 | } | |||
1738 | ||||
1739 | if( pOtherSet && pOtherSet->Count() ) | |||
1740 | { | |||
1741 | lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout); | |||
1742 | } | |||
1743 | ||||
1744 | ++nNodes; | |||
1745 | aEnd = pEnd->nNode; | |||
1746 | } | |||
1747 | else | |||
1748 | aEnd.Assign( pEnd->nNode.GetNode(), +1 ); | |||
1749 | } | |||
1750 | else | |||
1751 | aEnd = pEnd->nNode; | |||
1752 | } | |||
1753 | else | |||
1754 | aEnd.Assign( pEnd->nNode.GetNode(), +1 ); | |||
1755 | ||||
1756 | // aEnd points BEHIND the last full node now | |||
1757 | ||||
1758 | /* Edit the fully selected Nodes. */ | |||
1759 | // Reset all attributes from the set! | |||
1760 | if( pCharSet && pCharSet->Count() && !( SetAttrMode::DONTREPLACE & nFlags ) ) | |||
1761 | { | |||
1762 | ::sw::DocumentContentOperationsManager::ParaRstFormat aPara( | |||
1763 | pStt, pEnd, pHistory, pCharSet, pLayout); | |||
1764 | rDoc.GetNodes().ForEach( aSt, aEnd, ::sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara ); | |||
1765 | } | |||
1766 | ||||
1767 | bool bCreateSwpHints = pCharSet && ( | |||
1768 | SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_CHARFMT, false ) || | |||
1769 | SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_INETFMT, false ) ); | |||
1770 | ||||
1771 | for (SwNodeIndex current = aSt; current < aEnd; ++current) | |||
1772 | { | |||
1773 | SwTextNode *const pTNd = current.GetNode().GetTextNode(); | |||
1774 | if (!pTNd) | |||
1775 | continue; | |||
1776 | ||||
1777 | if (pLayout && pLayout->IsHideRedlines() | |||
1778 | && pTNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden) | |||
1779 | { // not really sure what to do here, but applying to hidden | |||
1780 | continue; // nodes doesn't make sense... | |||
1781 | } | |||
1782 | ||||
1783 | if( pHistory ) | |||
1784 | { | |||
1785 | SwRegHistory aRegH( pTNd, *pTNd, pHistory ); | |||
1786 | ||||
1787 | if (pCharSet && pCharSet->Count()) | |||
1788 | { | |||
1789 | SwpHints *pSwpHints = bCreateSwpHints ? &pTNd->GetOrCreateSwpHints() | |||
1790 | : pTNd->GetpSwpHints(); | |||
1791 | if( pSwpHints ) | |||
1792 | pSwpHints->Register( &aRegH ); | |||
1793 | ||||
1794 | pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags); | |||
1795 | if( pSwpHints ) | |||
1796 | pSwpHints->DeRegister(); | |||
1797 | } | |||
1798 | } | |||
1799 | else | |||
1800 | { | |||
1801 | if (pCharSet && pCharSet->Count()) | |||
1802 | pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags); | |||
1803 | } | |||
1804 | ++nNodes; | |||
1805 | } | |||
1806 | ||||
1807 | if (pOtherSet && pOtherSet->Count()) | |||
1808 | { | |||
1809 | for (; aSt < aEnd; ++aSt) | |||
1810 | { | |||
1811 | pNode = aSt.GetNode().GetContentNode(); | |||
1812 | if (!pNode) | |||
1813 | continue; | |||
1814 | ||||
1815 | lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout, &aSt); | |||
1816 | ++nNodes; | |||
1817 | } | |||
1818 | } | |||
1819 | ||||
1820 | //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc, | |||
1821 | //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that | |||
1822 | //current setting attribute set is a character range properties set and comes from a MS Word | |||
1823 | //binary file, and the setting range include a paragraph end position (0X0D); | |||
1824 | //more specifications, as such property inside the character range properties set recorded in | |||
1825 | //MS Word binary file are dealt and inserted into data model (SwDoc) one by one, so we | |||
1826 | //only dealing the scenario that the char properties set with 1 item inside; | |||
1827 | if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1) | |||
1828 | { | |||
1829 | SwPosition aStartPos (*rRg.Start()); | |||
1830 | SwPosition aEndPos (*rRg.End()); | |||
1831 | ||||
1832 | if (aEndPos.nNode.GetNode().GetTextNode() && aEndPos.nContent != aEndPos.nNode.GetNode().GetTextNode()->Len()) | |||
1833 | aEndPos.nNode--; | |||
1834 | ||||
1835 | sal_uLong nStart = aStartPos.nNode.GetIndex(); | |||
1836 | sal_uLong nEnd = aEndPos.nNode.GetIndex(); | |||
1837 | for(; nStart <= nEnd; ++nStart) | |||
1838 | { | |||
1839 | SwNode* pNd = rDoc.GetNodes()[ nStart ]; | |||
1840 | if (!pNd || !pNd->IsTextNode()) | |||
1841 | continue; | |||
1842 | SwTextNode *pCurrentNd = pNd->GetTextNode(); | |||
1843 | pCurrentNd->TryCharSetExpandToNum(*pCharSet); | |||
1844 | } | |||
1845 | } | |||
1846 | ||||
1847 | DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } | |||
1848 | return (nNodes != 0) || bRet; | |||
1849 | } | |||
1850 | } | |||
1851 | ||||
1852 | namespace sw | |||
1853 | { | |||
1854 | ||||
1855 | namespace mark | |||
1856 | { | |||
1857 | bool IsFieldmarkOverlap(SwPaM const& rPaM) | |||
1858 | { | |||
1859 | std::vector<std::pair<sal_uLong, sal_Int32>> Breaks; | |||
1860 | sw::CalcBreaks(Breaks, rPaM); | |||
1861 | return !Breaks.empty(); | |||
1862 | } | |||
1863 | } | |||
1864 | ||||
1865 | DocumentContentOperationsManager::DocumentContentOperationsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ) | |||
1866 | { | |||
1867 | } | |||
1868 | ||||
1869 | /** | |||
1870 | * Checks if rStart..rEnd mark a range that makes sense to copy. | |||
1871 | * | |||
1872 | * IsMoveToFly means the copy is a move to create a fly | |||
1873 | * and so existing flys at the edge must not be copied. | |||
1874 | */ | |||
1875 | static bool IsEmptyRange(const SwPosition& rStart, const SwPosition& rEnd, | |||
1876 | SwCopyFlags const flags) | |||
1877 | { | |||
1878 | if (rStart == rEnd) | |||
1879 | { // check if a fly anchored there would be copied - then copy... | |||
1880 | return !IsDestroyFrameAnchoredAtChar(rStart, rStart, rEnd, | |||
1881 | (flags & SwCopyFlags::IsMoveToFly) | |||
1882 | ? DelContentType::WriterfilterHack|DelContentType::AllMask | |||
1883 | : DelContentType::AllMask); | |||
1884 | } | |||
1885 | else | |||
1886 | { | |||
1887 | return rEnd < rStart; | |||
1888 | } | |||
1889 | } | |||
1890 | ||||
1891 | // Copy an area into this document or into another document | |||
1892 | bool | |||
1893 | DocumentContentOperationsManager::CopyRange( SwPaM& rPam, SwPosition& rPos, | |||
1894 | SwCopyFlags const flags) const | |||
1895 | { | |||
1896 | const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); | |||
1897 | ||||
1898 | SwDoc& rDoc = rPos.nNode.GetNode().GetDoc(); | |||
1899 | bool bColumnSel = rDoc.IsClipBoard() && rDoc.IsColumnSelection(); | |||
1900 | ||||
1901 | // Catch if there's no copy to do | |||
1902 | if (!rPam.HasMark() || (IsEmptyRange(*pStt, *pEnd, flags) && !bColumnSel)) | |||
1903 | return false; | |||
1904 | ||||
1905 | // Prevent copying into Flys that are anchored in the source range | |||
1906 | if (&rDoc == &m_rDoc && (flags & SwCopyFlags::CheckPosInFly)) | |||
1907 | { | |||
1908 | // Correct the Start-/EndNode | |||
1909 | sal_uLong nStt = pStt->nNode.GetIndex(), | |||
1910 | nEnd = pEnd->nNode.GetIndex(), | |||
1911 | nDiff = nEnd - nStt +1; | |||
1912 | SwNode* pNd = m_rDoc.GetNodes()[ nStt ]; | |||
1913 | if( pNd->IsContentNode() && pStt->nContent.GetIndex() ) | |||
1914 | { | |||
1915 | ++nStt; | |||
1916 | --nDiff; | |||
1917 | } | |||
1918 | if( (pNd = m_rDoc.GetNodes()[ nEnd ])->IsContentNode() && | |||
1919 | static_cast<SwContentNode*>(pNd)->Len() != pEnd->nContent.GetIndex() ) | |||
1920 | { | |||
1921 | --nEnd; | |||
1922 | --nDiff; | |||
1923 | } | |||
1924 | if( nDiff && | |||
1925 | lcl_ChkFlyFly( rDoc, nStt, nEnd, rPos.nNode.GetIndex() ) ) | |||
1926 | { | |||
1927 | return false; | |||
1928 | } | |||
1929 | } | |||
1930 | ||||
1931 | SwPaM* pRedlineRange = nullptr; | |||
1932 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() || | |||
1933 | (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) ) | |||
1934 | pRedlineRange = new SwPaM( rPos ); | |||
1935 | ||||
1936 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
1937 | ||||
1938 | bool bRet = false; | |||
1939 | ||||
1940 | if( &rDoc != &m_rDoc ) | |||
1941 | { // ordinary copy | |||
1942 | bRet = CopyImpl(rPam, rPos, flags & ~SwCopyFlags::CheckPosInFly, pRedlineRange); | |||
1943 | } | |||
1944 | else if( ! ( *pStt <= rPos && rPos < *pEnd && | |||
1945 | ( pStt->nNode != pEnd->nNode || | |||
1946 | !pStt->nNode.GetNode().IsTextNode() )) ) | |||
1947 | { | |||
1948 | // Copy to a position outside of the area, or copy a single TextNode | |||
1949 | // Do an ordinary copy | |||
1950 | bRet = CopyImpl(rPam, rPos, flags & ~SwCopyFlags::CheckPosInFly, pRedlineRange); | |||
1951 | } | |||
1952 | else | |||
1953 | { | |||
1954 | // Copy the range in itself | |||
1955 | assert(!"mst: this is assumed to be dead code")(static_cast <bool> (!"mst: this is assumed to be dead code" ) ? void (0) : __assert_fail ("!\"mst: this is assumed to be dead code\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1955, __extension__ __PRETTY_FUNCTION__)); | |||
1956 | } | |||
1957 | ||||
1958 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | |||
1959 | if( pRedlineRange ) | |||
1960 | { | |||
1961 | if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
1962 | rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, *pRedlineRange ), true); | |||
1963 | else | |||
1964 | rDoc.getIDocumentRedlineAccess().SplitRedline( *pRedlineRange ); | |||
1965 | delete pRedlineRange; | |||
1966 | } | |||
1967 | ||||
1968 | return bRet; | |||
1969 | } | |||
1970 | ||||
1971 | /// Delete a full Section of the NodeArray. | |||
1972 | /// The passed Node is located somewhere in the designated Section. | |||
1973 | void DocumentContentOperationsManager::DeleteSection( SwNode *pNode ) | |||
1974 | { | |||
1975 | assert(pNode && "Didn't pass a Node.")(static_cast <bool> (pNode && "Didn't pass a Node." ) ? void (0) : __assert_fail ("pNode && \"Didn't pass a Node.\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 1975, __extension__ __PRETTY_FUNCTION__)); | |||
1976 | ||||
1977 | SwStartNode* pSttNd = pNode->IsStartNode() ? static_cast<SwStartNode*>(pNode) | |||
1978 | : pNode->StartOfSectionNode(); | |||
1979 | SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() ); | |||
1980 | ||||
1981 | // delete all Flys, Bookmarks, ... | |||
1982 | DelFlyInRange( aSttIdx, aEndIdx ); | |||
1983 | m_rDoc.getIDocumentRedlineAccess().DeleteRedline( *pSttNd, true, RedlineType::Any ); | |||
1984 | DelBookmarks(aSttIdx, aEndIdx); | |||
1985 | ||||
1986 | { | |||
1987 | // move all Cursor/StackCursor/UnoCursor out of the to-be-deleted area | |||
1988 | SwNodeIndex aMvStt( aSttIdx, 1 ); | |||
1989 | SwDoc::CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), true ); | |||
1990 | } | |||
1991 | ||||
1992 | m_rDoc.GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 ); | |||
1993 | } | |||
1994 | ||||
1995 | void DocumentContentOperationsManager::DeleteDummyChar( | |||
1996 | SwPosition const& rPos, sal_Unicode const cDummy) | |||
1997 | { | |||
1998 | SwPaM aPam(rPos, rPos); | |||
1999 | ++aPam.GetPoint()->nContent; | |||
2000 | assert(aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy)(static_cast <bool> (aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy) ? void (0) : __assert_fail ("aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2000, __extension__ __PRETTY_FUNCTION__)); | |||
2001 | (void) cDummy; | |||
2002 | ||||
2003 | DeleteRangeImpl(aPam); | |||
2004 | ||||
2005 | if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() | |||
2006 | && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()) | |||
2007 | { | |||
2008 | m_rDoc.getIDocumentRedlineAccess().CompressRedlines(); | |||
2009 | } | |||
2010 | } | |||
2011 | ||||
2012 | void DocumentContentOperationsManager::DeleteRange( SwPaM & rPam ) | |||
2013 | { | |||
2014 | lcl_DoWithBreaks( *this, rPam, &DocumentContentOperationsManager::DeleteRangeImpl ); | |||
2015 | ||||
2016 | if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()) | |||
2017 | { | |||
2018 | rPam.Normalize(false); // tdf#127635 put point at the end of deletion | |||
2019 | } | |||
2020 | ||||
2021 | if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() | |||
2022 | && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()) | |||
2023 | { | |||
2024 | m_rDoc.getIDocumentRedlineAccess().CompressRedlines(); | |||
2025 | } | |||
2026 | } | |||
2027 | ||||
2028 | bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam ) | |||
2029 | { | |||
2030 | const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); | |||
2031 | const SwNode* pNd = &rStt.nNode.GetNode(); | |||
2032 | sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() - | |||
2033 | pNd->StartOfSectionIndex(); | |||
2034 | sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex(); | |||
2035 | ||||
2036 | if ( nSectDiff-2 <= nNodeDiff || m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || | |||
2037 | /* #i9185# Prevent getting the node after the end node (see below) */ | |||
2038 | rEnd.nNode.GetIndex() + 1 == m_rDoc.GetNodes().Count() ) | |||
2039 | { | |||
2040 | return false; | |||
2041 | } | |||
2042 | ||||
2043 | { | |||
2044 | SwPaM temp(rPam, nullptr); | |||
2045 | if (!temp.HasMark()) | |||
2046 | { | |||
2047 | temp.SetMark(); | |||
2048 | } | |||
2049 | if (SwTextNode *const pNode = temp.Start()->nNode.GetNode().GetTextNode()) | |||
2050 | { // rPam may not have nContent set but IsFieldmarkOverlap requires it | |||
2051 | pNode->MakeStartIndex(&temp.Start()->nContent); | |||
2052 | } | |||
2053 | if (SwTextNode *const pNode = temp.End()->nNode.GetNode().GetTextNode()) | |||
2054 | { | |||
2055 | pNode->MakeEndIndex(&temp.End()->nContent); | |||
2056 | } | |||
2057 | if (sw::mark::IsFieldmarkOverlap(temp)) | |||
2058 | { // a bit of a problem: we want to completely remove the nodes | |||
2059 | // but then how can the CH_TXT_ATR survive? | |||
2060 | return false; | |||
2061 | } | |||
2062 | } | |||
2063 | ||||
2064 | // Move hard page brakes to the following Node. | |||
2065 | bool bSavePageBreak = false, bSavePageDesc = false; | |||
2066 | ||||
2067 | /* #i9185# This would lead to a segmentation fault if not caught above. */ | |||
2068 | sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1; | |||
2069 | SwTableNode *const pTableNd = m_rDoc.GetNodes()[ nNextNd ]->GetTableNode(); | |||
2070 | ||||
2071 | if( pTableNd && pNd->IsContentNode() ) | |||
2072 | { | |||
2073 | SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); | |||
2074 | ||||
2075 | { | |||
2076 | const SfxPoolItem *pItem; | |||
2077 | const SfxItemSet* pSet = static_cast<const SwContentNode*>(pNd)->GetpSwAttrSet(); | |||
2078 | if( pSet && SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, | |||
2079 | false, &pItem ) ) | |||
2080 | { | |||
2081 | pTableFormat->SetFormatAttr( *pItem ); | |||
2082 | bSavePageDesc = true; | |||
2083 | } | |||
2084 | ||||
2085 | if( pSet && SfxItemState::SET == pSet->GetItemState( RES_BREAK, | |||
2086 | false, &pItem ) ) | |||
2087 | { | |||
2088 | pTableFormat->SetFormatAttr( *pItem ); | |||
2089 | bSavePageBreak = true; | |||
2090 | } | |||
2091 | } | |||
2092 | } | |||
2093 | ||||
2094 | bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo(); | |||
2095 | if( bDoesUndo ) | |||
2096 | { | |||
2097 | if( !rPam.HasMark() ) | |||
2098 | rPam.SetMark(); | |||
2099 | else if( rPam.GetPoint() == &rStt ) | |||
2100 | rPam.Exchange(); | |||
2101 | rPam.GetPoint()->nNode++; | |||
2102 | ||||
2103 | SwContentNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetContentNode(); | |||
2104 | rPam.GetPoint()->nContent.Assign( pTmpNode, 0 ); | |||
2105 | bool bGoNext = (nullptr == pTmpNode); | |||
2106 | pTmpNode = rPam.GetMark()->nNode.GetNode().GetContentNode(); | |||
2107 | rPam.GetMark()->nContent.Assign( pTmpNode, 0 ); | |||
2108 | ||||
2109 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | |||
2110 | ||||
2111 | SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); | |||
2112 | { | |||
2113 | SwPosition aTmpPos( *aDelPam.GetPoint() ); | |||
2114 | if( bGoNext ) | |||
2115 | { | |||
2116 | pTmpNode = m_rDoc.GetNodes().GoNext( &aTmpPos.nNode ); | |||
2117 | aTmpPos.nContent.Assign( pTmpNode, 0 ); | |||
2118 | } | |||
2119 | ::PaMCorrAbs( aDelPam, aTmpPos ); | |||
2120 | } | |||
2121 | ||||
2122 | std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aDelPam, true )); | |||
2123 | ||||
2124 | *rPam.GetPoint() = *aDelPam.GetPoint(); | |||
2125 | pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); | |||
2126 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); | |||
2127 | rPam.DeleteMark(); | |||
2128 | } | |||
2129 | else | |||
2130 | { | |||
2131 | SwNodeRange aRg( rStt.nNode, rEnd.nNode ); | |||
2132 | rPam.Normalize(false); | |||
2133 | ||||
2134 | // Try to move past the End | |||
2135 | if( !rPam.Move( fnMoveForward, GoInNode ) ) | |||
2136 | { | |||
2137 | // Fair enough, at the Beginning then | |||
2138 | rPam.Exchange(); | |||
2139 | if( !rPam.Move( fnMoveBackward, GoInNode )) | |||
2140 | { | |||
2141 | SAL_WARN("sw.core", "DelFullPara: no more Nodes")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "DelFullPara: no more Nodes" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2141" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "DelFullPara: no more Nodes"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "DelFullPara: no more Nodes"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2141" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "DelFullPara: no more Nodes") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2141" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "DelFullPara: no more Nodes"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "DelFullPara: no more Nodes"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2141" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2142 | return false; | |||
2143 | } | |||
2144 | } | |||
2145 | // move bookmarks, redlines etc. | |||
2146 | if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this | |||
2147 | { | |||
2148 | m_rDoc.CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, true ); | |||
2149 | } | |||
2150 | else | |||
2151 | { | |||
2152 | SwDoc::CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), true ); | |||
2153 | } | |||
2154 | ||||
2155 | // What's with Flys? | |||
2156 | { | |||
2157 | // If there are FlyFrames left, delete these too | |||
2158 | for( size_t n = 0; n < m_rDoc.GetSpzFrameFormats()->size(); ++n ) | |||
2159 | { | |||
2160 | SwFrameFormat* pFly = (*m_rDoc.GetSpzFrameFormats())[n]; | |||
2161 | const SwFormatAnchor* pAnchor = &pFly->GetAnchor(); | |||
2162 | SwPosition const*const pAPos = pAnchor->GetContentAnchor(); | |||
2163 | if (pAPos && | |||
2164 | ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) || | |||
2165 | (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) && | |||
2166 | // note: here use <= not < like in | |||
2167 | // IsDestroyFrameAnchoredAtChar() because of the increment | |||
2168 | // of rPam in the bDoesUndo path above! | |||
2169 | aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd ) | |||
2170 | { | |||
2171 | m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFly ); | |||
2172 | --n; | |||
2173 | } | |||
2174 | } | |||
2175 | } | |||
2176 | ||||
2177 | rPam.DeleteMark(); | |||
2178 | m_rDoc.GetNodes().Delete( aRg.aStart, nNodeDiff+1 ); | |||
2179 | } | |||
2180 | m_rDoc.getIDocumentState().SetModified(); | |||
2181 | ||||
2182 | return true; | |||
2183 | } | |||
2184 | ||||
2185 | // #i100466# Add handling of new optional parameter <bForceJoinNext> | |||
2186 | bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM & rPam, | |||
2187 | const bool bForceJoinNext ) | |||
2188 | { | |||
2189 | if ( lcl_StrLenOverflow( rPam ) ) | |||
2190 | return false; | |||
2191 | ||||
2192 | bool const ret = lcl_DoWithBreaks( *this, rPam, (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()) | |||
2193 | ? &DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl | |||
2194 | : &DocumentContentOperationsManager::DeleteAndJoinImpl, | |||
2195 | bForceJoinNext ); | |||
2196 | ||||
2197 | if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()) | |||
2198 | { | |||
2199 | rPam.Normalize(false); // tdf#127635 put point at the end of deletion | |||
2200 | } | |||
2201 | ||||
2202 | return ret; | |||
2203 | } | |||
2204 | ||||
2205 | // It seems that this is mostly used by SwDoc internals; the only | |||
2206 | // way to call this from the outside seems to be the special case in | |||
2207 | // SwDoc::CopyRange (but I have not managed to actually hit that case). | |||
2208 | bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags ) | |||
2209 | { | |||
2210 | // nothing moved: return | |||
2211 | const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End(); | |||
2212 | if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd)) | |||
2213 | return false; | |||
2214 | ||||
2215 | assert(!sw::mark::IsFieldmarkOverlap(rPaM))(static_cast <bool> (!sw::mark::IsFieldmarkOverlap(rPaM )) ? void (0) : __assert_fail ("!sw::mark::IsFieldmarkOverlap(rPaM)" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2215, __extension__ __PRETTY_FUNCTION__)); // probably an invalid redline was created? | |||
2216 | ||||
2217 | // Save the paragraph anchored Flys, so that they can be moved. | |||
2218 | SaveFlyArr aSaveFlyArr; | |||
2219 | SaveFlyInRange( rPaM, rPos, aSaveFlyArr, bool( SwMoveFlags::ALLFLYS & eMvFlags ) ); | |||
2220 | ||||
2221 | // save redlines (if DOC_MOVEREDLINES is used) | |||
2222 | SaveRedlines_t aSaveRedl; | |||
2223 | if( SwMoveFlags::REDLINES & eMvFlags && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) | |||
2224 | { | |||
2225 | lcl_SaveRedlines( rPaM, aSaveRedl ); | |||
2226 | ||||
2227 | // #i17764# unfortunately, code below relies on undos being | |||
2228 | // in a particular order, and presence of bookmarks | |||
2229 | // will change this order. Hence, we delete bookmarks | |||
2230 | // here without undo. | |||
2231 | ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo()); | |||
2232 | DelBookmarks( | |||
2233 | pStt->nNode, | |||
2234 | pEnd->nNode, | |||
2235 | nullptr, | |||
2236 | &pStt->nContent, | |||
2237 | &pEnd->nContent); | |||
2238 | } | |||
2239 | ||||
2240 | bool bUpdateFootnote = false; | |||
2241 | SwFootnoteIdxs aTmpFntIdx; | |||
2242 | ||||
2243 | std::unique_ptr<SwUndoMove> pUndoMove; | |||
2244 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2245 | { | |||
2246 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | |||
2247 | pUndoMove.reset(new SwUndoMove( rPaM, rPos )); | |||
2248 | pUndoMove->SetMoveRedlines( eMvFlags == SwMoveFlags::REDLINES ); | |||
2249 | } | |||
2250 | else | |||
2251 | { | |||
2252 | bUpdateFootnote = lcl_SaveFootnote( pStt->nNode, pEnd->nNode, rPos.nNode, | |||
2253 | m_rDoc.GetFootnoteIdxs(), aTmpFntIdx, | |||
2254 | &pStt->nContent, &pEnd->nContent ); | |||
2255 | } | |||
2256 | ||||
2257 | bool bSplit = false; | |||
2258 | SwPaM aSavePam( rPos, rPos ); | |||
2259 | ||||
2260 | // Move the SPoint to the beginning of the range | |||
2261 | if( rPaM.GetPoint() == pEnd ) | |||
2262 | rPaM.Exchange(); | |||
2263 | ||||
2264 | // If there is a TextNode before and after the Move, create a JoinNext in the EditShell. | |||
2265 | SwTextNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTextNode(); | |||
2266 | bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode; | |||
2267 | ||||
2268 | // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode. | |||
2269 | // However, this does not update the cursor. So we create a TextNode to keep | |||
2270 | // updating the indices. After the Move the Node is optionally deleted. | |||
2271 | SwTextNode * pTNd = rPos.nNode.GetNode().GetTextNode(); | |||
2272 | if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode && | |||
2273 | ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) ) | |||
2274 | { | |||
2275 | bSplit = true; | |||
2276 | const sal_Int32 nMkContent = rPaM.GetMark()->nContent.GetIndex(); | |||
2277 | ||||
2278 | const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create()); | |||
2279 | pContentStore->Save( m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true ); | |||
2280 | ||||
2281 | SwTextNode * pOrigNode = pTNd; | |||
2282 | assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam. GetMark() && *aSavePam.GetPoint() == rPos) ? void (0) : __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2283, __extension__ __PRETTY_FUNCTION__)) | |||
2283 | *aSavePam.GetPoint() == rPos)(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam. GetMark() && *aSavePam.GetPoint() == rPos) ? void (0) : __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2283, __extension__ __PRETTY_FUNCTION__)); | |||
2284 | assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode)(static_cast <bool> (aSavePam.GetPoint()->nContent.GetIdxReg () == pOrigNode) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2284, __extension__ __PRETTY_FUNCTION__)); | |||
2285 | assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex())(static_cast <bool> (aSavePam.GetPoint()->nNode == rPos .nNode.GetIndex()) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2285, __extension__ __PRETTY_FUNCTION__)); | |||
2286 | assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex())(static_cast <bool> (rPos.nNode.GetIndex() == pOrigNode ->GetIndex()) ? void (0) : __assert_fail ("rPos.nNode.GetIndex() == pOrigNode->GetIndex()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2286, __extension__ __PRETTY_FUNCTION__)); | |||
2287 | ||||
2288 | std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc( | |||
2289 | [&](SwTextNode *const, sw::mark::RestoreMode const eMode) | |||
2290 | { | |||
2291 | if (!pContentStore->Empty()) | |||
2292 | { | |||
2293 | pContentStore->Restore(m_rDoc, pOrigNode->GetIndex()-1, 0, true, eMode); | |||
2294 | } | |||
2295 | }); | |||
2296 | pTNd = pTNd->SplitContentNode(rPos, &restoreFunc)->GetTextNode(); | |||
2297 | ||||
2298 | //A new node was inserted before the orig pTNd and the content up to | |||
2299 | //rPos moved into it. The old node is returned with the remainder | |||
2300 | //of the content in it. | |||
2301 | // | |||
2302 | //aSavePam was created with rPos, it continues to point to the | |||
2303 | //old node, but with the *original* content index into the node. | |||
2304 | //Seeing as all the orignode content before that index has | |||
2305 | //been removed, the new index into the original node should now be set | |||
2306 | //to 0 and the content index of rPos should also be adapted to the | |||
2307 | //truncated node | |||
2308 | assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam. GetMark() && *aSavePam.GetPoint() == rPos) ? void (0) : __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2309, __extension__ __PRETTY_FUNCTION__)) | |||
2309 | *aSavePam.GetPoint() == rPos)(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam. GetMark() && *aSavePam.GetPoint() == rPos) ? void (0) : __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2309, __extension__ __PRETTY_FUNCTION__)); | |||
2310 | assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode)(static_cast <bool> (aSavePam.GetPoint()->nContent.GetIdxReg () == pOrigNode) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2310, __extension__ __PRETTY_FUNCTION__)); | |||
2311 | assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex())(static_cast <bool> (aSavePam.GetPoint()->nNode == rPos .nNode.GetIndex()) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2311, __extension__ __PRETTY_FUNCTION__)); | |||
2312 | assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex())(static_cast <bool> (rPos.nNode.GetIndex() == pOrigNode ->GetIndex()) ? void (0) : __assert_fail ("rPos.nNode.GetIndex() == pOrigNode->GetIndex()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2312, __extension__ __PRETTY_FUNCTION__)); | |||
2313 | aSavePam.GetPoint()->nContent.Assign(pOrigNode, 0); | |||
2314 | rPos = *aSavePam.GetMark() = *aSavePam.GetPoint(); | |||
2315 | ||||
2316 | // correct the PaM! | |||
2317 | if( rPos.nNode == rPaM.GetMark()->nNode ) | |||
2318 | { | |||
2319 | rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1; | |||
2320 | rPaM.GetMark()->nContent.Assign( pTNd, nMkContent ); | |||
2321 | } | |||
2322 | } | |||
2323 | ||||
2324 | // Put back the Pam by one "content"; so that it's always outside of | |||
2325 | // the manipulated range. | |||
2326 | // tdf#99692 don't Move() back if that would end up in another node | |||
2327 | // because moving backward is not necessarily the inverse of forward then. | |||
2328 | // (but do Move() back if we have split the node) | |||
2329 | const bool bNullContent = !bSplit && aSavePam.GetPoint()->nContent == 0; | |||
2330 | if( bNullContent ) | |||
2331 | { | |||
2332 | aSavePam.GetPoint()->nNode--; | |||
2333 | aSavePam.GetPoint()->nContent.Assign(aSavePam.GetContentNode(), 0); | |||
2334 | } | |||
2335 | else | |||
2336 | { | |||
2337 | bool const success(aSavePam.Move(fnMoveBackward, GoInContent)); | |||
2338 | assert(success)(static_cast <bool> (success) ? void (0) : __assert_fail ("success", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2338, __extension__ __PRETTY_FUNCTION__)); | |||
2339 | (void) success; | |||
2340 | } | |||
2341 | ||||
2342 | // Copy all Bookmarks that are within the Move range into an array, | |||
2343 | // that saves the position as an offset. | |||
2344 | std::vector< ::sw::mark::SaveBookmark> aSaveBkmks; | |||
2345 | DelBookmarks( | |||
2346 | pStt->nNode, | |||
2347 | pEnd->nNode, | |||
2348 | &aSaveBkmks, | |||
2349 | &pStt->nContent, | |||
2350 | &pEnd->nContent); | |||
2351 | ||||
2352 | // If there is no range anymore due to the above deletions (e.g. the | |||
2353 | // footnotes got deleted), it's still a valid Move! | |||
2354 | if( *rPaM.GetPoint() != *rPaM.GetMark() ) | |||
2355 | { | |||
2356 | // now do the actual move | |||
2357 | m_rDoc.GetNodes().MoveRange( rPaM, rPos, m_rDoc.GetNodes() ); | |||
2358 | ||||
2359 | // after a MoveRange() the Mark is deleted | |||
2360 | if ( rPaM.HasMark() ) // => no Move occurred! | |||
2361 | { | |||
2362 | return false; | |||
2363 | } | |||
2364 | } | |||
2365 | else | |||
2366 | rPaM.DeleteMark(); | |||
2367 | ||||
2368 | OSL_ENSURE( *aSavePam.GetMark() == rPos ||do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam .GetMark()->nNode.GetNode().GetContentNode() == nullptr )) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?" ); } } while (false) | |||
2369 | ( aSavePam.GetMark()->nNode.GetNode().GetContentNode() == nullptr ),do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam .GetMark()->nNode.GetNode().GetContentNode() == nullptr )) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?" ); } } while (false) | |||
2370 | "PaM was not moved. Aren't there ContentNodes at the beginning/end?" )do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam .GetMark()->nNode.GetNode().GetContentNode() == nullptr )) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?" ); } } while (false); | |||
2371 | *aSavePam.GetMark() = rPos; | |||
2372 | ||||
2373 | rPaM.SetMark(); // create a Sel. around the new range | |||
2374 | pTNd = aSavePam.GetNode().GetTextNode(); | |||
2375 | assert(!m_rDoc.GetIDocumentUndoRedo().DoesUndo())(static_cast <bool> (!m_rDoc.GetIDocumentUndoRedo().DoesUndo ()) ? void (0) : __assert_fail ("!m_rDoc.GetIDocumentUndoRedo().DoesUndo()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2375, __extension__ __PRETTY_FUNCTION__)); | |||
2376 | bool bRemove = true; | |||
2377 | // Do two Nodes have to be joined at the SavePam? | |||
2378 | if (bSplit && pTNd) | |||
2379 | { | |||
2380 | if (pTNd->CanJoinNext()) | |||
2381 | { | |||
2382 | // Always join next, because <pTNd> has to stay as it is. | |||
2383 | // A join previous from its next would more or less delete <pTNd> | |||
2384 | pTNd->JoinNext(); | |||
2385 | bRemove = false; | |||
2386 | } | |||
2387 | } | |||
2388 | if (bNullContent) | |||
2389 | { | |||
2390 | aSavePam.GetPoint()->nNode++; | |||
2391 | aSavePam.GetPoint()->nContent.Assign( aSavePam.GetContentNode(), 0 ); | |||
2392 | } | |||
2393 | else if (bRemove) // No move forward after joining with next paragraph | |||
2394 | { | |||
2395 | aSavePam.Move( fnMoveForward, GoInContent ); | |||
2396 | } | |||
2397 | ||||
2398 | // Insert the Bookmarks back into the Document. | |||
2399 | *rPaM.GetMark() = *aSavePam.Start(); | |||
2400 | for(auto& rBkmk : aSaveBkmks) | |||
2401 | rBkmk.SetInDoc( | |||
2402 | &m_rDoc, | |||
2403 | rPaM.GetMark()->nNode, | |||
2404 | &rPaM.GetMark()->nContent); | |||
2405 | *rPaM.GetPoint() = *aSavePam.End(); | |||
2406 | ||||
2407 | // Move the Flys to the new position. | |||
2408 | // note: rPos is at the end here; can't really tell flys that used to be | |||
2409 | // at the start of rPam from flys that used to be at the end of rPam | |||
2410 | // unfortunately, so some of them are going to end up with wrong anchor... | |||
2411 | RestFlyInRange( aSaveFlyArr, *rPaM.Start(), &(rPos.nNode) ); | |||
2412 | ||||
2413 | // restore redlines (if DOC_MOVEREDLINES is used) | |||
2414 | if( !aSaveRedl.empty() ) | |||
2415 | { | |||
2416 | lcl_RestoreRedlines( m_rDoc, *aSavePam.Start(), aSaveRedl ); | |||
2417 | } | |||
2418 | ||||
2419 | if( bUpdateFootnote ) | |||
2420 | { | |||
2421 | if( !aTmpFntIdx.empty() ) | |||
2422 | { | |||
2423 | m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx ); | |||
2424 | aTmpFntIdx.clear(); | |||
2425 | } | |||
2426 | ||||
2427 | m_rDoc.GetFootnoteIdxs().UpdateAllFootnote(); | |||
2428 | } | |||
2429 | ||||
2430 | m_rDoc.getIDocumentState().SetModified(); | |||
2431 | return true; | |||
2432 | } | |||
2433 | ||||
2434 | bool DocumentContentOperationsManager::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos, | |||
2435 | SwMoveFlags eMvFlags ) | |||
2436 | { | |||
2437 | std::vector<SwNode*> aFoldedOutlineNdsArray; | |||
2438 | SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(m_rDoc.GetEditShell()); | |||
2439 | if (pWrtShell && pWrtShell->GetViewOptions() && pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) | |||
2440 | { | |||
2441 | // unfold all folded outline content | |||
2442 | SwOutlineNodes rOutlineNds = m_rDoc.GetNodes().GetOutLineNds(); | |||
2443 | for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos) | |||
2444 | { | |||
2445 | SwNode* pNd = rOutlineNds[nPos]; | |||
2446 | if (pNd->IsTextNode()) // should always be true | |||
2447 | { | |||
2448 | bool bOutlineContentVisibleAttr = true; | |||
2449 | pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); | |||
2450 | if (!bOutlineContentVisibleAttr) | |||
2451 | { | |||
2452 | aFoldedOutlineNdsArray.push_back(pNd); | |||
2453 | pWrtShell->ToggleOutlineContentVisibility(nPos); | |||
2454 | } | |||
2455 | } | |||
2456 | } | |||
2457 | } | |||
2458 | // Moves all Nodes to the new position. | |||
2459 | // Bookmarks are moved too (currently without Undo support). | |||
2460 | ||||
2461 | // If footnotes are being moved to the special section, remove them now. | |||
2462 | ||||
2463 | // Or else delete the Frames for all footnotes that are being moved | |||
2464 | // and have it rebuild after the Move (footnotes can change pages). | |||
2465 | // Additionally we have to correct the FootnoteIdx array's sorting. | |||
2466 | bool bUpdateFootnote = false; | |||
2467 | SwFootnoteIdxs aTmpFntIdx; | |||
2468 | ||||
2469 | std::unique_ptr<SwUndoMove> pUndo; | |||
2470 | if ((SwMoveFlags::CREATEUNDOOBJ & eMvFlags ) && m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2471 | { | |||
2472 | pUndo.reset(new SwUndoMove( m_rDoc, rRange, rPos )); | |||
2473 | } | |||
2474 | else | |||
2475 | { | |||
2476 | bUpdateFootnote = lcl_SaveFootnote( rRange.aStart, rRange.aEnd, rPos, | |||
2477 | m_rDoc.GetFootnoteIdxs(), aTmpFntIdx ); | |||
2478 | } | |||
2479 | ||||
2480 | SaveRedlines_t aSaveRedl; | |||
2481 | std::vector<SwRangeRedline*> aSavRedlInsPosArr; | |||
2482 | if( SwMoveFlags::REDLINES & eMvFlags && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) | |||
2483 | { | |||
2484 | lcl_SaveRedlines( rRange, aSaveRedl ); | |||
2485 | ||||
2486 | // Find all RedLines that end at the InsPos. | |||
2487 | // These have to be moved back to the "old" position after the Move. | |||
2488 | SwRedlineTable::size_type nRedlPos = m_rDoc.getIDocumentRedlineAccess().GetRedlinePos( rPos.GetNode(), RedlineType::Any ); | |||
2489 | if( SwRedlineTable::npos != nRedlPos ) | |||
2490 | { | |||
2491 | const SwPosition *pRStt, *pREnd; | |||
2492 | do { | |||
2493 | SwRangeRedline* pTmp = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos ]; | |||
2494 | pRStt = pTmp->Start(); | |||
2495 | pREnd = pTmp->End(); | |||
2496 | if( pREnd->nNode == rPos && pRStt->nNode < rPos ) | |||
2497 | { | |||
2498 | aSavRedlInsPosArr.push_back( pTmp ); | |||
2499 | } | |||
2500 | } while( pRStt->nNode < rPos && ++nRedlPos < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()); | |||
2501 | } | |||
2502 | } | |||
2503 | ||||
2504 | // Copy all Bookmarks that are within the Move range into an array | |||
2505 | // that stores all references to positions as an offset. | |||
2506 | // The final mapping happens after the Move. | |||
2507 | std::vector< ::sw::mark::SaveBookmark> aSaveBkmks; | |||
2508 | DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks); | |||
2509 | ||||
2510 | // Save the paragraph-bound Flys, so that they can be moved. | |||
2511 | SaveFlyArr aSaveFlyArr; | |||
2512 | if( !m_rDoc.GetSpzFrameFormats()->empty() ) | |||
2513 | SaveFlyInRange( rRange, aSaveFlyArr ); | |||
2514 | ||||
2515 | // Set it to before the Position, so that it cannot be moved further. | |||
2516 | SwNodeIndex aIdx( rPos, -1 ); | |||
2517 | ||||
2518 | std::unique_ptr<SwNodeIndex> pSaveInsPos; | |||
2519 | if( pUndo ) | |||
2520 | pSaveInsPos.reset(new SwNodeIndex( rRange.aStart, -1 )); | |||
2521 | ||||
2522 | // move the Nodes | |||
2523 | bool bNoDelFrames = bool(SwMoveFlags::NO_DELFRMS & eMvFlags); | |||
2524 | if( m_rDoc.GetNodes().MoveNodes( rRange, m_rDoc.GetNodes(), rPos, !bNoDelFrames ) ) | |||
2525 | { | |||
2526 | ++aIdx; // again back to old position | |||
2527 | if( pSaveInsPos ) | |||
2528 | ++(*pSaveInsPos); | |||
2529 | } | |||
2530 | else | |||
2531 | { | |||
2532 | aIdx = rRange.aStart; | |||
2533 | pUndo.reset(); | |||
2534 | } | |||
2535 | ||||
2536 | // move the Flys to the new position | |||
2537 | if( !aSaveFlyArr.empty() ) | |||
2538 | { | |||
2539 | SwPosition const tmp(aIdx); | |||
2540 | RestFlyInRange(aSaveFlyArr, tmp, nullptr); | |||
2541 | } | |||
2542 | ||||
2543 | // Add the Bookmarks back to the Document | |||
2544 | for(auto& rBkmk : aSaveBkmks) | |||
2545 | rBkmk.SetInDoc(&m_rDoc, aIdx); | |||
2546 | ||||
2547 | if( !aSavRedlInsPosArr.empty() ) | |||
2548 | { | |||
2549 | SwNode* pNewNd = &aIdx.GetNode(); | |||
2550 | for(SwRangeRedline* pTmp : aSavRedlInsPosArr) | |||
2551 | { | |||
2552 | if( m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().Contains( pTmp ) ) | |||
2553 | { | |||
2554 | SwPosition* pEnd = pTmp->End(); | |||
2555 | pEnd->nNode = aIdx; | |||
2556 | pEnd->nContent.Assign( pNewNd->GetContentNode(), 0 ); | |||
2557 | } | |||
2558 | } | |||
2559 | } | |||
2560 | ||||
2561 | if( !aSaveRedl.empty() ) | |||
2562 | lcl_RestoreRedlines( m_rDoc, aIdx.GetIndex(), aSaveRedl ); | |||
2563 | ||||
2564 | if( pUndo ) | |||
2565 | { | |||
2566 | pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos ); | |||
2567 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); | |||
2568 | } | |||
2569 | ||||
2570 | pSaveInsPos.reset(); | |||
2571 | ||||
2572 | if( bUpdateFootnote ) | |||
2573 | { | |||
2574 | if( !aTmpFntIdx.empty() ) | |||
2575 | { | |||
2576 | m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx ); | |||
2577 | aTmpFntIdx.clear(); | |||
2578 | } | |||
2579 | ||||
2580 | m_rDoc.GetFootnoteIdxs().UpdateAllFootnote(); | |||
2581 | } | |||
2582 | ||||
2583 | if (pWrtShell && pWrtShell->GetViewOptions() && pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) | |||
2584 | { | |||
2585 | // fold all outlines that were folded before move | |||
2586 | for (SwNode* pNd : aFoldedOutlineNdsArray) | |||
2587 | pWrtShell->ToggleOutlineContentVisibility(pNd, true); | |||
2588 | } | |||
2589 | ||||
2590 | m_rDoc.getIDocumentState().SetModified(); | |||
2591 | return true; | |||
2592 | } | |||
2593 | ||||
2594 | bool DocumentContentOperationsManager::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos ) | |||
2595 | { | |||
2596 | SwNodeIndex aIdx( rPaM.Start()->nNode ); | |||
2597 | bool bJoinText = aIdx.GetNode().IsTextNode(); | |||
2598 | bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode; | |||
2599 | aIdx--; // in front of the move area! | |||
2600 | ||||
2601 | bool bRet = MoveRange( rPaM, rPos, SwMoveFlags::DEFAULT ); | |||
2602 | if( bRet && !bOneNode ) | |||
2603 | { | |||
2604 | if( bJoinText ) | |||
2605 | ++aIdx; | |||
2606 | SwTextNode * pTextNd = aIdx.GetNode().GetTextNode(); | |||
2607 | SwNodeIndex aNxtIdx( aIdx ); | |||
2608 | if( pTextNd && pTextNd->CanJoinNext( &aNxtIdx ) ) | |||
2609 | { | |||
2610 | { // Block so SwIndex into node is deleted before Join | |||
2611 | m_rDoc.CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex(pTextNd, | |||
2612 | pTextNd->GetText().getLength()) ), 0, true ); | |||
2613 | } | |||
2614 | pTextNd->JoinNext(); | |||
2615 | } | |||
2616 | } | |||
2617 | return bRet; | |||
2618 | } | |||
2619 | ||||
2620 | // Overwrite only uses the point of the PaM, the mark is ignored; characters | |||
2621 | // are replaced from point until the end of the node; at the end of the node, | |||
2622 | // characters are inserted. | |||
2623 | bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUString &rStr ) | |||
2624 | { | |||
2625 | assert(rStr.getLength())(static_cast <bool> (rStr.getLength()) ? void (0) : __assert_fail ("rStr.getLength()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2625, __extension__ __PRETTY_FUNCTION__)); | |||
2626 | SwPosition& rPt = *const_cast<SwPosition*>(rRg.GetPoint()); | |||
2627 | if( m_rDoc.GetAutoCorrExceptWord() ) // Add to AutoCorrect | |||
2628 | { | |||
2629 | if( 1 == rStr.getLength() ) | |||
2630 | m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPt, rStr[ 0 ] ); | |||
2631 | m_rDoc.DeleteAutoCorrExceptWord(); | |||
2632 | } | |||
2633 | ||||
2634 | SwTextNode *pNode = rPt.nNode.GetNode().GetTextNode(); | |||
2635 | if (!pNode || rStr.getLength() > pNode->GetSpaceLeft()) // worst case: no erase | |||
2636 | { | |||
2637 | return false; | |||
2638 | } | |||
2639 | ||||
2640 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2641 | { | |||
2642 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called | |||
2643 | } | |||
2644 | ||||
2645 | const size_t nOldAttrCnt = pNode->GetpSwpHints() | |||
2646 | ? pNode->GetpSwpHints()->Count() : 0; | |||
2647 | SwDataChanged aTmp( rRg ); | |||
2648 | SwIndex& rIdx = rPt.nContent; | |||
2649 | sal_Int32 const nActualStart(rIdx.GetIndex()); | |||
2650 | sal_Int32 nStart = 0; | |||
2651 | ||||
2652 | bool bOldExpFlg = pNode->IsIgnoreDontExpand(); | |||
2653 | pNode->SetIgnoreDontExpand( true ); | |||
2654 | ||||
2655 | for( sal_Int32 nCnt = 0; nCnt < rStr.getLength(); ++nCnt ) | |||
2656 | { | |||
2657 | // start behind the characters (to fix the attributes!) | |||
2658 | nStart = rIdx.GetIndex(); | |||
2659 | if (nStart < pNode->GetText().getLength()) | |||
2660 | { | |||
2661 | lcl_SkipAttr( pNode, rIdx, nStart ); | |||
2662 | } | |||
2663 | sal_Unicode c = rStr[ nCnt ]; | |||
2664 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2665 | { | |||
2666 | bool bMerged(false); | |||
2667 | if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | |||
2668 | { | |||
2669 | SwUndo *const pUndo = m_rDoc.GetUndoManager().GetLastUndo(); | |||
2670 | SwUndoOverwrite *const pUndoOW( | |||
2671 | dynamic_cast<SwUndoOverwrite *>(pUndo) ); | |||
2672 | if (pUndoOW) | |||
2673 | { | |||
2674 | // if CanGrouping() returns true it's already merged | |||
2675 | bMerged = pUndoOW->CanGrouping(m_rDoc, rPt, c); | |||
2676 | } | |||
2677 | } | |||
2678 | if (!bMerged) | |||
2679 | { | |||
2680 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( | |||
2681 | std::make_unique<SwUndoOverwrite>(m_rDoc, rPt, c) ); | |||
2682 | } | |||
2683 | } | |||
2684 | else | |||
2685 | { | |||
2686 | // start behind the characters (to fix the attributes!) | |||
2687 | if (nStart < pNode->GetText().getLength()) | |||
2688 | ++rIdx; | |||
2689 | pNode->InsertText( OUString(c), rIdx, SwInsertFlags::EMPTYEXPAND ); | |||
2690 | if( nStart+1 < rIdx.GetIndex() ) | |||
2691 | { | |||
2692 | rIdx = nStart; | |||
2693 | pNode->EraseText( rIdx, 1 ); | |||
2694 | ++rIdx; | |||
2695 | } | |||
2696 | } | |||
2697 | } | |||
2698 | pNode->SetIgnoreDontExpand( bOldExpFlg ); | |||
2699 | ||||
2700 | const size_t nNewAttrCnt = pNode->GetpSwpHints() | |||
2701 | ? pNode->GetpSwpHints()->Count() : 0; | |||
2702 | if( nOldAttrCnt != nNewAttrCnt ) | |||
2703 | { | |||
2704 | SwUpdateAttr aHint(0,0,0); | |||
2705 | pNode->ModifyBroadcast(nullptr, &aHint); | |||
2706 | } | |||
2707 | ||||
2708 | if (!m_rDoc.GetIDocumentUndoRedo().DoesUndo() && | |||
2709 | !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()) | |||
2710 | { | |||
2711 | SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex()); | |||
2712 | m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aPam, true, RedlineType::Any ); | |||
2713 | } | |||
2714 | else if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
2715 | { | |||
2716 | // FIXME: this redline is WRONG: there is no DELETE, and the skipped | |||
2717 | // characters are also included in aPam | |||
2718 | SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex()); | |||
2719 | m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true); | |||
2720 | } | |||
2721 | ||||
2722 | m_rDoc.getIDocumentState().SetModified(); | |||
2723 | return true; | |||
2724 | } | |||
2725 | ||||
2726 | bool DocumentContentOperationsManager::InsertString( const SwPaM &rRg, const OUString &rStr, | |||
2727 | const SwInsertFlags nInsertMode ) | |||
2728 | { | |||
2729 | // tdf#119019 accept tracked paragraph formatting to do not hide new insertions | |||
2730 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
2731 | { | |||
2732 | RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | |||
2733 | m_rDoc.getIDocumentRedlineAccess().AcceptRedlineParagraphFormatting( rRg ); | |||
2734 | if (eOld != m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags()) | |||
2735 | m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld ); | |||
2736 | } | |||
2737 | ||||
2738 | // fetching DoesUndo is surprisingly expensive | |||
2739 | bool bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo(); | |||
2740 | if (bDoesUndo) | |||
2741 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called! | |||
2742 | ||||
2743 | const SwPosition& rPos = *rRg.GetPoint(); | |||
2744 | ||||
2745 | if( m_rDoc.GetAutoCorrExceptWord() ) // add to auto correction | |||
2746 | { | |||
2747 | if( 1 == rStr.getLength() && m_rDoc.GetAutoCorrExceptWord()->IsDeleted() ) | |||
2748 | { | |||
2749 | m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPos, rStr[ 0 ] ); | |||
2750 | } | |||
2751 | m_rDoc.DeleteAutoCorrExceptWord(); | |||
2752 | } | |||
2753 | ||||
2754 | SwTextNode *const pNode = rPos.nNode.GetNode().GetTextNode(); | |||
2755 | if(!pNode) | |||
2756 | return false; | |||
2757 | ||||
2758 | SwDataChanged aTmp( rRg ); | |||
2759 | ||||
2760 | if (!bDoesUndo || !m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | |||
2761 | { | |||
2762 | OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode)); | |||
2763 | if (bDoesUndo) | |||
2764 | { | |||
2765 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( | |||
2766 | std::make_unique<SwUndoInsert>(rPos.nNode, | |||
2767 | rPos.nContent.GetIndex(), ins.getLength(), nInsertMode)); | |||
2768 | } | |||
2769 | } | |||
2770 | else | |||
2771 | { // if Undo and grouping is enabled, everything changes! | |||
2772 | SwUndoInsert * pUndo = nullptr; | |||
2773 | ||||
2774 | // don't group the start if hints at the start should be expanded | |||
2775 | if (!(nInsertMode & SwInsertFlags::FORCEHINTEXPAND)) | |||
2776 | { | |||
2777 | SwUndo *const pLastUndo = m_rDoc.GetUndoManager().GetLastUndo(); | |||
2778 | SwUndoInsert *const pUndoInsert( | |||
2779 | dynamic_cast<SwUndoInsert *>(pLastUndo) ); | |||
2780 | if (pUndoInsert && pUndoInsert->CanGrouping(rPos)) | |||
2781 | { | |||
2782 | pUndo = pUndoInsert; | |||
2783 | } | |||
2784 | } | |||
2785 | ||||
2786 | CharClass const& rCC = GetAppCharClass(); | |||
2787 | sal_Int32 nInsPos = rPos.nContent.GetIndex(); | |||
2788 | ||||
2789 | if (!pUndo) | |||
2790 | { | |||
2791 | pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 0, nInsertMode, | |||
2792 | !rCC.isLetterNumeric( rStr, 0 ) ); | |||
2793 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) ); | |||
2794 | } | |||
2795 | ||||
2796 | OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode)); | |||
2797 | ||||
2798 | for (sal_Int32 i = 0; i < ins.getLength(); ++i) | |||
2799 | { | |||
2800 | nInsPos++; | |||
2801 | // if CanGrouping() returns true, everything has already been done | |||
2802 | if (!pUndo->CanGrouping(ins[i])) | |||
2803 | { | |||
2804 | pUndo = new SwUndoInsert(rPos.nNode, nInsPos, 1, nInsertMode, | |||
2805 | !rCC.isLetterNumeric(ins, i)); | |||
2806 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) ); | |||
2807 | } | |||
2808 | } | |||
2809 | } | |||
2810 | ||||
2811 | // To-Do - add 'SwExtraRedlineTable' also ? | |||
2812 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )) | |||
2813 | { | |||
2814 | SwPaM aPam( rPos.nNode, aTmp.GetContent(), | |||
2815 | rPos.nNode, rPos.nContent.GetIndex()); | |||
2816 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | |||
2817 | { | |||
2818 | m_rDoc.getIDocumentRedlineAccess().AppendRedline( | |||
2819 | new SwRangeRedline( RedlineType::Insert, aPam ), true); | |||
2820 | } | |||
2821 | else | |||
2822 | { | |||
2823 | m_rDoc.getIDocumentRedlineAccess().SplitRedline( aPam ); | |||
2824 | } | |||
2825 | } | |||
2826 | ||||
2827 | m_rDoc.getIDocumentState().SetModified(); | |||
2828 | return true; | |||
2829 | } | |||
2830 | ||||
2831 | void DocumentContentOperationsManager::TransliterateText( | |||
2832 | const SwPaM& rPaM, | |||
2833 | utl::TransliterationWrapper& rTrans ) | |||
2834 | { | |||
2835 | std::unique_ptr<SwUndoTransliterate> pUndo; | |||
2836 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2837 | pUndo.reset(new SwUndoTransliterate( rPaM, rTrans )); | |||
2838 | ||||
2839 | const SwPosition* pStt = rPaM.Start(), | |||
2840 | * pEnd = rPaM.End(); | |||
2841 | sal_uLong nSttNd = pStt->nNode.GetIndex(), | |||
2842 | nEndNd = pEnd->nNode.GetIndex(); | |||
2843 | sal_Int32 nSttCnt = pStt->nContent.GetIndex(); | |||
2844 | sal_Int32 nEndCnt = pEnd->nContent.GetIndex(); | |||
2845 | ||||
2846 | SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode(); | |||
2847 | if( pStt == pEnd && pTNd ) // no selection? | |||
2848 | { | |||
2849 | // set current word as 'area of effect' | |||
2850 | ||||
2851 | assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt-> GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 2851, __extension__ __PRETTY_FUNCTION__)); | |||
2852 | Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary( | |||
2853 | pTNd->GetText(), nSttCnt, | |||
2854 | g_pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ), | |||
2855 | WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, | |||
2856 | true); | |||
2857 | ||||
2858 | if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos ) | |||
2859 | { | |||
2860 | nSttCnt = aBndry.startPos; | |||
2861 | nEndCnt = aBndry.endPos; | |||
2862 | } | |||
2863 | } | |||
2864 | ||||
2865 | if( nSttNd != nEndNd ) // is more than one text node involved? | |||
2866 | { | |||
2867 | // iterate over all effected text nodes, the first and the last one | |||
2868 | // may be incomplete because the selection starts and/or ends there | |||
2869 | ||||
2870 | SwNodeIndex aIdx( pStt->nNode ); | |||
2871 | if( nSttCnt ) | |||
2872 | { | |||
2873 | ++aIdx; | |||
2874 | if( pTNd ) | |||
2875 | pTNd->TransliterateText( | |||
2876 | rTrans, nSttCnt, pTNd->GetText().getLength(), pUndo.get()); | |||
2877 | } | |||
2878 | ||||
2879 | for( ; aIdx.GetIndex() < nEndNd; ++aIdx ) | |||
2880 | { | |||
2881 | pTNd = aIdx.GetNode().GetTextNode(); | |||
2882 | if (pTNd) | |||
2883 | { | |||
2884 | pTNd->TransliterateText( | |||
2885 | rTrans, 0, pTNd->GetText().getLength(), pUndo.get()); | |||
2886 | } | |||
2887 | } | |||
2888 | ||||
2889 | if( nEndCnt && nullptr != ( pTNd = pEnd->nNode.GetNode().GetTextNode() )) | |||
2890 | pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo.get() ); | |||
2891 | } | |||
2892 | else if( pTNd && nSttCnt < nEndCnt ) | |||
2893 | pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo.get() ); | |||
2894 | ||||
2895 | if( pUndo && pUndo->HasData() ) | |||
2896 | { | |||
2897 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); | |||
2898 | } | |||
2899 | m_rDoc.getIDocumentState().SetModified(); | |||
2900 | } | |||
2901 | ||||
2902 | SwFlyFrameFormat* DocumentContentOperationsManager::InsertGraphic( | |||
2903 | const SwPaM &rRg, | |||
2904 | const OUString& rGrfName, | |||
2905 | const OUString& rFltName, | |||
2906 | const Graphic* pGraphic, | |||
2907 | const SfxItemSet* pFlyAttrSet, | |||
2908 | const SfxItemSet* pGrfAttrSet, | |||
2909 | SwFrameFormat* pFrameFormat ) | |||
2910 | { | |||
2911 | if( !pFrameFormat ) | |||
2912 | pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC ); | |||
2913 | SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode( | |||
2914 | SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ), | |||
2915 | rGrfName, rFltName, pGraphic, | |||
2916 | m_rDoc.GetDfltGrfFormatColl() ); | |||
2917 | SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode, | |||
2918 | pFlyAttrSet, pGrfAttrSet, pFrameFormat ); | |||
2919 | return pSwFlyFrameFormat; | |||
2920 | } | |||
2921 | ||||
2922 | SwFlyFrameFormat* DocumentContentOperationsManager::InsertGraphicObject( | |||
2923 | const SwPaM &rRg, const GraphicObject& rGrfObj, | |||
2924 | const SfxItemSet* pFlyAttrSet, | |||
2925 | const SfxItemSet* pGrfAttrSet ) | |||
2926 | { | |||
2927 | SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC ); | |||
2928 | SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode( | |||
2929 | SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ), | |||
2930 | rGrfObj, m_rDoc.GetDfltGrfFormatColl() ); | |||
2931 | SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode, | |||
2932 | pFlyAttrSet, pGrfAttrSet, pFrameFormat ); | |||
2933 | return pSwFlyFrameFormat; | |||
2934 | } | |||
2935 | ||||
2936 | SwFlyFrameFormat* DocumentContentOperationsManager::InsertEmbObject( | |||
2937 | const SwPaM &rRg, const svt::EmbeddedObjectRef& xObj, | |||
2938 | SfxItemSet* pFlyAttrSet) | |||
2939 | { | |||
2940 | sal_uInt16 nId = RES_POOLFRM_OLE; | |||
2941 | if (xObj.is()) | |||
2942 | { | |||
2943 | SvGlobalName aClassName( xObj->getClassID() ); | |||
2944 | if (SotExchange::IsMath(aClassName)) | |||
2945 | { | |||
2946 | nId = RES_POOLFRM_FORMEL; | |||
2947 | } | |||
2948 | } | |||
2949 | ||||
2950 | SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( nId ); | |||
2951 | ||||
2952 | return InsNoTextNode( *rRg.GetPoint(), m_rDoc.GetNodes().MakeOLENode( | |||
2953 | SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ), | |||
2954 | xObj, | |||
2955 | m_rDoc.GetDfltGrfFormatColl() ), | |||
2956 | pFlyAttrSet, nullptr, | |||
2957 | pFrameFormat ); | |||
2958 | } | |||
2959 | ||||
2960 | SwFlyFrameFormat* DocumentContentOperationsManager::InsertOLE(const SwPaM &rRg, const OUString& rObjName, | |||
2961 | sal_Int64 nAspect, | |||
2962 | const SfxItemSet* pFlyAttrSet, | |||
2963 | const SfxItemSet* pGrfAttrSet) | |||
2964 | { | |||
2965 | SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_OLE ); | |||
2966 | ||||
2967 | return InsNoTextNode( *rRg.GetPoint(), | |||
2968 | m_rDoc.GetNodes().MakeOLENode( | |||
2969 | SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ), | |||
2970 | rObjName, | |||
2971 | nAspect, | |||
2972 | m_rDoc.GetDfltGrfFormatColl(), | |||
2973 | nullptr ), | |||
2974 | pFlyAttrSet, pGrfAttrSet, | |||
2975 | pFrameFormat ); | |||
2976 | } | |||
2977 | ||||
2978 | void DocumentContentOperationsManager::ReRead( SwPaM& rPam, const OUString& rGrfName, | |||
2979 | const OUString& rFltName, const Graphic* pGraphic ) | |||
2980 | { | |||
2981 | SwGrfNode *pGrfNd; | |||
2982 | if( !(( !rPam.HasMark() | |||
2983 | || rPam.GetPoint()->nNode.GetIndex() == rPam.GetMark()->nNode.GetIndex() ) | |||
2984 | && nullptr != ( pGrfNd = rPam.GetPoint()->nNode.GetNode().GetGrfNode() )) ) | |||
2985 | return; | |||
2986 | ||||
2987 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | |||
2988 | { | |||
2989 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoReRead>(rPam, *pGrfNd)); | |||
2990 | } | |||
2991 | ||||
2992 | // Because we don't know if we can mirror the graphic, the mirror attribute is always reset | |||
2993 | if( MirrorGraph::Dont != pGrfNd->GetSwAttrSet(). | |||
2994 | GetMirrorGrf().GetValue() ) | |||
2995 | pGrfNd->SetAttr( SwMirrorGrf() ); | |||
2996 | ||||
2997 | pGrfNd->ReRead( rGrfName, rFltName, pGraphic ); | |||
2998 | m_rDoc.getIDocumentState().SetModified(); | |||
2999 | } | |||
3000 | ||||
3001 | // Insert drawing object, which has to be already inserted in the DrawModel | |||
3002 | SwDrawFrameFormat* DocumentContentOperationsManager::InsertDrawObj( | |||
3003 | const SwPaM &rRg, | |||
3004 | SdrObject& rDrawObj, | |||
3005 | const SfxItemSet& rFlyAttrSet ) | |||
3006 | { | |||
3007 | SwDrawFrameFormat* pFormat = m_rDoc.MakeDrawFrameFormat( OUString(), m_rDoc.GetDfltFrameFormat() ); | |||
3008 | ||||
3009 | const SwFormatAnchor* pAnchor = nullptr; | |||
3010 | rFlyAttrSet.GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchor) ); | |||
3011 | pFormat->SetFormatAttr( rFlyAttrSet ); | |||
3012 | ||||
3013 | // Didn't set the Anchor yet? | |||
3014 | // DrawObjecte must never end up in the Header/Footer! | |||
3015 | RndStdIds eAnchorId = pAnchor != nullptr ? pAnchor->GetAnchorId() : pFormat->GetAnchor().GetAnchorId(); | |||
| ||||
3016 | const bool bIsAtContent = (RndStdIds::FLY_AT_PAGE != eAnchorId); | |||
3017 | ||||
3018 | const SwNodeIndex* pChkIdx = nullptr; | |||
3019 | if ( pAnchor == nullptr ) | |||
3020 | { | |||
3021 | pChkIdx = &rRg.GetPoint()->nNode; | |||
3022 | } | |||
3023 | else if ( bIsAtContent
| |||
3024 | { | |||
3025 | pChkIdx = | |||
3026 | pAnchor->GetContentAnchor() ? &pAnchor->GetContentAnchor()->nNode : &rRg.GetPoint()->nNode; | |||
3027 | } | |||
3028 | ||||
3029 | // allow drawing objects in header/footer, but control objects aren't allowed in header/footer. | |||
3030 | if( pChkIdx != nullptr | |||
3031 | && ::CheckControlLayer( &rDrawObj ) | |||
3032 | && m_rDoc.IsInHeaderFooter( *pChkIdx ) ) | |||
3033 | { | |||
3034 | // apply at-page anchor format | |||
3035 | eAnchorId = RndStdIds::FLY_AT_PAGE; | |||
3036 | pFormat->SetFormatAttr( SwFormatAnchor( eAnchorId ) ); | |||
3037 | } | |||
3038 | else if( pAnchor == nullptr | |||
3039 | || ( bIsAtContent |
5.1 | 'bIsAtContent' is false |
5.2 | 'eAnchorId' is not equal to FLY_AS_CHAR |
10 | Potential leak of memory pointed to by 'pContact' |