File: | home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx |
Warning: | line 5156, column 9 Called C++ object pointer is null |
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 | ||||||||||||||
3040 | && pAnchor->GetContentAnchor() == nullptr ) ) | ||||||||||||||
3041 | { | ||||||||||||||
3042 | // apply anchor format | ||||||||||||||
3043 | SwFormatAnchor aAnch( pAnchor != nullptr ? *pAnchor : pFormat->GetAnchor() ); | ||||||||||||||
3044 | eAnchorId = aAnch.GetAnchorId(); | ||||||||||||||
3045 | if ( eAnchorId == RndStdIds::FLY_AT_FLY ) | ||||||||||||||
3046 | { | ||||||||||||||
3047 | const SwStartNode* pStartNode = rRg.GetNode().FindFlyStartNode(); | ||||||||||||||
3048 | assert(pStartNode)(static_cast <bool> (pStartNode) ? void (0) : __assert_fail ("pStartNode", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3048, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3049 | SwPosition aPos(*pStartNode); | ||||||||||||||
3050 | aAnch.SetAnchor( &aPos ); | ||||||||||||||
3051 | } | ||||||||||||||
3052 | else | ||||||||||||||
3053 | { | ||||||||||||||
3054 | aAnch.SetAnchor( rRg.GetPoint() ); | ||||||||||||||
3055 | if ( eAnchorId == RndStdIds::FLY_AT_PAGE ) | ||||||||||||||
3056 | { | ||||||||||||||
3057 | eAnchorId = dynamic_cast<const SdrUnoObj*>( &rDrawObj) != nullptr ? RndStdIds::FLY_AS_CHAR : RndStdIds::FLY_AT_PARA; | ||||||||||||||
3058 | aAnch.SetType( eAnchorId ); | ||||||||||||||
3059 | } | ||||||||||||||
3060 | } | ||||||||||||||
3061 | pFormat->SetFormatAttr( aAnch ); | ||||||||||||||
3062 | } | ||||||||||||||
3063 | |||||||||||||||
3064 | // insert text attribute for as-character anchored drawing object | ||||||||||||||
3065 | if ( eAnchorId == RndStdIds::FLY_AS_CHAR ) | ||||||||||||||
3066 | { | ||||||||||||||
3067 | bool bAnchorAtPageAsFallback = true; | ||||||||||||||
3068 | const SwFormatAnchor& rDrawObjAnchorFormat = pFormat->GetAnchor(); | ||||||||||||||
3069 | if ( rDrawObjAnchorFormat.GetContentAnchor() != nullptr ) | ||||||||||||||
3070 | { | ||||||||||||||
3071 | SwTextNode* pAnchorTextNode = | ||||||||||||||
3072 | rDrawObjAnchorFormat.GetContentAnchor()->nNode.GetNode().GetTextNode(); | ||||||||||||||
3073 | if ( pAnchorTextNode != nullptr ) | ||||||||||||||
3074 | { | ||||||||||||||
3075 | const sal_Int32 nStt = rDrawObjAnchorFormat.GetContentAnchor()->nContent.GetIndex(); | ||||||||||||||
3076 | SwFormatFlyCnt aFormat( pFormat ); | ||||||||||||||
3077 | pAnchorTextNode->InsertItem( aFormat, nStt, nStt ); | ||||||||||||||
3078 | bAnchorAtPageAsFallback = false; | ||||||||||||||
3079 | } | ||||||||||||||
3080 | } | ||||||||||||||
3081 | |||||||||||||||
3082 | if ( bAnchorAtPageAsFallback ) | ||||||||||||||
3083 | { | ||||||||||||||
3084 | OSL_ENSURE( false, "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page" )do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3084" ": "), "%s", "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page" ); } } while (false); | ||||||||||||||
3085 | pFormat->SetFormatAttr( SwFormatAnchor( RndStdIds::FLY_AT_PAGE ) ); | ||||||||||||||
3086 | } | ||||||||||||||
3087 | } | ||||||||||||||
3088 | |||||||||||||||
3089 | SwDrawContact* pContact = new SwDrawContact( pFormat, &rDrawObj ); | ||||||||||||||
3090 | |||||||||||||||
3091 | // Create Frames if necessary | ||||||||||||||
3092 | if( m_rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() ) | ||||||||||||||
3093 | { | ||||||||||||||
3094 | // create layout representation | ||||||||||||||
3095 | pFormat->MakeFrames(); | ||||||||||||||
3096 | // #i42319# - follow-up of #i35635# | ||||||||||||||
3097 | // move object to visible layer | ||||||||||||||
3098 | // #i79391# | ||||||||||||||
3099 | if ( pContact->GetAnchorFrame() ) | ||||||||||||||
3100 | { | ||||||||||||||
3101 | pContact->MoveObjToVisibleLayer( &rDrawObj ); | ||||||||||||||
3102 | } | ||||||||||||||
3103 | } | ||||||||||||||
3104 | |||||||||||||||
3105 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3106 | { | ||||||||||||||
3107 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsLayFormat>(pFormat, 0, 0) ); | ||||||||||||||
3108 | } | ||||||||||||||
3109 | |||||||||||||||
3110 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3111 | return pFormat; | ||||||||||||||
3112 | } | ||||||||||||||
3113 | |||||||||||||||
3114 | bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool bChkTableStart ) | ||||||||||||||
3115 | { | ||||||||||||||
3116 | SwContentNode *pNode = rPos.nNode.GetNode().GetContentNode(); | ||||||||||||||
3117 | if(nullptr == pNode) | ||||||||||||||
3118 | return false; | ||||||||||||||
3119 | |||||||||||||||
3120 | { | ||||||||||||||
3121 | // BUG 26675: Send DataChanged before deleting, so that we notice which objects are in scope. | ||||||||||||||
3122 | // After that they can be before/after the position. | ||||||||||||||
3123 | SwDataChanged aTmp( m_rDoc, rPos ); | ||||||||||||||
3124 | } | ||||||||||||||
3125 | |||||||||||||||
3126 | SwUndoSplitNode* pUndo = nullptr; | ||||||||||||||
3127 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3128 | { | ||||||||||||||
3129 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | ||||||||||||||
3130 | // insert the Undo object (currently only for TextNode) | ||||||||||||||
3131 | if( pNode->IsTextNode() ) | ||||||||||||||
3132 | { | ||||||||||||||
3133 | pUndo = new SwUndoSplitNode( m_rDoc, rPos, bChkTableStart ); | ||||||||||||||
3134 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo)); | ||||||||||||||
3135 | } | ||||||||||||||
3136 | } | ||||||||||||||
3137 | |||||||||||||||
3138 | // Update the rsid of the old and the new node unless | ||||||||||||||
3139 | // the old node is split at the beginning or at the end | ||||||||||||||
3140 | SwTextNode *pTextNode = rPos.nNode.GetNode().GetTextNode(); | ||||||||||||||
3141 | const sal_Int32 nPos = rPos.nContent.GetIndex(); | ||||||||||||||
3142 | if( pTextNode && nPos && nPos != pTextNode->Len() ) | ||||||||||||||
3143 | { | ||||||||||||||
3144 | m_rDoc.UpdateParRsid( pTextNode ); | ||||||||||||||
3145 | } | ||||||||||||||
3146 | |||||||||||||||
3147 | //JP 28.01.97: Special case for SplitNode at table start: | ||||||||||||||
3148 | // If it is at the beginning of a Doc/Fly/Footer/... or right at after a table | ||||||||||||||
3149 | // then insert a paragraph before it. | ||||||||||||||
3150 | if( bChkTableStart && !rPos.nContent.GetIndex() && pNode->IsTextNode() ) | ||||||||||||||
3151 | { | ||||||||||||||
3152 | sal_uLong nPrevPos = rPos.nNode.GetIndex() - 1; | ||||||||||||||
3153 | const SwTableNode* pTableNd; | ||||||||||||||
3154 | const SwNode* pNd = m_rDoc.GetNodes()[ nPrevPos ]; | ||||||||||||||
3155 | if( pNd->IsStartNode() && | ||||||||||||||
3156 | SwTableBoxStartNode == static_cast<const SwStartNode*>(pNd)->GetStartNodeType() && | ||||||||||||||
3157 | nullptr != ( pTableNd = m_rDoc.GetNodes()[ --nPrevPos ]->GetTableNode() ) && | ||||||||||||||
3158 | ((( pNd = m_rDoc.GetNodes()[ --nPrevPos ])->IsStartNode() && | ||||||||||||||
3159 | SwTableBoxStartNode != static_cast<const SwStartNode*>(pNd)->GetStartNodeType() ) | ||||||||||||||
3160 | || ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() ) | ||||||||||||||
3161 | || pNd->IsContentNode() )) | ||||||||||||||
3162 | { | ||||||||||||||
3163 | if( pNd->IsContentNode() ) | ||||||||||||||
3164 | { | ||||||||||||||
3165 | //JP 30.04.99 Bug 65660: | ||||||||||||||
3166 | // There are no page breaks outside of the normal body area, | ||||||||||||||
3167 | // so this is not a valid condition to insert a paragraph. | ||||||||||||||
3168 | if( nPrevPos < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() ) | ||||||||||||||
3169 | pNd = nullptr; | ||||||||||||||
3170 | else | ||||||||||||||
3171 | { | ||||||||||||||
3172 | // Only if the table has page breaks! | ||||||||||||||
3173 | const SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat(); | ||||||||||||||
3174 | if( SfxItemState::SET != pFrameFormat->GetItemState(RES_PAGEDESC, false) && | ||||||||||||||
3175 | SfxItemState::SET != pFrameFormat->GetItemState( RES_BREAK, false ) ) | ||||||||||||||
3176 | pNd = nullptr; | ||||||||||||||
3177 | } | ||||||||||||||
3178 | } | ||||||||||||||
3179 | |||||||||||||||
3180 | if( pNd ) | ||||||||||||||
3181 | { | ||||||||||||||
3182 | SwTextNode* pTextNd = m_rDoc.GetNodes().MakeTextNode( | ||||||||||||||
3183 | SwNodeIndex( *pTableNd ), | ||||||||||||||
3184 | m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT )); | ||||||||||||||
3185 | if( pTextNd ) | ||||||||||||||
3186 | { | ||||||||||||||
3187 | const_cast<SwPosition&>(rPos).nNode = pTableNd->GetIndex()-1; | ||||||||||||||
3188 | const_cast<SwPosition&>(rPos).nContent.Assign( pTextNd, 0 ); | ||||||||||||||
3189 | |||||||||||||||
3190 | // only add page breaks/styles to the body area | ||||||||||||||
3191 | if( nPrevPos > m_rDoc.GetNodes().GetEndOfExtras().GetIndex() ) | ||||||||||||||
3192 | { | ||||||||||||||
3193 | SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat(); | ||||||||||||||
3194 | const SfxPoolItem *pItem; | ||||||||||||||
3195 | if( SfxItemState::SET == pFrameFormat->GetItemState( RES_PAGEDESC, | ||||||||||||||
3196 | false, &pItem ) ) | ||||||||||||||
3197 | { | ||||||||||||||
3198 | pTextNd->SetAttr( *pItem ); | ||||||||||||||
3199 | pFrameFormat->ResetFormatAttr( RES_PAGEDESC ); | ||||||||||||||
3200 | } | ||||||||||||||
3201 | if( SfxItemState::SET == pFrameFormat->GetItemState( RES_BREAK, | ||||||||||||||
3202 | false, &pItem ) ) | ||||||||||||||
3203 | { | ||||||||||||||
3204 | pTextNd->SetAttr( *pItem ); | ||||||||||||||
3205 | pFrameFormat->ResetFormatAttr( RES_BREAK ); | ||||||||||||||
3206 | } | ||||||||||||||
3207 | } | ||||||||||||||
3208 | |||||||||||||||
3209 | if( pUndo ) | ||||||||||||||
3210 | pUndo->SetTableFlag(); | ||||||||||||||
3211 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3212 | return true; | ||||||||||||||
3213 | } | ||||||||||||||
3214 | } | ||||||||||||||
3215 | } | ||||||||||||||
3216 | } | ||||||||||||||
3217 | |||||||||||||||
3218 | const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create()); | ||||||||||||||
3219 | pContentStore->Save( m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true ); | ||||||||||||||
3220 | assert(pNode->IsTextNode())(static_cast <bool> (pNode->IsTextNode()) ? void (0) : __assert_fail ("pNode->IsTextNode()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3220, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3221 | std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc( | ||||||||||||||
3222 | [&](SwTextNode *const, sw::mark::RestoreMode const eMode) | ||||||||||||||
3223 | { | ||||||||||||||
3224 | if (!pContentStore->Empty()) | ||||||||||||||
3225 | { // move all bookmarks, TOXMarks, FlyAtCnt | ||||||||||||||
3226 | pContentStore->Restore(m_rDoc, rPos.nNode.GetIndex()-1, 0, true, eMode); | ||||||||||||||
3227 | } | ||||||||||||||
3228 | if (eMode & sw::mark::RestoreMode::NonFlys) | ||||||||||||||
3229 | { | ||||||||||||||
3230 | // To-Do - add 'SwExtraRedlineTable' also ? | ||||||||||||||
3231 | if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || | ||||||||||||||
3232 | (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && | ||||||||||||||
3233 | !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())) | ||||||||||||||
3234 | { | ||||||||||||||
3235 | SwPaM aPam( rPos ); | ||||||||||||||
3236 | aPam.SetMark(); | ||||||||||||||
3237 | aPam.Move( fnMoveBackward ); | ||||||||||||||
3238 | if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()) | ||||||||||||||
3239 | { | ||||||||||||||
3240 | m_rDoc.getIDocumentRedlineAccess().AppendRedline( | ||||||||||||||
3241 | new SwRangeRedline(RedlineType::Insert, aPam), true); | ||||||||||||||
3242 | } | ||||||||||||||
3243 | else | ||||||||||||||
3244 | { | ||||||||||||||
3245 | m_rDoc.getIDocumentRedlineAccess().SplitRedline(aPam); | ||||||||||||||
3246 | } | ||||||||||||||
3247 | } | ||||||||||||||
3248 | } | ||||||||||||||
3249 | }); | ||||||||||||||
3250 | pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc); | ||||||||||||||
3251 | |||||||||||||||
3252 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3253 | return true; | ||||||||||||||
3254 | } | ||||||||||||||
3255 | |||||||||||||||
3256 | bool DocumentContentOperationsManager::AppendTextNode( SwPosition& rPos ) | ||||||||||||||
3257 | { | ||||||||||||||
3258 | // create new node before EndOfContent | ||||||||||||||
3259 | SwTextNode * pCurNode = rPos.nNode.GetNode().GetTextNode(); | ||||||||||||||
3260 | if( !pCurNode ) | ||||||||||||||
3261 | { | ||||||||||||||
3262 | // so then one can be created! | ||||||||||||||
3263 | SwNodeIndex aIdx( rPos.nNode, 1 ); | ||||||||||||||
3264 | pCurNode = m_rDoc.GetNodes().MakeTextNode( aIdx, | ||||||||||||||
3265 | m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD )); | ||||||||||||||
3266 | } | ||||||||||||||
3267 | else | ||||||||||||||
3268 | pCurNode = pCurNode->AppendNode( rPos )->GetTextNode(); | ||||||||||||||
3269 | |||||||||||||||
3270 | rPos.nNode++; | ||||||||||||||
3271 | rPos.nContent.Assign( pCurNode, 0 ); | ||||||||||||||
3272 | |||||||||||||||
3273 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3274 | { | ||||||||||||||
3275 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsert>( rPos.nNode ) ); | ||||||||||||||
3276 | } | ||||||||||||||
3277 | |||||||||||||||
3278 | // To-Do - add 'SwExtraRedlineTable' also ? | ||||||||||||||
3279 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )) | ||||||||||||||
3280 | { | ||||||||||||||
3281 | SwPaM aPam( rPos ); | ||||||||||||||
3282 | aPam.SetMark(); | ||||||||||||||
3283 | aPam.Move( fnMoveBackward ); | ||||||||||||||
3284 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | ||||||||||||||
3285 | m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true); | ||||||||||||||
3286 | else | ||||||||||||||
3287 | m_rDoc.getIDocumentRedlineAccess().SplitRedline( aPam ); | ||||||||||||||
3288 | } | ||||||||||||||
3289 | |||||||||||||||
3290 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3291 | return true; | ||||||||||||||
3292 | } | ||||||||||||||
3293 | |||||||||||||||
3294 | bool DocumentContentOperationsManager::ReplaceRange( SwPaM& rPam, const OUString& rStr, | ||||||||||||||
3295 | const bool bRegExReplace ) | ||||||||||||||
3296 | { | ||||||||||||||
3297 | // unfortunately replace works slightly differently from delete, | ||||||||||||||
3298 | // so we cannot use lcl_DoWithBreaks here... | ||||||||||||||
3299 | |||||||||||||||
3300 | std::vector<std::pair<sal_uLong, sal_Int32>> Breaks; | ||||||||||||||
3301 | |||||||||||||||
3302 | SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() ); | ||||||||||||||
3303 | aPam.Normalize(false); | ||||||||||||||
3304 | if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode) | ||||||||||||||
3305 | { | ||||||||||||||
3306 | aPam.Move(fnMoveBackward); | ||||||||||||||
3307 | } | ||||||||||||||
3308 | OSL_ENSURE((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?")do { if (true && (!((aPam.GetPoint()->nNode == aPam .GetMark()->nNode)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3308" ": "), "%s", "invalid pam?"); } } while (false); | ||||||||||||||
3309 | |||||||||||||||
3310 | sw::CalcBreaks(Breaks, aPam); | ||||||||||||||
3311 | |||||||||||||||
3312 | while (!Breaks.empty() // skip over prefix of dummy chars | ||||||||||||||
3313 | && (aPam.GetMark()->nNode.GetIndex() == Breaks.begin()->first) | ||||||||||||||
3314 | && (aPam.GetMark()->nContent.GetIndex() == Breaks.begin()->second)) | ||||||||||||||
3315 | { | ||||||||||||||
3316 | // skip! | ||||||||||||||
3317 | ++aPam.GetMark()->nContent; // always in bounds if Breaks valid | ||||||||||||||
3318 | Breaks.erase(Breaks.begin()); | ||||||||||||||
3319 | } | ||||||||||||||
3320 | *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix | ||||||||||||||
3321 | |||||||||||||||
3322 | if (Breaks.empty()) | ||||||||||||||
3323 | { | ||||||||||||||
3324 | // park aPam somewhere so it does not point to node that is deleted | ||||||||||||||
3325 | aPam.DeleteMark(); | ||||||||||||||
3326 | *aPam.GetPoint() = SwPosition(m_rDoc.GetNodes().GetEndOfContent()); | ||||||||||||||
3327 | return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam! | ||||||||||||||
3328 | } | ||||||||||||||
3329 | |||||||||||||||
3330 | // Deletion must be split into several parts if the text node | ||||||||||||||
3331 | // contains a text attribute with end and with dummy character | ||||||||||||||
3332 | // and the selection does not contain the text attribute completely, | ||||||||||||||
3333 | // but overlaps its start (left), where the dummy character is. | ||||||||||||||
3334 | |||||||||||||||
3335 | bool bRet( true ); | ||||||||||||||
3336 | // iterate from end to start, to avoid invalidating the offsets! | ||||||||||||||
3337 | auto iter( Breaks.rbegin() ); | ||||||||||||||
3338 | sal_uLong nOffset(0); | ||||||||||||||
3339 | SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes()); | ||||||||||||||
3340 | OSL_ENSURE(aPam.GetPoint() == aPam.End(), "wrong!")do { if (true && (!(aPam.GetPoint() == aPam.End()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3340" ": "), "%s", "wrong!"); } } while (false); | ||||||||||||||
3341 | SwPosition & rEnd( *aPam.End() ); | ||||||||||||||
3342 | SwPosition & rStart( *aPam.Start() ); | ||||||||||||||
3343 | |||||||||||||||
3344 | // set end of temp pam to original end (undo Move backward above) | ||||||||||||||
3345 | rEnd = *rPam.End(); | ||||||||||||||
3346 | // after first deletion, rEnd will point into the original text node again! | ||||||||||||||
3347 | |||||||||||||||
3348 | while (iter != Breaks.rend()) | ||||||||||||||
3349 | { | ||||||||||||||
3350 | rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1); | ||||||||||||||
3351 | if (rStart < rEnd) // check if part is empty | ||||||||||||||
3352 | { | ||||||||||||||
3353 | bRet &= (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()) | ||||||||||||||
3354 | ? DeleteAndJoinWithRedlineImpl(aPam) | ||||||||||||||
3355 | : DeleteAndJoinImpl(aPam, false); | ||||||||||||||
3356 | nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes... | ||||||||||||||
3357 | } | ||||||||||||||
3358 | rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second); | ||||||||||||||
3359 | ++iter; | ||||||||||||||
3360 | } | ||||||||||||||
3361 | |||||||||||||||
3362 | rStart = *rPam.Start(); // set to original start | ||||||||||||||
3363 | assert(rStart < rEnd && "replace part empty!")(static_cast <bool> (rStart < rEnd && "replace part empty!" ) ? void (0) : __assert_fail ("rStart < rEnd && \"replace part empty!\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3363, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3364 | if (rStart < rEnd) // check if part is empty | ||||||||||||||
3365 | { | ||||||||||||||
3366 | bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace); | ||||||||||||||
3367 | } | ||||||||||||||
3368 | |||||||||||||||
3369 | rPam = aPam; // update original pam (is this required?) | ||||||||||||||
3370 | |||||||||||||||
3371 | return bRet; | ||||||||||||||
3372 | } | ||||||||||||||
3373 | |||||||||||||||
3374 | ///Add a para for the char attribute exp... | ||||||||||||||
3375 | bool DocumentContentOperationsManager::InsertPoolItem( | ||||||||||||||
3376 | const SwPaM &rRg, | ||||||||||||||
3377 | const SfxPoolItem &rHt, | ||||||||||||||
3378 | const SetAttrMode nFlags, | ||||||||||||||
3379 | SwRootFrame const*const pLayout, | ||||||||||||||
3380 | const bool bExpandCharToPara, | ||||||||||||||
3381 | SwTextAttr **ppNewTextAttr) | ||||||||||||||
3382 | { | ||||||||||||||
3383 | if (utl::ConfigManager::IsFuzzing()) | ||||||||||||||
3384 | return false; | ||||||||||||||
3385 | |||||||||||||||
3386 | SwDataChanged aTmp( rRg ); | ||||||||||||||
3387 | std::unique_ptr<SwUndoAttr> pUndoAttr; | ||||||||||||||
3388 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3389 | { | ||||||||||||||
3390 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | ||||||||||||||
3391 | pUndoAttr.reset(new SwUndoAttr( rRg, rHt, nFlags )); | ||||||||||||||
3392 | } | ||||||||||||||
3393 | |||||||||||||||
3394 | SfxItemSet aSet( m_rDoc.GetAttrPool(), {{rHt.Which(), rHt.Which()}} ); | ||||||||||||||
3395 | aSet.Put( rHt ); | ||||||||||||||
3396 | const bool bRet = lcl_InsAttr(m_rDoc, rRg, aSet, nFlags, pUndoAttr.get(), pLayout, bExpandCharToPara, ppNewTextAttr); | ||||||||||||||
3397 | |||||||||||||||
3398 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3399 | { | ||||||||||||||
3400 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) ); | ||||||||||||||
3401 | } | ||||||||||||||
3402 | |||||||||||||||
3403 | if( bRet ) | ||||||||||||||
3404 | { | ||||||||||||||
3405 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3406 | } | ||||||||||||||
3407 | return bRet; | ||||||||||||||
3408 | } | ||||||||||||||
3409 | |||||||||||||||
3410 | void DocumentContentOperationsManager::InsertItemSet ( const SwPaM &rRg, const SfxItemSet &rSet, | ||||||||||||||
3411 | const SetAttrMode nFlags, SwRootFrame const*const pLayout) | ||||||||||||||
3412 | { | ||||||||||||||
3413 | SwDataChanged aTmp( rRg ); | ||||||||||||||
3414 | std::unique_ptr<SwUndoAttr> pUndoAttr; | ||||||||||||||
3415 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3416 | { | ||||||||||||||
3417 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | ||||||||||||||
3418 | pUndoAttr.reset(new SwUndoAttr( rRg, rSet, nFlags )); | ||||||||||||||
3419 | } | ||||||||||||||
3420 | |||||||||||||||
3421 | bool bRet = lcl_InsAttr(m_rDoc, rRg, rSet, nFlags, pUndoAttr.get(), pLayout, /*bExpandCharToPara*/false, /*ppNewTextAttr*/nullptr ); | ||||||||||||||
3422 | |||||||||||||||
3423 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3424 | { | ||||||||||||||
3425 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) ); | ||||||||||||||
3426 | } | ||||||||||||||
3427 | |||||||||||||||
3428 | if( bRet ) | ||||||||||||||
3429 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
3430 | } | ||||||||||||||
3431 | |||||||||||||||
3432 | void DocumentContentOperationsManager::RemoveLeadingWhiteSpace(const SwPosition & rPos ) | ||||||||||||||
3433 | { | ||||||||||||||
3434 | const SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode(); | ||||||||||||||
3435 | if ( !pTNd ) | ||||||||||||||
3436 | return; | ||||||||||||||
3437 | |||||||||||||||
3438 | const OUString& rText = pTNd->GetText(); | ||||||||||||||
3439 | sal_Int32 nIdx = 0; | ||||||||||||||
3440 | while (nIdx < rText.getLength()) | ||||||||||||||
3441 | { | ||||||||||||||
3442 | sal_Unicode const cCh = rText[nIdx]; | ||||||||||||||
3443 | if (('\t' != cCh) && (' ' != cCh)) | ||||||||||||||
3444 | { | ||||||||||||||
3445 | break; | ||||||||||||||
3446 | } | ||||||||||||||
3447 | ++nIdx; | ||||||||||||||
3448 | } | ||||||||||||||
3449 | |||||||||||||||
3450 | if ( nIdx > 0 ) | ||||||||||||||
3451 | { | ||||||||||||||
3452 | SwPaM aPam(rPos); | ||||||||||||||
3453 | aPam.GetPoint()->nContent = 0; | ||||||||||||||
3454 | aPam.SetMark(); | ||||||||||||||
3455 | aPam.GetMark()->nContent = nIdx; | ||||||||||||||
3456 | DeleteRange( aPam ); | ||||||||||||||
3457 | } | ||||||||||||||
3458 | } | ||||||||||||||
3459 | |||||||||||||||
3460 | // Copy method from SwDoc - "copy Flys in Flys" | ||||||||||||||
3461 | /// note: rRg/rInsPos *exclude* a partially selected start text node; | ||||||||||||||
3462 | /// pCopiedPaM *includes* a partially selected start text node | ||||||||||||||
3463 | void DocumentContentOperationsManager::CopyWithFlyInFly( | ||||||||||||||
3464 | const SwNodeRange& rRg, | ||||||||||||||
3465 | const SwNodeIndex& rInsPos, | ||||||||||||||
3466 | const std::pair<const SwPaM&, const SwPosition&>* pCopiedPaM /*and real insert pos*/, | ||||||||||||||
3467 | const bool bMakeNewFrames, | ||||||||||||||
3468 | const bool bDelRedlines, | ||||||||||||||
3469 | const bool bCopyFlyAtFly, | ||||||||||||||
3470 | SwCopyFlags const flags) const | ||||||||||||||
3471 | { | ||||||||||||||
3472 | assert(!pCopiedPaM || pCopiedPaM->first.End()->nNode == rRg.aEnd)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->first .End()->nNode == rRg.aEnd) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->first.End()->nNode == rRg.aEnd" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3472, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3473 | assert(!pCopiedPaM || pCopiedPaM->second.nNode <= rInsPos)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->second .nNode <= rInsPos) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->second.nNode <= rInsPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3473, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3474 | |||||||||||||||
3475 | SwDoc& rDest = rInsPos.GetNode().GetDoc(); | ||||||||||||||
3476 | SwNodeIndex aSavePos( rInsPos ); | ||||||||||||||
3477 | |||||||||||||||
3478 | if (rRg.aStart != rRg.aEnd) | ||||||||||||||
3479 | { | ||||||||||||||
3480 | bool bEndIsEqualEndPos = rInsPos == rRg.aEnd; | ||||||||||||||
3481 | bool isRecreateEndNode(false); | ||||||||||||||
3482 | --aSavePos; | ||||||||||||||
3483 | SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 ); | ||||||||||||||
3484 | |||||||||||||||
3485 | // insert behind the already copied start node | ||||||||||||||
3486 | m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true ); | ||||||||||||||
3487 | aRedlRest.Restore(); | ||||||||||||||
3488 | if (bMakeNewFrames) // tdf#130685 only after aRedlRest | ||||||||||||||
3489 | { // recreate from previous node (could be merged now) | ||||||||||||||
3490 | if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode()) | ||||||||||||||
3491 | { | ||||||||||||||
3492 | o3tl::sorted_vector<SwTextFrame*> frames; | ||||||||||||||
3493 | SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode(); | ||||||||||||||
3494 | if (pEndNode) | ||||||||||||||
3495 | { | ||||||||||||||
3496 | SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode); | ||||||||||||||
3497 | for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next()) | ||||||||||||||
3498 | { | ||||||||||||||
3499 | if (pFrame->getRootFrame()->IsHideRedlines()) | ||||||||||||||
3500 | { | ||||||||||||||
3501 | frames.insert(pFrame); | ||||||||||||||
3502 | } | ||||||||||||||
3503 | } | ||||||||||||||
3504 | } | ||||||||||||||
3505 | sw::RecreateStartTextFrames(*pNode); | ||||||||||||||
3506 | if (!frames.empty()) | ||||||||||||||
3507 | { // tdf#132187 check if the end node needs new frames | ||||||||||||||
3508 | SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode); | ||||||||||||||
3509 | for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next()) | ||||||||||||||
3510 | { | ||||||||||||||
3511 | if (pFrame->getRootFrame()->IsHideRedlines()) | ||||||||||||||
3512 | { | ||||||||||||||
3513 | auto const it = frames.find(pFrame); | ||||||||||||||
3514 | if (it != frames.end()) | ||||||||||||||
3515 | { | ||||||||||||||
3516 | frames.erase(it); | ||||||||||||||
3517 | } | ||||||||||||||
3518 | } | ||||||||||||||
3519 | } | ||||||||||||||
3520 | if (!frames.empty()) // existing frame was deleted | ||||||||||||||
3521 | { // all layouts because MakeFrames recreates all layouts | ||||||||||||||
3522 | pEndNode->DelFrames(nullptr); | ||||||||||||||
3523 | isRecreateEndNode = true; | ||||||||||||||
3524 | } | ||||||||||||||
3525 | } | ||||||||||||||
3526 | } | ||||||||||||||
3527 | } | ||||||||||||||
3528 | bool const isAtStartOfSection(aSavePos.GetNode().IsStartNode()); | ||||||||||||||
3529 | ++aSavePos; | ||||||||||||||
3530 | if (bMakeNewFrames) | ||||||||||||||
3531 | { | ||||||||||||||
3532 | // it's possible that CheckParaRedlineMerge() deleted frames | ||||||||||||||
3533 | // on rInsPos so have to include it, but it must not be included | ||||||||||||||
3534 | // if it was the first node in the document so that MakeFrames() | ||||||||||||||
3535 | // will find the existing (wasn't deleted) frame on it | ||||||||||||||
3536 | SwNodeIndex const end(rInsPos, | ||||||||||||||
3537 | (!isRecreateEndNode || isAtStartOfSection) | ||||||||||||||
3538 | ? 0 : +1); | ||||||||||||||
3539 | ::MakeFrames(&rDest, aSavePos, end); | ||||||||||||||
3540 | } | ||||||||||||||
3541 | if (bEndIsEqualEndPos) | ||||||||||||||
3542 | { | ||||||||||||||
3543 | const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos; | ||||||||||||||
3544 | } | ||||||||||||||
3545 | } | ||||||||||||||
3546 | |||||||||||||||
3547 | #if OSL_DEBUG_LEVEL1 > 0 | ||||||||||||||
3548 | { | ||||||||||||||
3549 | //JP 17.06.99: Bug 66973 - check count only if the selection is in | ||||||||||||||
3550 | // the same section or there's no section, because sections that are | ||||||||||||||
3551 | // not fully selected are not copied. | ||||||||||||||
3552 | const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode(); | ||||||||||||||
3553 | SwNodeIndex aTmpI( rRg.aEnd, -1 ); | ||||||||||||||
3554 | const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode(); | ||||||||||||||
3555 | if( pSSectNd == pESectNd && | ||||||||||||||
3556 | !rRg.aStart.GetNode().IsSectionNode() && | ||||||||||||||
3557 | !aTmpI.GetNode().IsEndNode() ) | ||||||||||||||
3558 | { | ||||||||||||||
3559 | // If the range starts with a SwStartNode, it isn't copied | ||||||||||||||
3560 | sal_uInt16 offset = (rRg.aStart.GetNode().GetNodeType() != SwNodeType::Start) ? 1 : 0; | ||||||||||||||
3561 | OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() ==do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex () == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3563" ": "), "%s", "An insufficient number of nodes were copied!" ); } } while (false) | ||||||||||||||
3562 | rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset,do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex () == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3563" ": "), "%s", "An insufficient number of nodes were copied!" ); } } while (false) | ||||||||||||||
3563 | "An insufficient number of nodes were copied!" )do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex () == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3563" ": "), "%s", "An insufficient number of nodes were copied!" ); } } while (false); | ||||||||||||||
3564 | } | ||||||||||||||
3565 | } | ||||||||||||||
3566 | #endif | ||||||||||||||
3567 | |||||||||||||||
3568 | { | ||||||||||||||
3569 | ::sw::UndoGuard const undoGuard(rDest.GetIDocumentUndoRedo()); | ||||||||||||||
3570 | CopyFlyInFlyImpl(rRg, pCopiedPaM ? &pCopiedPaM->first : nullptr, | ||||||||||||||
3571 | // see comment below regarding use of pCopiedPaM->second | ||||||||||||||
3572 | (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode) | ||||||||||||||
3573 | ? pCopiedPaM->second.nNode | ||||||||||||||
3574 | : aSavePos, | ||||||||||||||
3575 | bCopyFlyAtFly, | ||||||||||||||
3576 | flags); | ||||||||||||||
3577 | } | ||||||||||||||
3578 | |||||||||||||||
3579 | SwNodeRange aCpyRange( aSavePos, rInsPos ); | ||||||||||||||
3580 | |||||||||||||||
3581 | // Also copy all bookmarks | ||||||||||||||
3582 | // guess this must be done before the DelDummyNodes below as that | ||||||||||||||
3583 | // deletes nodes so would mess up the index arithmetic | ||||||||||||||
3584 | if( m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() ) | ||||||||||||||
3585 | { | ||||||||||||||
3586 | SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); | ||||||||||||||
3587 | SwPaM aCpyPaM(aCpyRange.aStart, aCpyRange.aEnd); | ||||||||||||||
3588 | if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode) | ||||||||||||||
3589 | { | ||||||||||||||
3590 | // there is 1 (partially selected, maybe) paragraph before | ||||||||||||||
3591 | assert(SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode)(static_cast <bool> (SwNodeIndex(rRg.aStart, -1) == pCopiedPaM ->first.Start()->nNode) ? void (0) : __assert_fail ("SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3591, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3592 | // only use the passed in target SwPosition if the source PaM point | ||||||||||||||
3593 | // is on a different node; if it was the same node then the target | ||||||||||||||
3594 | // position was likely moved along by the copy operation and now | ||||||||||||||
3595 | // points to the end of the range! | ||||||||||||||
3596 | *aCpyPaM.GetPoint() = pCopiedPaM->second; | ||||||||||||||
3597 | } | ||||||||||||||
3598 | |||||||||||||||
3599 | sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, *aCpyPaM.Start()); | ||||||||||||||
3600 | } | ||||||||||||||
3601 | |||||||||||||||
3602 | if( bDelRedlines && ( RedlineFlags::DeleteRedlines & rDest.getIDocumentRedlineAccess().GetRedlineFlags() )) | ||||||||||||||
3603 | lcl_DeleteRedlines( rRg, aCpyRange ); | ||||||||||||||
3604 | |||||||||||||||
3605 | rDest.GetNodes().DelDummyNodes( aCpyRange ); | ||||||||||||||
3606 | } | ||||||||||||||
3607 | |||||||||||||||
3608 | // note: for the redline Show/Hide this must be in sync with | ||||||||||||||
3609 | // SwRangeRedline::CopyToSection()/DelCopyOfSection()/MoveFromSection() | ||||||||||||||
3610 | void DocumentContentOperationsManager::CopyFlyInFlyImpl( | ||||||||||||||
3611 | const SwNodeRange& rRg, | ||||||||||||||
3612 | SwPaM const*const pCopiedPaM, | ||||||||||||||
3613 | const SwNodeIndex& rStartIdx, | ||||||||||||||
3614 | const bool bCopyFlyAtFly, | ||||||||||||||
3615 | SwCopyFlags const flags) const | ||||||||||||||
3616 | { | ||||||||||||||
3617 | assert(!pCopiedPaM || pCopiedPaM->End()->nNode == rRg.aEnd)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->End( )->nNode == rRg.aEnd) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->End()->nNode == rRg.aEnd" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3617, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3618 | |||||||||||||||
3619 | // First collect all Flys, sort them according to their ordering number, | ||||||||||||||
3620 | // and then only copy them. This maintains the ordering numbers (which are only | ||||||||||||||
3621 | // managed in the DrawModel). | ||||||||||||||
3622 | SwDoc& rDest = rStartIdx.GetNode().GetDoc(); | ||||||||||||||
3623 | std::set< ZSortFly > aSet; | ||||||||||||||
3624 | const size_t nArrLen = m_rDoc.GetSpzFrameFormats()->size(); | ||||||||||||||
3625 | |||||||||||||||
3626 | SwTextBoxHelper::SavedLink aOldTextBoxes; | ||||||||||||||
3627 | SwTextBoxHelper::saveLinks(*m_rDoc.GetSpzFrameFormats(), aOldTextBoxes); | ||||||||||||||
3628 | |||||||||||||||
3629 | for ( size_t n = 0; n < nArrLen; ++n ) | ||||||||||||||
3630 | { | ||||||||||||||
3631 | SwFrameFormat* pFormat = (*m_rDoc.GetSpzFrameFormats())[n]; | ||||||||||||||
3632 | SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor(); | ||||||||||||||
3633 | SwPosition const*const pAPos = pAnchor->GetContentAnchor(); | ||||||||||||||
3634 | if ( !pAPos ) | ||||||||||||||
3635 | continue; | ||||||||||||||
3636 | bool bAdd = false; | ||||||||||||||
3637 | sal_uLong nSkipAfter = pAPos->nNode.GetIndex(); | ||||||||||||||
3638 | sal_uLong nStart = rRg.aStart.GetIndex(); | ||||||||||||||
3639 | switch ( pAnchor->GetAnchorId() ) | ||||||||||||||
3640 | { | ||||||||||||||
3641 | case RndStdIds::FLY_AT_FLY: | ||||||||||||||
3642 | if(bCopyFlyAtFly) | ||||||||||||||
3643 | ++nSkipAfter; | ||||||||||||||
3644 | else if(m_rDoc.getIDocumentRedlineAccess().IsRedlineMove()) | ||||||||||||||
3645 | ++nStart; | ||||||||||||||
3646 | break; | ||||||||||||||
3647 | case RndStdIds::FLY_AT_PARA: | ||||||||||||||
3648 | { | ||||||||||||||
3649 | bAdd = IsSelectFrameAnchoredAtPara(*pAPos, | ||||||||||||||
3650 | pCopiedPaM ? *pCopiedPaM->Start() : SwPosition(rRg.aStart), | ||||||||||||||
3651 | pCopiedPaM ? *pCopiedPaM->End() : SwPosition(rRg.aEnd), | ||||||||||||||
3652 | (flags & SwCopyFlags::IsMoveToFly) | ||||||||||||||
3653 | ? DelContentType::AllMask|DelContentType::WriterfilterHack | ||||||||||||||
3654 | : DelContentType::AllMask); | ||||||||||||||
3655 | } | ||||||||||||||
3656 | break; | ||||||||||||||
3657 | case RndStdIds::FLY_AT_CHAR: | ||||||||||||||
3658 | { | ||||||||||||||
3659 | bAdd = IsDestroyFrameAnchoredAtChar(*pAPos, | ||||||||||||||
3660 | pCopiedPaM ? *pCopiedPaM->Start() : SwPosition(rRg.aStart), | ||||||||||||||
3661 | pCopiedPaM ? *pCopiedPaM->End() : SwPosition(rRg.aEnd), | ||||||||||||||
3662 | (flags & SwCopyFlags::IsMoveToFly) | ||||||||||||||
3663 | ? DelContentType::AllMask|DelContentType::WriterfilterHack | ||||||||||||||
3664 | : DelContentType::AllMask); | ||||||||||||||
3665 | } | ||||||||||||||
3666 | break; | ||||||||||||||
3667 | default: | ||||||||||||||
3668 | continue; | ||||||||||||||
3669 | } | ||||||||||||||
3670 | if (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId()) | ||||||||||||||
3671 | { | ||||||||||||||
3672 | if (nStart > nSkipAfter) | ||||||||||||||
3673 | continue; | ||||||||||||||
3674 | if (pAPos->nNode > rRg.aEnd) | ||||||||||||||
3675 | continue; | ||||||||||||||
3676 | //frames at the last source node are not always copied: | ||||||||||||||
3677 | //- if the node is empty and is the last node of the document or a table cell | ||||||||||||||
3678 | // or a text frame then they have to be copied | ||||||||||||||
3679 | //- if the content index in this node is > 0 then paragraph and frame bound objects are copied | ||||||||||||||
3680 | //- to-character bound objects are copied if their index is <= nEndContentIndex | ||||||||||||||
3681 | if (pAPos->nNode < rRg.aEnd) | ||||||||||||||
3682 | bAdd = true; | ||||||||||||||
3683 | if (!bAdd && !m_rDoc.getIDocumentRedlineAccess().IsRedlineMove()) // fdo#40599: not for redline move | ||||||||||||||
3684 | { | ||||||||||||||
3685 | if (!bAdd) | ||||||||||||||
3686 | { | ||||||||||||||
3687 | // technically old code checked nContent of AT_FLY which is pointless | ||||||||||||||
3688 | bAdd = pCopiedPaM && 0 < pCopiedPaM->End()->nContent.GetIndex(); | ||||||||||||||
3689 | } | ||||||||||||||
3690 | } | ||||||||||||||
3691 | } | ||||||||||||||
3692 | if( bAdd ) | ||||||||||||||
3693 | { | ||||||||||||||
3694 | aSet.insert( ZSortFly( pFormat, pAnchor, nArrLen + aSet.size() )); | ||||||||||||||
3695 | } | ||||||||||||||
3696 | } | ||||||||||||||
3697 | |||||||||||||||
3698 | // Store all copied (and also the newly created) frames in another array. | ||||||||||||||
3699 | // They are stored as matching the originals, so that we will be later | ||||||||||||||
3700 | // able to build the chains accordingly. | ||||||||||||||
3701 | std::vector< SwFrameFormat* > aVecSwFrameFormat; | ||||||||||||||
3702 | std::set< ZSortFly >::const_iterator it=aSet.begin(); | ||||||||||||||
3703 | |||||||||||||||
3704 | while (it != aSet.end()) | ||||||||||||||
3705 | { | ||||||||||||||
3706 | // #i59964# | ||||||||||||||
3707 | // correct determination of new anchor position | ||||||||||||||
3708 | SwFormatAnchor aAnchor( *(*it).GetAnchor() ); | ||||||||||||||
3709 | assert( aAnchor.GetContentAnchor() != nullptr )(static_cast <bool> (aAnchor.GetContentAnchor() != nullptr ) ? void (0) : __assert_fail ("aAnchor.GetContentAnchor() != nullptr" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3709, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3710 | SwPosition newPos = *aAnchor.GetContentAnchor(); | ||||||||||||||
3711 | // for at-paragraph and at-character anchored objects the new anchor | ||||||||||||||
3712 | // position can *not* be determined by the difference of the current | ||||||||||||||
3713 | // anchor position to the start of the copied range, because not | ||||||||||||||
3714 | // complete selected sections in the copied range aren't copied - see | ||||||||||||||
3715 | // method <SwNodes::CopyNodes(..)>. | ||||||||||||||
3716 | // Thus, the new anchor position in the destination document is found | ||||||||||||||
3717 | // by counting the text nodes. | ||||||||||||||
3718 | if ((aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) || | ||||||||||||||
3719 | (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR) ) | ||||||||||||||
3720 | { | ||||||||||||||
3721 | // First, determine number of anchor text node in the copied range. | ||||||||||||||
3722 | // Note: The anchor text node *have* to be inside the copied range. | ||||||||||||||
3723 | sal_uLong nAnchorTextNdNumInRange( 0 ); | ||||||||||||||
3724 | bool bAnchorTextNdFound( false ); | ||||||||||||||
3725 | // start at the first node for which flys are copied | ||||||||||||||
3726 | SwNodeIndex aIdx(pCopiedPaM ? pCopiedPaM->Start()->nNode : rRg.aStart); | ||||||||||||||
3727 | while ( !bAnchorTextNdFound && aIdx <= rRg.aEnd ) | ||||||||||||||
3728 | { | ||||||||||||||
3729 | if ( aIdx.GetNode().IsTextNode() ) | ||||||||||||||
3730 | { | ||||||||||||||
3731 | ++nAnchorTextNdNumInRange; | ||||||||||||||
3732 | bAnchorTextNdFound = aAnchor.GetContentAnchor()->nNode == aIdx; | ||||||||||||||
3733 | } | ||||||||||||||
3734 | |||||||||||||||
3735 | ++aIdx; | ||||||||||||||
3736 | } | ||||||||||||||
3737 | |||||||||||||||
3738 | if ( !bAnchorTextNdFound ) | ||||||||||||||
3739 | { | ||||||||||||||
3740 | // This case can *not* happen, but to be robust take the first | ||||||||||||||
3741 | // text node in the destination document. | ||||||||||||||
3742 | OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" )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" ":" "3742" ": "), "%s", "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" ); } } while (false); | ||||||||||||||
3743 | nAnchorTextNdNumInRange = 1; | ||||||||||||||
3744 | } | ||||||||||||||
3745 | // Second, search corresponding text node in destination document | ||||||||||||||
3746 | // by counting forward from start insert position <rStartIdx> the | ||||||||||||||
3747 | // determined number of text nodes. | ||||||||||||||
3748 | aIdx = rStartIdx; | ||||||||||||||
3749 | SwNodeIndex aAnchorNdIdx( rStartIdx ); | ||||||||||||||
3750 | const SwNode& aEndOfContentNd = | ||||||||||||||
3751 | aIdx.GetNode().GetNodes().GetEndOfContent(); | ||||||||||||||
3752 | while ( nAnchorTextNdNumInRange > 0 && | ||||||||||||||
3753 | &(aIdx.GetNode()) != &aEndOfContentNd ) | ||||||||||||||
3754 | { | ||||||||||||||
3755 | if ( aIdx.GetNode().IsTextNode() ) | ||||||||||||||
3756 | { | ||||||||||||||
3757 | --nAnchorTextNdNumInRange; | ||||||||||||||
3758 | aAnchorNdIdx = aIdx; | ||||||||||||||
3759 | } | ||||||||||||||
3760 | |||||||||||||||
3761 | ++aIdx; | ||||||||||||||
3762 | } | ||||||||||||||
3763 | if ( !aAnchorNdIdx.GetNode().IsTextNode() ) | ||||||||||||||
3764 | { | ||||||||||||||
3765 | // This case can *not* happen, but to be robust take the first | ||||||||||||||
3766 | // text node in the destination document. | ||||||||||||||
3767 | OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" )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" ":" "3767" ": "), "%s", "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" ); } } while (false); | ||||||||||||||
3768 | aAnchorNdIdx = rStartIdx; | ||||||||||||||
3769 | while ( !aAnchorNdIdx.GetNode().IsTextNode() ) | ||||||||||||||
3770 | { | ||||||||||||||
3771 | ++aAnchorNdIdx; | ||||||||||||||
3772 | } | ||||||||||||||
3773 | } | ||||||||||||||
3774 | // apply found anchor text node as new anchor position | ||||||||||||||
3775 | newPos.nNode = aAnchorNdIdx; | ||||||||||||||
3776 | } | ||||||||||||||
3777 | else | ||||||||||||||
3778 | { | ||||||||||||||
3779 | long nOffset = newPos.nNode.GetIndex() - rRg.aStart.GetIndex(); | ||||||||||||||
3780 | SwNodeIndex aIdx( rStartIdx, nOffset ); | ||||||||||||||
3781 | newPos.nNode = aIdx; | ||||||||||||||
3782 | } | ||||||||||||||
3783 | // Set the character bound Flys back at the original character | ||||||||||||||
3784 | if ((RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) && | ||||||||||||||
3785 | newPos.nNode.GetNode().IsTextNode() ) | ||||||||||||||
3786 | { | ||||||||||||||
3787 | // only if pCopiedPaM: care about partially selected start node | ||||||||||||||
3788 | sal_Int32 const nContent = pCopiedPaM && pCopiedPaM->Start()->nNode == aAnchor.GetContentAnchor()->nNode | ||||||||||||||
3789 | ? newPos.nContent.GetIndex() - pCopiedPaM->Start()->nContent.GetIndex() | ||||||||||||||
3790 | : newPos.nContent.GetIndex(); | ||||||||||||||
3791 | newPos.nContent.Assign(newPos.nNode.GetNode().GetTextNode(), nContent); | ||||||||||||||
3792 | } | ||||||||||||||
3793 | else | ||||||||||||||
3794 | { | ||||||||||||||
3795 | newPos.nContent.Assign( nullptr, 0 ); | ||||||||||||||
3796 | } | ||||||||||||||
3797 | aAnchor.SetAnchor( &newPos ); | ||||||||||||||
3798 | |||||||||||||||
3799 | // Check recursion: if copying content inside the same frame, then don't copy the format. | ||||||||||||||
3800 | if( &rDest == &m_rDoc ) | ||||||||||||||
3801 | { | ||||||||||||||
3802 | const SwFormatContent& rContent = (*it).GetFormat()->GetContent(); | ||||||||||||||
3803 | const SwStartNode* pSNd; | ||||||||||||||
3804 | if( rContent.GetContentIdx() && | ||||||||||||||
3805 | nullptr != ( pSNd = rContent.GetContentIdx()->GetNode().GetStartNode() ) && | ||||||||||||||
3806 | pSNd->GetIndex() < rStartIdx.GetIndex() && | ||||||||||||||
3807 | rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() ) | ||||||||||||||
3808 | { | ||||||||||||||
3809 | it = aSet.erase(it); | ||||||||||||||
3810 | continue; | ||||||||||||||
3811 | } | ||||||||||||||
3812 | } | ||||||||||||||
3813 | |||||||||||||||
3814 | // Ignore TextBoxes, they are already handled in | ||||||||||||||
3815 | // sw::DocumentLayoutManager::CopyLayoutFormat(). | ||||||||||||||
3816 | if (SwTextBoxHelper::isTextBox(it->GetFormat(), RES_FLYFRMFMT)) | ||||||||||||||
3817 | { | ||||||||||||||
3818 | it = aSet.erase(it); | ||||||||||||||
3819 | continue; | ||||||||||||||
3820 | } | ||||||||||||||
3821 | |||||||||||||||
3822 | // Copy the format and set the new anchor | ||||||||||||||
3823 | aVecSwFrameFormat.push_back( rDest.getIDocumentLayoutAccess().CopyLayoutFormat( *(*it).GetFormat(), | ||||||||||||||
3824 | aAnchor, false, true ) ); | ||||||||||||||
3825 | ++it; | ||||||||||||||
3826 | } | ||||||||||||||
3827 | |||||||||||||||
3828 | // Rebuild as much as possible of all chains that are available in the original, | ||||||||||||||
3829 | OSL_ENSURE( aSet.size() == aVecSwFrameFormat.size(), "Missing new Flys" )do { if (true && (!(aSet.size() == aVecSwFrameFormat. size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3829" ": "), "%s", "Missing new Flys"); } } while (false ); | ||||||||||||||
3830 | if ( aSet.size() != aVecSwFrameFormat.size() ) | ||||||||||||||
3831 | return; | ||||||||||||||
3832 | |||||||||||||||
3833 | size_t n = 0; | ||||||||||||||
3834 | for (const auto& rFlyN : aSet) | ||||||||||||||
3835 | { | ||||||||||||||
3836 | const SwFrameFormat *pFormatN = rFlyN.GetFormat(); | ||||||||||||||
3837 | const SwFormatChain &rChain = pFormatN->GetChain(); | ||||||||||||||
3838 | int nCnt = int(nullptr != rChain.GetPrev()); | ||||||||||||||
3839 | nCnt += rChain.GetNext() ? 1: 0; | ||||||||||||||
3840 | size_t k = 0; | ||||||||||||||
3841 | for (const auto& rFlyK : aSet) | ||||||||||||||
3842 | { | ||||||||||||||
3843 | const SwFrameFormat *pFormatK = rFlyK.GetFormat(); | ||||||||||||||
3844 | if ( rChain.GetPrev() == pFormatK ) | ||||||||||||||
3845 | { | ||||||||||||||
3846 | ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]), | ||||||||||||||
3847 | static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]) ); | ||||||||||||||
3848 | --nCnt; | ||||||||||||||
3849 | } | ||||||||||||||
3850 | else if ( rChain.GetNext() == pFormatK ) | ||||||||||||||
3851 | { | ||||||||||||||
3852 | ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]), | ||||||||||||||
3853 | static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]) ); | ||||||||||||||
3854 | --nCnt; | ||||||||||||||
3855 | } | ||||||||||||||
3856 | ++k; | ||||||||||||||
3857 | } | ||||||||||||||
3858 | ++n; | ||||||||||||||
3859 | } | ||||||||||||||
3860 | |||||||||||||||
3861 | // Re-create content property of draw formats, knowing how old shapes | ||||||||||||||
3862 | // were paired with old fly formats (aOldTextBoxes) and that aSet is | ||||||||||||||
3863 | // parallel with aVecSwFrameFormat. | ||||||||||||||
3864 | SwTextBoxHelper::restoreLinks(aSet, aVecSwFrameFormat, aOldTextBoxes); | ||||||||||||||
3865 | } | ||||||||||||||
3866 | |||||||||||||||
3867 | /* | ||||||||||||||
3868 | * Reset the text's hard formatting | ||||||||||||||
3869 | */ | ||||||||||||||
3870 | /** @params pArgs contains the document's ChrFormatTable | ||||||||||||||
3871 | * Is need for selections at the beginning/end and with no SSelection. | ||||||||||||||
3872 | */ | ||||||||||||||
3873 | bool DocumentContentOperationsManager::lcl_RstTextAttr( const SwNodePtr& rpNd, void* pArgs ) | ||||||||||||||
3874 | { | ||||||||||||||
3875 | ParaRstFormat* pPara = static_cast<ParaRstFormat*>(pArgs); | ||||||||||||||
3876 | if (pPara->pLayout && pPara->pLayout->IsHideRedlines() | ||||||||||||||
3877 | && rpNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden) | ||||||||||||||
3878 | { | ||||||||||||||
3879 | return true; // skip hidden, since new items aren't applied | ||||||||||||||
3880 | } | ||||||||||||||
3881 | SwTextNode * pTextNode = rpNd->GetTextNode(); | ||||||||||||||
3882 | if( pTextNode && pTextNode->GetpSwpHints() ) | ||||||||||||||
3883 | { | ||||||||||||||
3884 | SwIndex aSt( pTextNode, 0 ); | ||||||||||||||
3885 | sal_Int32 nEnd = pTextNode->Len(); | ||||||||||||||
3886 | |||||||||||||||
3887 | if( &pPara->pSttNd->nNode.GetNode() == pTextNode && | ||||||||||||||
3888 | pPara->pSttNd->nContent.GetIndex() ) | ||||||||||||||
3889 | aSt = pPara->pSttNd->nContent.GetIndex(); | ||||||||||||||
3890 | |||||||||||||||
3891 | if( &pPara->pEndNd->nNode.GetNode() == rpNd ) | ||||||||||||||
3892 | nEnd = pPara->pEndNd->nContent.GetIndex(); | ||||||||||||||
3893 | |||||||||||||||
3894 | if( pPara->pHistory ) | ||||||||||||||
3895 | { | ||||||||||||||
3896 | // Save all attributes for the Undo. | ||||||||||||||
3897 | SwRegHistory aRHst( *pTextNode, pPara->pHistory ); | ||||||||||||||
3898 | pTextNode->GetpSwpHints()->Register( &aRHst ); | ||||||||||||||
3899 | pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich, | ||||||||||||||
3900 | pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange ); | ||||||||||||||
3901 | if( pTextNode->GetpSwpHints() ) | ||||||||||||||
3902 | pTextNode->GetpSwpHints()->DeRegister(); | ||||||||||||||
3903 | } | ||||||||||||||
3904 | else | ||||||||||||||
3905 | pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich, | ||||||||||||||
3906 | pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange ); | ||||||||||||||
3907 | } | ||||||||||||||
3908 | return true; | ||||||||||||||
3909 | } | ||||||||||||||
3910 | |||||||||||||||
3911 | DocumentContentOperationsManager::~DocumentContentOperationsManager() | ||||||||||||||
3912 | { | ||||||||||||||
3913 | } | ||||||||||||||
3914 | //Private methods | ||||||||||||||
3915 | |||||||||||||||
3916 | bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool ) | ||||||||||||||
3917 | { | ||||||||||||||
3918 | assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())(static_cast <bool> (m_rDoc.getIDocumentRedlineAccess() .IsRedlineOn()) ? void (0) : __assert_fail ("m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3918, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3919 | |||||||||||||||
3920 | RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | ||||||||||||||
3921 | |||||||||||||||
3922 | if (*rPam.GetPoint() == *rPam.GetMark()) | ||||||||||||||
3923 | { | ||||||||||||||
3924 | return false; // do not add empty redlines | ||||||||||||||
3925 | } | ||||||||||||||
3926 | |||||||||||||||
3927 | std::vector<SwRangeRedline*> redlines; | ||||||||||||||
3928 | { | ||||||||||||||
3929 | auto pRedline(std::make_unique<SwRangeRedline>(RedlineType::Delete, rPam)); | ||||||||||||||
3930 | if (pRedline->HasValidRange()) | ||||||||||||||
3931 | { | ||||||||||||||
3932 | redlines.push_back(pRedline.release()); | ||||||||||||||
3933 | } | ||||||||||||||
3934 | else // sigh ... why is such a selection even possible... | ||||||||||||||
3935 | { // split it up so we get one SwUndoRedlineDelete per inserted RL | ||||||||||||||
3936 | redlines = GetAllValidRanges(std::move(pRedline)); | ||||||||||||||
3937 | } | ||||||||||||||
3938 | } | ||||||||||||||
3939 | |||||||||||||||
3940 | if (redlines.empty()) | ||||||||||||||
3941 | { | ||||||||||||||
3942 | return false; | ||||||||||||||
3943 | } | ||||||||||||||
3944 | |||||||||||||||
3945 | // tdf#54819 current redlining needs also modification of paragraph style and | ||||||||||||||
3946 | // attributes added to the same grouped Undo | ||||||||||||||
3947 | if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | ||||||||||||||
3948 | m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); | ||||||||||||||
3949 | |||||||||||||||
3950 | auto & rDMA(*m_rDoc.getIDocumentMarkAccess()); | ||||||||||||||
3951 | std::vector<std::unique_ptr<SwUndo>> MarkUndos; | ||||||||||||||
3952 | for (auto iter = rDMA.getAnnotationMarksBegin(); | ||||||||||||||
3953 | iter != rDMA.getAnnotationMarksEnd(); ) | ||||||||||||||
3954 | { | ||||||||||||||
3955 | // tdf#111524 remove annotation marks that have their field | ||||||||||||||
3956 | // characters deleted | ||||||||||||||
3957 | SwPosition const& rEndPos((**iter).GetMarkEnd()); | ||||||||||||||
3958 | if (*rPam.Start() < rEndPos && rEndPos <= *rPam.End()) | ||||||||||||||
3959 | { | ||||||||||||||
3960 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3961 | { | ||||||||||||||
3962 | MarkUndos.emplace_back(std::make_unique<SwUndoDeleteBookmark>(**iter)); | ||||||||||||||
3963 | } | ||||||||||||||
3964 | // iter is into annotation mark vector so must be dereferenced! | ||||||||||||||
3965 | rDMA.deleteMark(&**iter); | ||||||||||||||
3966 | // this invalidates iter, have to start over... | ||||||||||||||
3967 | iter = rDMA.getAnnotationMarksBegin(); | ||||||||||||||
3968 | } | ||||||||||||||
3969 | else | ||||||||||||||
3970 | { // marks are sorted by start | ||||||||||||||
3971 | if (*rPam.End() < (**iter).GetMarkStart()) | ||||||||||||||
3972 | { | ||||||||||||||
3973 | break; | ||||||||||||||
3974 | } | ||||||||||||||
3975 | ++iter; | ||||||||||||||
3976 | } | ||||||||||||||
3977 | } | ||||||||||||||
3978 | |||||||||||||||
3979 | // tdf#119019 accept tracked paragraph formatting to do not hide new deletions | ||||||||||||||
3980 | if (*rPam.GetPoint() != *rPam.GetMark()) | ||||||||||||||
3981 | m_rDoc.getIDocumentRedlineAccess().AcceptRedlineParagraphFormatting(rPam); | ||||||||||||||
3982 | |||||||||||||||
3983 | std::vector<std::unique_ptr<SwUndoRedlineDelete>> undos; | ||||||||||||||
3984 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
3985 | { | ||||||||||||||
3986 | // this should no longer happen in calls from the UI but maybe via API | ||||||||||||||
3987 | // (randomTest and testTdf54819 triggers it) | ||||||||||||||
3988 | SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,do { if (true && ((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask)) { 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() << "redlines will be moved in DeleteAndJoin" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in DeleteAndJoin" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in DeleteAndJoin"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "redlines will be moved in DeleteAndJoin") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core") , ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in DeleteAndJoin" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in DeleteAndJoin"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||||||||||||
3989 | "sw.core", "redlines will be moved in DeleteAndJoin")do { if (true && ((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask)) { 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() << "redlines will be moved in DeleteAndJoin" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in DeleteAndJoin" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in DeleteAndJoin"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "redlines will be moved in DeleteAndJoin") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core") , ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in DeleteAndJoin" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in DeleteAndJoin"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "3989" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||||||||||||
3990 | m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( | ||||||||||||||
3991 | RedlineFlags::On | RedlineFlags::ShowInsert | RedlineFlags::ShowDelete); | ||||||||||||||
3992 | for (SwRangeRedline * pRedline : redlines) | ||||||||||||||
3993 | { | ||||||||||||||
3994 | assert(pRedline->HasValidRange())(static_cast <bool> (pRedline->HasValidRange()) ? void (0) : __assert_fail ("pRedline->HasValidRange()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 3994, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
3995 | undos.emplace_back(std::make_unique<SwUndoRedlineDelete>( | ||||||||||||||
3996 | *pRedline, SwUndoId::DELETE)); | ||||||||||||||
3997 | } | ||||||||||||||
3998 | const SwRewriter aRewriter = undos.front()->GetRewriter(); | ||||||||||||||
3999 | // can only group a single undo action | ||||||||||||||
4000 | if (MarkUndos.empty() && undos.size() == 1 | ||||||||||||||
4001 | && m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | ||||||||||||||
4002 | { | ||||||||||||||
4003 | SwUndo * const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() ); | ||||||||||||||
4004 | SwUndoRedlineDelete *const pUndoRedlineDel(dynamic_cast<SwUndoRedlineDelete*>(pLastUndo)); | ||||||||||||||
4005 | bool const bMerged = pUndoRedlineDel | ||||||||||||||
4006 | && pUndoRedlineDel->CanGrouping(*undos.front()); | ||||||||||||||
4007 | if (!bMerged) | ||||||||||||||
4008 | { | ||||||||||||||
4009 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(undos.front())); | ||||||||||||||
4010 | } | ||||||||||||||
4011 | undos.clear(); // prevent unmatched EndUndo | ||||||||||||||
4012 | } | ||||||||||||||
4013 | else | ||||||||||||||
4014 | { | ||||||||||||||
4015 | m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE, &aRewriter); | ||||||||||||||
4016 | for (auto& it : MarkUndos) | ||||||||||||||
4017 | { | ||||||||||||||
4018 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it)); | ||||||||||||||
4019 | } | ||||||||||||||
4020 | for (auto & it : undos) | ||||||||||||||
4021 | { | ||||||||||||||
4022 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it)); | ||||||||||||||
4023 | } | ||||||||||||||
4024 | } | ||||||||||||||
4025 | } | ||||||||||||||
4026 | |||||||||||||||
4027 | for (SwRangeRedline *const pRedline : redlines) | ||||||||||||||
4028 | { | ||||||||||||||
4029 | // note: 1. the pRedline can still be merged & deleted | ||||||||||||||
4030 | // 2. the impl. can even DeleteAndJoin the range => no plain PaM | ||||||||||||||
4031 | std::shared_ptr<SwUnoCursor> const pCursor(m_rDoc.CreateUnoCursor(*pRedline->GetMark())); | ||||||||||||||
4032 | pCursor->SetMark(); | ||||||||||||||
4033 | *pCursor->GetPoint() = *pRedline->GetPoint(); | ||||||||||||||
4034 | m_rDoc.getIDocumentRedlineAccess().AppendRedline(pRedline, true); | ||||||||||||||
4035 | // sw_redlinehide: 2 reasons why this is needed: | ||||||||||||||
4036 | // 1. it's the first redline in node => RedlineDelText was sent but ignored | ||||||||||||||
4037 | // 2. redline spans multiple nodes => must merge text frames | ||||||||||||||
4038 | sw::UpdateFramesForAddDeleteRedline(m_rDoc, *pCursor); | ||||||||||||||
4039 | } | ||||||||||||||
4040 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
4041 | |||||||||||||||
4042 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4043 | { | ||||||||||||||
4044 | if (!undos.empty()) | ||||||||||||||
4045 | { | ||||||||||||||
4046 | m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); | ||||||||||||||
4047 | } | ||||||||||||||
4048 | m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld ); | ||||||||||||||
4049 | } | ||||||||||||||
4050 | |||||||||||||||
4051 | if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | ||||||||||||||
4052 | m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); | ||||||||||||||
4053 | |||||||||||||||
4054 | return true; | ||||||||||||||
4055 | } | ||||||||||||||
4056 | |||||||||||||||
4057 | bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam, | ||||||||||||||
4058 | const bool bForceJoinNext ) | ||||||||||||||
4059 | { | ||||||||||||||
4060 | bool bJoinText, bJoinPrev; | ||||||||||||||
4061 | ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev ); | ||||||||||||||
4062 | // #i100466# | ||||||||||||||
4063 | if ( bForceJoinNext ) | ||||||||||||||
4064 | { | ||||||||||||||
4065 | bJoinPrev = false; | ||||||||||||||
4066 | } | ||||||||||||||
4067 | |||||||||||||||
4068 | { | ||||||||||||||
4069 | bool const bSuccess( DeleteRangeImpl( rPam ) ); | ||||||||||||||
4070 | if (!bSuccess) | ||||||||||||||
4071 | return false; | ||||||||||||||
4072 | } | ||||||||||||||
4073 | |||||||||||||||
4074 | if( bJoinText ) | ||||||||||||||
4075 | { | ||||||||||||||
4076 | ::sw_JoinText( rPam, bJoinPrev ); | ||||||||||||||
4077 | } | ||||||||||||||
4078 | |||||||||||||||
4079 | if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() | ||||||||||||||
4080 | && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()) | ||||||||||||||
4081 | { | ||||||||||||||
4082 | m_rDoc.getIDocumentRedlineAccess().CompressRedlines(); | ||||||||||||||
4083 | } | ||||||||||||||
4084 | |||||||||||||||
4085 | return true; | ||||||||||||||
4086 | } | ||||||||||||||
4087 | |||||||||||||||
4088 | bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const bool) | ||||||||||||||
4089 | { | ||||||||||||||
4090 | // Move all cursors out of the deleted range, but first copy the | ||||||||||||||
4091 | // passed PaM, because it could be a cursor that would be moved! | ||||||||||||||
4092 | SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); | ||||||||||||||
4093 | ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() ); | ||||||||||||||
4094 | |||||||||||||||
4095 | bool const bSuccess( DeleteRangeImplImpl( aDelPam ) ); | ||||||||||||||
4096 | if (bSuccess) | ||||||||||||||
4097 | { // now copy position from temp copy to given PaM | ||||||||||||||
4098 | *rPam.GetPoint() = *aDelPam.GetPoint(); | ||||||||||||||
4099 | } | ||||||||||||||
4100 | |||||||||||||||
4101 | return bSuccess; | ||||||||||||||
4102 | } | ||||||||||||||
4103 | |||||||||||||||
4104 | bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam) | ||||||||||||||
4105 | { | ||||||||||||||
4106 | SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); | ||||||||||||||
4107 | |||||||||||||||
4108 | if (!rPam.HasMark() | ||||||||||||||
4109 | || (*pStt == *pEnd && !IsFlySelectedByCursor(m_rDoc, *pStt, *pEnd))) | ||||||||||||||
4110 | { | ||||||||||||||
4111 | return false; | ||||||||||||||
4112 | } | ||||||||||||||
4113 | |||||||||||||||
4114 | if( m_rDoc.GetAutoCorrExceptWord() ) | ||||||||||||||
4115 | { | ||||||||||||||
4116 | // if necessary the saved Word for the exception | ||||||||||||||
4117 | if( m_rDoc.GetAutoCorrExceptWord()->IsDeleted() || pStt->nNode != pEnd->nNode || | ||||||||||||||
4118 | pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() || | ||||||||||||||
4119 | !m_rDoc.GetAutoCorrExceptWord()->CheckDelChar( *pStt )) | ||||||||||||||
4120 | { m_rDoc.DeleteAutoCorrExceptWord(); } | ||||||||||||||
4121 | } | ||||||||||||||
4122 | |||||||||||||||
4123 | { | ||||||||||||||
4124 | // Delete all empty TextHints at the Mark's position | ||||||||||||||
4125 | SwTextNode* pTextNd = rPam.GetMark()->nNode.GetNode().GetTextNode(); | ||||||||||||||
4126 | SwpHints* pHts; | ||||||||||||||
4127 | if( pTextNd && nullptr != ( pHts = pTextNd->GetpSwpHints()) && pHts->Count() ) | ||||||||||||||
4128 | { | ||||||||||||||
4129 | const sal_Int32 nMkCntPos = rPam.GetMark()->nContent.GetIndex(); | ||||||||||||||
4130 | for( size_t n = pHts->Count(); n; ) | ||||||||||||||
4131 | { | ||||||||||||||
4132 | const SwTextAttr* pAttr = pHts->Get( --n ); | ||||||||||||||
4133 | if( nMkCntPos > pAttr->GetStart() ) | ||||||||||||||
4134 | break; | ||||||||||||||
4135 | |||||||||||||||
4136 | const sal_Int32 *pEndIdx; | ||||||||||||||
4137 | if( nMkCntPos == pAttr->GetStart() && | ||||||||||||||
4138 | nullptr != (pEndIdx = pAttr->End()) && | ||||||||||||||
4139 | *pEndIdx == pAttr->GetStart() ) | ||||||||||||||
4140 | pTextNd->DestroyAttr( pHts->Cut( n ) ); | ||||||||||||||
4141 | } | ||||||||||||||
4142 | } | ||||||||||||||
4143 | } | ||||||||||||||
4144 | |||||||||||||||
4145 | { | ||||||||||||||
4146 | // Send DataChanged before deletion, so that we still know | ||||||||||||||
4147 | // which objects are in the range. | ||||||||||||||
4148 | // Afterwards they could be before/after the Position. | ||||||||||||||
4149 | SwDataChanged aTmp( rPam ); | ||||||||||||||
4150 | } | ||||||||||||||
4151 | |||||||||||||||
4152 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4153 | { | ||||||||||||||
4154 | m_rDoc.GetIDocumentUndoRedo().ClearRedo(); | ||||||||||||||
4155 | bool bMerged(false); | ||||||||||||||
4156 | if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo()) | ||||||||||||||
4157 | { | ||||||||||||||
4158 | SwUndo *const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() ); | ||||||||||||||
4159 | SwUndoDelete *const pUndoDelete( | ||||||||||||||
4160 | dynamic_cast<SwUndoDelete *>(pLastUndo) ); | ||||||||||||||
4161 | if (pUndoDelete) | ||||||||||||||
4162 | { | ||||||||||||||
4163 | bMerged = pUndoDelete->CanGrouping(m_rDoc, rPam); | ||||||||||||||
4164 | // if CanGrouping() returns true it's already merged | ||||||||||||||
4165 | } | ||||||||||||||
4166 | } | ||||||||||||||
4167 | if (!bMerged) | ||||||||||||||
4168 | { | ||||||||||||||
4169 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelete>( rPam ) ); | ||||||||||||||
4170 | } | ||||||||||||||
4171 | |||||||||||||||
4172 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
4173 | |||||||||||||||
4174 | return true; | ||||||||||||||
4175 | } | ||||||||||||||
4176 | |||||||||||||||
4177 | if( !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) | ||||||||||||||
4178 | m_rDoc.getIDocumentRedlineAccess().DeleteRedline( rPam, true, RedlineType::Any ); | ||||||||||||||
4179 | |||||||||||||||
4180 | // Delete and move all "Flys at the paragraph", which are within the Selection | ||||||||||||||
4181 | DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode, | ||||||||||||||
4182 | &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent); | ||||||||||||||
4183 | DelBookmarks( | ||||||||||||||
4184 | pStt->nNode, | ||||||||||||||
4185 | pEnd->nNode, | ||||||||||||||
4186 | nullptr, | ||||||||||||||
4187 | &pStt->nContent, | ||||||||||||||
4188 | &pEnd->nContent); | ||||||||||||||
4189 | |||||||||||||||
4190 | SwNodeIndex aSttIdx( pStt->nNode ); | ||||||||||||||
4191 | SwContentNode * pCNd = aSttIdx.GetNode().GetContentNode(); | ||||||||||||||
4192 | |||||||||||||||
4193 | do { // middle checked loop! | ||||||||||||||
4194 | if( pCNd ) | ||||||||||||||
4195 | { | ||||||||||||||
4196 | SwTextNode * pStartTextNode( pCNd->GetTextNode() ); | ||||||||||||||
4197 | if ( pStartTextNode ) | ||||||||||||||
4198 | { | ||||||||||||||
4199 | // now move the Content to the new Node | ||||||||||||||
4200 | bool bOneNd = pStt->nNode == pEnd->nNode; | ||||||||||||||
4201 | const sal_Int32 nLen = ( bOneNd ? pEnd->nContent.GetIndex() | ||||||||||||||
4202 | : pCNd->Len() ) | ||||||||||||||
4203 | - pStt->nContent.GetIndex(); | ||||||||||||||
4204 | |||||||||||||||
4205 | // Don't call again, if already empty | ||||||||||||||
4206 | if( nLen ) | ||||||||||||||
4207 | { | ||||||||||||||
4208 | pStartTextNode->EraseText( pStt->nContent, nLen ); | ||||||||||||||
4209 | |||||||||||||||
4210 | if( !pStartTextNode->Len() ) | ||||||||||||||
4211 | { | ||||||||||||||
4212 | // METADATA: remove reference if empty (consider node deleted) | ||||||||||||||
4213 | pStartTextNode->RemoveMetadataReference(); | ||||||||||||||
4214 | } | ||||||||||||||
4215 | } | ||||||||||||||
4216 | |||||||||||||||
4217 | if( bOneNd ) // that's it | ||||||||||||||
4218 | break; | ||||||||||||||
4219 | |||||||||||||||
4220 | ++aSttIdx; | ||||||||||||||
4221 | } | ||||||||||||||
4222 | else | ||||||||||||||
4223 | { | ||||||||||||||
4224 | // So that there are no indices left registered when deleted, | ||||||||||||||
4225 | // we remove a SwPaM from the Content here. | ||||||||||||||
4226 | pStt->nContent.Assign( nullptr, 0 ); | ||||||||||||||
4227 | } | ||||||||||||||
4228 | } | ||||||||||||||
4229 | |||||||||||||||
4230 | pCNd = pEnd->nNode.GetNode().GetContentNode(); | ||||||||||||||
4231 | if( pCNd ) | ||||||||||||||
4232 | { | ||||||||||||||
4233 | SwTextNode * pEndTextNode( pCNd->GetTextNode() ); | ||||||||||||||
4234 | if( pEndTextNode ) | ||||||||||||||
4235 | { | ||||||||||||||
4236 | // if already empty, don't call again | ||||||||||||||
4237 | if( pEnd->nContent.GetIndex() ) | ||||||||||||||
4238 | { | ||||||||||||||
4239 | SwIndex aIdx( pCNd, 0 ); | ||||||||||||||
4240 | pEndTextNode->EraseText( aIdx, pEnd->nContent.GetIndex() ); | ||||||||||||||
4241 | |||||||||||||||
4242 | if( !pEndTextNode->Len() ) | ||||||||||||||
4243 | { | ||||||||||||||
4244 | // METADATA: remove reference if empty (consider node deleted) | ||||||||||||||
4245 | pEndTextNode->RemoveMetadataReference(); | ||||||||||||||
4246 | } | ||||||||||||||
4247 | } | ||||||||||||||
4248 | } | ||||||||||||||
4249 | else | ||||||||||||||
4250 | { | ||||||||||||||
4251 | // So that there are no indices left registered when deleted, | ||||||||||||||
4252 | // we remove a SwPaM from the Content here. | ||||||||||||||
4253 | pEnd->nContent.Assign( nullptr, 0 ); | ||||||||||||||
4254 | } | ||||||||||||||
4255 | } | ||||||||||||||
4256 | |||||||||||||||
4257 | // if the end is not a content node, delete it as well | ||||||||||||||
4258 | sal_uInt32 nEnd = pEnd->nNode.GetIndex(); | ||||||||||||||
4259 | if( pCNd == nullptr ) | ||||||||||||||
4260 | nEnd++; | ||||||||||||||
4261 | |||||||||||||||
4262 | if( aSttIdx != nEnd ) | ||||||||||||||
4263 | { | ||||||||||||||
4264 | // tdf#134436 delete section nodes like SwUndoDelete::SwUndoDelete | ||||||||||||||
4265 | SwNode *pTmpNd; | ||||||||||||||
4266 | while (pEnd == rPam.GetPoint() | ||||||||||||||
4267 | && nEnd + 2 < m_rDoc.GetNodes().Count() | ||||||||||||||
4268 | && (pTmpNd = m_rDoc.GetNodes()[nEnd + 1])->IsEndNode() | ||||||||||||||
4269 | && pTmpNd->StartOfSectionNode()->IsSectionNode() | ||||||||||||||
4270 | && aSttIdx <= pTmpNd->StartOfSectionNode()->GetIndex()) | ||||||||||||||
4271 | { | ||||||||||||||
4272 | SwNodeRange range(*pTmpNd->StartOfSectionNode(), *pTmpNd); | ||||||||||||||
4273 | m_rDoc.GetNodes().SectionUp(&range); | ||||||||||||||
4274 | --nEnd; // account for deleted start node | ||||||||||||||
4275 | } | ||||||||||||||
4276 | |||||||||||||||
4277 | // delete the Nodes from the NodesArray | ||||||||||||||
4278 | m_rDoc.GetNodes().Delete( aSttIdx, nEnd - aSttIdx.GetIndex() ); | ||||||||||||||
4279 | } | ||||||||||||||
4280 | |||||||||||||||
4281 | // If the Node that contained the Cursor has been deleted, | ||||||||||||||
4282 | // the Content has to be assigned to the current Content. | ||||||||||||||
4283 | pStt->nContent.Assign( pStt->nNode.GetNode().GetContentNode(), | ||||||||||||||
4284 | pStt->nContent.GetIndex() ); | ||||||||||||||
4285 | |||||||||||||||
4286 | // If we deleted across Node boundaries we have to correct the PaM, | ||||||||||||||
4287 | // because they are in different Nodes now. | ||||||||||||||
4288 | // Also, the Selection is revoked. | ||||||||||||||
4289 | *pEnd = *pStt; | ||||||||||||||
4290 | rPam.DeleteMark(); | ||||||||||||||
4291 | |||||||||||||||
4292 | } while( false ); | ||||||||||||||
4293 | |||||||||||||||
4294 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
4295 | |||||||||||||||
4296 | return true; | ||||||||||||||
4297 | } | ||||||||||||||
4298 | |||||||||||||||
4299 | // It's possible to call Replace with a PaM that spans 2 paragraphs: | ||||||||||||||
4300 | // search with regex for "$", then replace _all_ | ||||||||||||||
4301 | bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM& rPam, const OUString& rStr, | ||||||||||||||
4302 | const bool bRegExReplace ) | ||||||||||||||
4303 | { | ||||||||||||||
4304 | if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() ) | ||||||||||||||
4305 | return false; | ||||||||||||||
4306 | |||||||||||||||
4307 | bool bJoinText, bJoinPrev; | ||||||||||||||
4308 | ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev ); | ||||||||||||||
4309 | |||||||||||||||
4310 | { | ||||||||||||||
4311 | // Create a copy of the Cursor in order to move all Pams from | ||||||||||||||
4312 | // the other views out of the deletion range. | ||||||||||||||
4313 | // Except for itself! | ||||||||||||||
4314 | SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); | ||||||||||||||
4315 | ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() ); | ||||||||||||||
4316 | |||||||||||||||
4317 | SwPosition *pStt = aDelPam.Start(), | ||||||||||||||
4318 | *pEnd = aDelPam.End(); | ||||||||||||||
4319 | bool bOneNode = pStt->nNode == pEnd->nNode; | ||||||||||||||
4320 | |||||||||||||||
4321 | // Own Undo? | ||||||||||||||
4322 | OUString sRepl( rStr ); | ||||||||||||||
4323 | SwTextNode* pTextNd = pStt->nNode.GetNode().GetTextNode(); | ||||||||||||||
4324 | sal_Int32 nStt = pStt->nContent.GetIndex(); | ||||||||||||||
4325 | sal_Int32 nEnd; | ||||||||||||||
4326 | |||||||||||||||
4327 | SwDataChanged aTmp( aDelPam ); | ||||||||||||||
4328 | |||||||||||||||
4329 | if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) | ||||||||||||||
4330 | { | ||||||||||||||
4331 | RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | ||||||||||||||
4332 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4333 | { | ||||||||||||||
4334 | // this should no longer happen in calls from the UI but maybe via API | ||||||||||||||
4335 | SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,do { if (true && ((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask)) { 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() << "redlines will be moved in ReplaceRange" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in ReplaceRange" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in ReplaceRange"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "redlines will be moved in ReplaceRange") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core") , ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in ReplaceRange" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in ReplaceRange"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||||||||||||
4336 | "sw.core", "redlines will be moved in ReplaceRange")do { if (true && ((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask)) { 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() << "redlines will be moved in ReplaceRange" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core" ), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in ReplaceRange" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in ReplaceRange"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "redlines will be moved in ReplaceRange") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core") , ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "redlines will be moved in ReplaceRange" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "redlines will be moved in ReplaceRange"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" ":" "4336" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||||||||||||
4337 | |||||||||||||||
4338 | m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); | ||||||||||||||
4339 | |||||||||||||||
4340 | // If any Redline will change (split!) the node | ||||||||||||||
4341 | const ::sw::mark::IMark* pBkmk = | ||||||||||||||
4342 | m_rDoc.getIDocumentMarkAccess()->makeMark( aDelPam, | ||||||||||||||
4343 | OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK, | ||||||||||||||
4344 | ::sw::mark::InsertMode::New); | ||||||||||||||
4345 | |||||||||||||||
4346 | m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( | ||||||||||||||
4347 | RedlineFlags::On | RedlineFlags::ShowInsert | RedlineFlags::ShowDelete ); | ||||||||||||||
4348 | |||||||||||||||
4349 | *aDelPam.GetPoint() = pBkmk->GetMarkPos(); | ||||||||||||||
4350 | if(pBkmk->IsExpanded()) | ||||||||||||||
4351 | *aDelPam.GetMark() = pBkmk->GetOtherMarkPos(); | ||||||||||||||
4352 | m_rDoc.getIDocumentMarkAccess()->deleteMark(pBkmk); | ||||||||||||||
4353 | pStt = aDelPam.Start(); | ||||||||||||||
4354 | pTextNd = pStt->nNode.GetNode().GetTextNode(); | ||||||||||||||
4355 | nStt = pStt->nContent.GetIndex(); | ||||||||||||||
4356 | } | ||||||||||||||
4357 | |||||||||||||||
4358 | if( !sRepl.isEmpty() ) | ||||||||||||||
4359 | { | ||||||||||||||
4360 | // Apply the first character's attributes to the ReplaceText | ||||||||||||||
4361 | SfxItemSet aSet( m_rDoc.GetAttrPool(), | ||||||||||||||
4362 | svl::Items<RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1, | ||||||||||||||
4363 | RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1>{} ); | ||||||||||||||
4364 | pTextNd->GetParaAttr( aSet, nStt+1, nStt+1 ); | ||||||||||||||
4365 | |||||||||||||||
4366 | aSet.ClearItem( RES_TXTATR_REFMARK ); | ||||||||||||||
4367 | aSet.ClearItem( RES_TXTATR_TOXMARK ); | ||||||||||||||
4368 | aSet.ClearItem( RES_TXTATR_CJK_RUBY ); | ||||||||||||||
4369 | aSet.ClearItem( RES_TXTATR_INETFMT ); | ||||||||||||||
4370 | aSet.ClearItem( RES_TXTATR_META ); | ||||||||||||||
4371 | aSet.ClearItem( RES_TXTATR_METAFIELD ); | ||||||||||||||
4372 | |||||||||||||||
4373 | if( aDelPam.GetPoint() != aDelPam.End() ) | ||||||||||||||
4374 | aDelPam.Exchange(); | ||||||||||||||
4375 | |||||||||||||||
4376 | // Remember the End | ||||||||||||||
4377 | SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 ); | ||||||||||||||
4378 | const sal_Int32 nPtCnt = aDelPam.GetPoint()->nContent.GetIndex(); | ||||||||||||||
4379 | |||||||||||||||
4380 | bool bFirst = true; | ||||||||||||||
4381 | OUString sIns; | ||||||||||||||
4382 | while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) ) | ||||||||||||||
4383 | { | ||||||||||||||
4384 | InsertString( aDelPam, sIns ); | ||||||||||||||
4385 | if( bFirst ) | ||||||||||||||
4386 | { | ||||||||||||||
4387 | SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 ); | ||||||||||||||
4388 | const sal_Int32 nMkCnt = aDelPam.GetMark()->nContent.GetIndex(); | ||||||||||||||
4389 | |||||||||||||||
4390 | SplitNode( *aDelPam.GetPoint(), false ); | ||||||||||||||
4391 | |||||||||||||||
4392 | ++aMkNd; | ||||||||||||||
4393 | aDelPam.GetMark()->nNode = aMkNd; | ||||||||||||||
4394 | aDelPam.GetMark()->nContent.Assign( | ||||||||||||||
4395 | aMkNd.GetNode().GetContentNode(), nMkCnt ); | ||||||||||||||
4396 | bFirst = false; | ||||||||||||||
4397 | } | ||||||||||||||
4398 | else | ||||||||||||||
4399 | SplitNode( *aDelPam.GetPoint(), false ); | ||||||||||||||
4400 | } | ||||||||||||||
4401 | if( !sIns.isEmpty() ) | ||||||||||||||
4402 | { | ||||||||||||||
4403 | InsertString( aDelPam, sIns ); | ||||||||||||||
4404 | } | ||||||||||||||
4405 | |||||||||||||||
4406 | SwPaM aTmpRange( *aDelPam.GetPoint() ); | ||||||||||||||
4407 | aTmpRange.SetMark(); | ||||||||||||||
4408 | |||||||||||||||
4409 | ++aPtNd; | ||||||||||||||
4410 | aDelPam.GetPoint()->nNode = aPtNd; | ||||||||||||||
4411 | aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetContentNode(), | ||||||||||||||
4412 | nPtCnt); | ||||||||||||||
4413 | *aTmpRange.GetMark() = *aDelPam.GetPoint(); | ||||||||||||||
4414 | |||||||||||||||
4415 | m_rDoc.RstTextAttrs( aTmpRange ); | ||||||||||||||
4416 | InsertItemSet( aTmpRange, aSet ); | ||||||||||||||
4417 | } | ||||||||||||||
4418 | |||||||||||||||
4419 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4420 | { | ||||||||||||||
4421 | m_rDoc.GetIDocumentUndoRedo().AppendUndo( | ||||||||||||||
4422 | std::make_unique<SwUndoRedlineDelete>( aDelPam, SwUndoId::REPLACE )); | ||||||||||||||
4423 | } | ||||||||||||||
4424 | m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Delete, aDelPam ), true); | ||||||||||||||
4425 | |||||||||||||||
4426 | *rPam.GetMark() = *aDelPam.GetMark(); | ||||||||||||||
4427 | if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4428 | { | ||||||||||||||
4429 | *aDelPam.GetPoint() = *rPam.GetPoint(); | ||||||||||||||
4430 | m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); | ||||||||||||||
4431 | |||||||||||||||
4432 | // If any Redline will change (split!) the node | ||||||||||||||
4433 | const ::sw::mark::IMark* pBkmk = | ||||||||||||||
4434 | m_rDoc.getIDocumentMarkAccess()->makeMark( aDelPam, | ||||||||||||||
4435 | OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK, | ||||||||||||||
4436 | ::sw::mark::InsertMode::New); | ||||||||||||||
4437 | |||||||||||||||
4438 | SwIndex& rIdx = aDelPam.GetPoint()->nContent; | ||||||||||||||
4439 | rIdx.Assign( nullptr, 0 ); | ||||||||||||||
4440 | aDelPam.GetMark()->nContent = rIdx; | ||||||||||||||
4441 | rPam.GetPoint()->nNode = 0; | ||||||||||||||
4442 | rPam.GetPoint()->nContent = rIdx; | ||||||||||||||
4443 | *rPam.GetMark() = *rPam.GetPoint(); | ||||||||||||||
4444 | m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld ); | ||||||||||||||
4445 | |||||||||||||||
4446 | *rPam.GetPoint() = pBkmk->GetMarkPos(); | ||||||||||||||
4447 | if(pBkmk->IsExpanded()) | ||||||||||||||
4448 | *rPam.GetMark() = pBkmk->GetOtherMarkPos(); | ||||||||||||||
4449 | m_rDoc.getIDocumentMarkAccess()->deleteMark(pBkmk); | ||||||||||||||
4450 | } | ||||||||||||||
4451 | bJoinText = false; | ||||||||||||||
4452 | } | ||||||||||||||
4453 | else | ||||||||||||||
4454 | { | ||||||||||||||
4455 | assert((pStt->nNode == pEnd->nNode ||(static_cast <bool> ((pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes" ) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4458, __extension__ __PRETTY_FUNCTION__)) | ||||||||||||||
4456 | ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&(static_cast <bool> ((pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes" ) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4458, __extension__ __PRETTY_FUNCTION__)) | ||||||||||||||
4457 | !pEnd->nContent.GetIndex() )) &&(static_cast <bool> ((pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes" ) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4458, __extension__ __PRETTY_FUNCTION__)) | ||||||||||||||
4458 | "invalid range: Point and Mark on different nodes" )(static_cast <bool> ((pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes" ) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\"" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4458, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
4459 | |||||||||||||||
4460 | if( !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) | ||||||||||||||
4461 | m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aDelPam, true, RedlineType::Any ); | ||||||||||||||
4462 | |||||||||||||||
4463 | SwUndoReplace* pUndoRpl = nullptr; | ||||||||||||||
4464 | bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo(); | ||||||||||||||
4465 | if (bDoesUndo) | ||||||||||||||
4466 | { | ||||||||||||||
4467 | pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace); | ||||||||||||||
4468 | m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoRpl)); | ||||||||||||||
4469 | } | ||||||||||||||
4470 | ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo()); | ||||||||||||||
4471 | |||||||||||||||
4472 | if( aDelPam.GetPoint() != pStt ) | ||||||||||||||
4473 | aDelPam.Exchange(); | ||||||||||||||
4474 | |||||||||||||||
4475 | SwNodeIndex aPtNd( pStt->nNode, -1 ); | ||||||||||||||
4476 | const sal_Int32 nPtCnt = pStt->nContent.GetIndex(); | ||||||||||||||
4477 | |||||||||||||||
4478 | // Set the values again, if Frames or footnotes on the Text have been removed. | ||||||||||||||
4479 | nStt = nPtCnt; | ||||||||||||||
4480 | nEnd = bOneNode ? pEnd->nContent.GetIndex() | ||||||||||||||
4481 | : pTextNd->GetText().getLength(); | ||||||||||||||
4482 | |||||||||||||||
4483 | bool bFirst = true; | ||||||||||||||
4484 | OUString sIns; | ||||||||||||||
4485 | while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) ) | ||||||||||||||
4486 | { | ||||||||||||||
4487 | if (!bFirst || nStt == pTextNd->GetText().getLength()) | ||||||||||||||
4488 | { | ||||||||||||||
4489 | InsertString( aDelPam, sIns ); | ||||||||||||||
4490 | } | ||||||||||||||
4491 | else if( nStt < nEnd || !sIns.isEmpty() ) | ||||||||||||||
4492 | { | ||||||||||||||
4493 | pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns ); | ||||||||||||||
4494 | } | ||||||||||||||
4495 | SplitNode( *pStt, false); | ||||||||||||||
4496 | bFirst = false; | ||||||||||||||
4497 | } | ||||||||||||||
4498 | |||||||||||||||
4499 | if( bFirst || !sIns.isEmpty() ) | ||||||||||||||
4500 | { | ||||||||||||||
4501 | if (!bFirst || nStt == pTextNd->GetText().getLength()) | ||||||||||||||
4502 | { | ||||||||||||||
4503 | InsertString( aDelPam, sIns ); | ||||||||||||||
4504 | } | ||||||||||||||
4505 | else if( nStt < nEnd || !sIns.isEmpty() ) | ||||||||||||||
4506 | { | ||||||||||||||
4507 | pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns ); | ||||||||||||||
4508 | } | ||||||||||||||
4509 | } | ||||||||||||||
4510 | |||||||||||||||
4511 | *rPam.GetPoint() = *aDelPam.GetMark(); | ||||||||||||||
4512 | ++aPtNd; | ||||||||||||||
4513 | rPam.GetMark()->nNode = aPtNd; | ||||||||||||||
4514 | rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetContentNode(), | ||||||||||||||
4515 | nPtCnt ); | ||||||||||||||
4516 | |||||||||||||||
4517 | if (bJoinText) | ||||||||||||||
4518 | { | ||||||||||||||
4519 | assert(rPam.GetPoint() == rPam.End())(static_cast <bool> (rPam.GetPoint() == rPam.End()) ? void (0) : __assert_fail ("rPam.GetPoint() == rPam.End()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4519, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
4520 | // move so that SetEnd remembers position after sw_JoinText | ||||||||||||||
4521 | rPam.Move(fnMoveBackward); | ||||||||||||||
4522 | } | ||||||||||||||
4523 | else if (aDelPam.GetPoint() == pStt) // backward selection? | ||||||||||||||
4524 | { | ||||||||||||||
4525 | assert(*rPam.GetMark() <= *rPam.GetPoint())(static_cast <bool> (*rPam.GetMark() <= *rPam.GetPoint ()) ? void (0) : __assert_fail ("*rPam.GetMark() <= *rPam.GetPoint()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4525, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
4526 | rPam.Exchange(); // swap so that rPam is backwards | ||||||||||||||
4527 | } | ||||||||||||||
4528 | |||||||||||||||
4529 | if( pUndoRpl ) | ||||||||||||||
4530 | { | ||||||||||||||
4531 | pUndoRpl->SetEnd(rPam); | ||||||||||||||
4532 | } | ||||||||||||||
4533 | } | ||||||||||||||
4534 | } | ||||||||||||||
4535 | |||||||||||||||
4536 | bool bRet(true); | ||||||||||||||
4537 | if (bJoinText) | ||||||||||||||
4538 | { | ||||||||||||||
4539 | bRet = ::sw_JoinText(rPam, bJoinPrev); | ||||||||||||||
4540 | } | ||||||||||||||
4541 | |||||||||||||||
4542 | m_rDoc.getIDocumentState().SetModified(); | ||||||||||||||
4543 | return bRet; | ||||||||||||||
4544 | } | ||||||||||||||
4545 | |||||||||||||||
4546 | SwFlyFrameFormat* DocumentContentOperationsManager::InsNoTextNode( const SwPosition& rPos, SwNoTextNode* pNode, | ||||||||||||||
4547 | const SfxItemSet* pFlyAttrSet, | ||||||||||||||
4548 | const SfxItemSet* pGrfAttrSet, | ||||||||||||||
4549 | SwFrameFormat* pFrameFormat) | ||||||||||||||
4550 | { | ||||||||||||||
4551 | SwFlyFrameFormat *pFormat = nullptr; | ||||||||||||||
4552 | if( pNode ) | ||||||||||||||
4553 | { | ||||||||||||||
4554 | pFormat = m_rDoc.MakeFlySection_( rPos, *pNode, RndStdIds::FLY_AT_PARA, | ||||||||||||||
4555 | pFlyAttrSet, pFrameFormat ); | ||||||||||||||
4556 | if( pGrfAttrSet ) | ||||||||||||||
4557 | pNode->SetAttr( *pGrfAttrSet ); | ||||||||||||||
4558 | } | ||||||||||||||
4559 | return pFormat; | ||||||||||||||
4560 | } | ||||||||||||||
4561 | |||||||||||||||
4562 | #define NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr <SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState = SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem> aListIdItem; \ | ||||||||||||||
4563 | SfxItemState aNumRuleState = SfxItemState::UNKNOWN; \ | ||||||||||||||
4564 | std::shared_ptr<SwNumRuleItem> aNumRuleItem; \ | ||||||||||||||
4565 | SfxItemState aListIdState = SfxItemState::UNKNOWN; \ | ||||||||||||||
4566 | std::shared_ptr<SfxStringItem> aListIdItem; \ | ||||||||||||||
4567 | |||||||||||||||
4568 | #define PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd ); \ | ||||||||||||||
4569 | lcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd ); | ||||||||||||||
4570 | |||||||||||||||
4571 | #define POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd, rPam ); \ | ||||||||||||||
4572 | lcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd, rPam ); | ||||||||||||||
4573 | |||||||||||||||
4574 | static void lcl_PushNumruleState( | ||||||||||||||
4575 | SfxItemState &aNumRuleState, std::shared_ptr<SwNumRuleItem>& aNumRuleItem, | ||||||||||||||
4576 | SfxItemState &aListIdState, std::shared_ptr<SfxStringItem>& aListIdItem, | ||||||||||||||
4577 | const SwTextNode *pDestTextNd ) | ||||||||||||||
4578 | { | ||||||||||||||
4579 | // Safe numrule item at destination. | ||||||||||||||
4580 | // #i86492# - Safe also <ListId> item of destination. | ||||||||||||||
4581 | const SfxItemSet * pAttrSet = pDestTextNd->GetpSwAttrSet(); | ||||||||||||||
4582 | if (pAttrSet == nullptr) | ||||||||||||||
4583 | return; | ||||||||||||||
4584 | |||||||||||||||
4585 | const SfxPoolItem * pItem = nullptr; | ||||||||||||||
4586 | aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, false, &pItem); | ||||||||||||||
4587 | if (SfxItemState::SET == aNumRuleState) | ||||||||||||||
4588 | { | ||||||||||||||
4589 | aNumRuleItem.reset(static_cast<SwNumRuleItem*>(pItem->Clone())); | ||||||||||||||
4590 | } | ||||||||||||||
4591 | |||||||||||||||
4592 | aListIdState = pAttrSet->GetItemState(RES_PARATR_LIST_ID, false, &pItem); | ||||||||||||||
4593 | if (SfxItemState::SET == aListIdState) | ||||||||||||||
4594 | { | ||||||||||||||
4595 | aListIdItem.reset(static_cast<SfxStringItem*>(pItem->Clone())); | ||||||||||||||
4596 | } | ||||||||||||||
4597 | } | ||||||||||||||
4598 | |||||||||||||||
4599 | static void lcl_PopNumruleState( | ||||||||||||||
4600 | SfxItemState aNumRuleState, const std::shared_ptr<SwNumRuleItem>& aNumRuleItem, | ||||||||||||||
4601 | SfxItemState aListIdState, const std::shared_ptr<SfxStringItem>& aListIdItem, | ||||||||||||||
4602 | SwTextNode *pDestTextNd, const SwPaM& rPam ) | ||||||||||||||
4603 | { | ||||||||||||||
4604 | /* If only a part of one paragraph is copied | ||||||||||||||
4605 | restore the numrule at the destination. */ | ||||||||||||||
4606 | // #i86492# - restore also <ListId> item | ||||||||||||||
4607 | if ( lcl_MarksWholeNode(rPam) ) | ||||||||||||||
4608 | return; | ||||||||||||||
4609 | |||||||||||||||
4610 | if (SfxItemState::SET == aNumRuleState) | ||||||||||||||
4611 | { | ||||||||||||||
4612 | pDestTextNd->SetAttr(*aNumRuleItem); | ||||||||||||||
4613 | } | ||||||||||||||
4614 | else | ||||||||||||||
4615 | { | ||||||||||||||
4616 | pDestTextNd->ResetAttr(RES_PARATR_NUMRULE); | ||||||||||||||
4617 | } | ||||||||||||||
4618 | if (SfxItemState::SET == aListIdState) | ||||||||||||||
4619 | { | ||||||||||||||
4620 | pDestTextNd->SetAttr(*aListIdItem); | ||||||||||||||
4621 | } | ||||||||||||||
4622 | else | ||||||||||||||
4623 | { | ||||||||||||||
4624 | pDestTextNd->ResetAttr(RES_PARATR_LIST_ID); | ||||||||||||||
4625 | } | ||||||||||||||
4626 | } | ||||||||||||||
4627 | |||||||||||||||
4628 | bool DocumentContentOperationsManager::CopyImpl(SwPaM& rPam, SwPosition& rPos, | ||||||||||||||
4629 | SwCopyFlags const flags, | ||||||||||||||
4630 | SwPaM *const pCopyRange) const | ||||||||||||||
4631 | { | ||||||||||||||
4632 | std::vector<std::pair<sal_uLong, sal_Int32>> Breaks; | ||||||||||||||
4633 | |||||||||||||||
4634 | sw::CalcBreaks(Breaks, rPam, true); | ||||||||||||||
4635 | |||||||||||||||
4636 | if (Breaks.empty()) | ||||||||||||||
4637 | { | ||||||||||||||
4638 | return CopyImplImpl(rPam, rPos, flags, pCopyRange); | ||||||||||||||
4639 | } | ||||||||||||||
4640 | |||||||||||||||
4641 | SwPosition const & rSelectionEnd( *rPam.End() ); | ||||||||||||||
4642 | |||||||||||||||
4643 | bool bRet(true); | ||||||||||||||
4644 | bool bFirst(true); | ||||||||||||||
4645 | // iterate from end to start, ... don't think it's necessary here? | ||||||||||||||
4646 | auto iter( Breaks.rbegin() ); | ||||||||||||||
4647 | sal_uLong nOffset(0); | ||||||||||||||
4648 | SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes()); | ||||||||||||||
4649 | SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node! | ||||||||||||||
4650 | SwPosition & rEnd( *aPam.End() ); | ||||||||||||||
4651 | SwPosition & rStart( *aPam.Start() ); | ||||||||||||||
4652 | SwPaM copyRange(rPos, rPos); | ||||||||||||||
4653 | |||||||||||||||
4654 | while (iter != Breaks.rend()) | ||||||||||||||
4655 | { | ||||||||||||||
4656 | rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1); | ||||||||||||||
4657 | if (rStart < rEnd) // check if part is empty | ||||||||||||||
4658 | { | ||||||||||||||
4659 | // pass in copyRange member as rPos; should work ... | ||||||||||||||
4660 | bRet &= CopyImplImpl(aPam, *copyRange.Start(), flags & ~SwCopyFlags::IsMoveToFly, ©Range); | ||||||||||||||
4661 | nOffset = iter->first - rStart.nNode.GetIndex(); // fly nodes... | ||||||||||||||
4662 | if (pCopyRange) | ||||||||||||||
4663 | { | ||||||||||||||
4664 | if (bFirst) | ||||||||||||||
4665 | { | ||||||||||||||
4666 | pCopyRange->SetMark(); | ||||||||||||||
4667 | *pCopyRange->GetMark() = *copyRange.End(); | ||||||||||||||
4668 | } | ||||||||||||||
4669 | *pCopyRange->GetPoint() = *copyRange.Start(); | ||||||||||||||
4670 | } | ||||||||||||||
4671 | bFirst = false; | ||||||||||||||
4672 | } | ||||||||||||||
4673 | rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second); | ||||||||||||||
4674 | ++iter; | ||||||||||||||
4675 | } | ||||||||||||||
4676 | |||||||||||||||
4677 | rStart = *rPam.Start(); // set to original start | ||||||||||||||
4678 | if (rStart < rEnd) // check if part is empty | ||||||||||||||
4679 | { | ||||||||||||||
4680 | bRet &= CopyImplImpl(aPam, *copyRange.Start(), flags & ~SwCopyFlags::IsMoveToFly, ©Range); | ||||||||||||||
4681 | if (pCopyRange) | ||||||||||||||
4682 | { | ||||||||||||||
4683 | if (bFirst) | ||||||||||||||
4684 | { | ||||||||||||||
4685 | pCopyRange->SetMark(); | ||||||||||||||
4686 | *pCopyRange->GetMark() = *copyRange.End(); | ||||||||||||||
4687 | } | ||||||||||||||
4688 | *pCopyRange->GetPoint() = *copyRange.Start(); | ||||||||||||||
4689 | } | ||||||||||||||
4690 | } | ||||||||||||||
4691 | |||||||||||||||
4692 | return bRet; | ||||||||||||||
4693 | } | ||||||||||||||
4694 | |||||||||||||||
4695 | bool DocumentContentOperationsManager::CopyImplImpl(SwPaM& rPam, SwPosition& rPos, | ||||||||||||||
4696 | SwCopyFlags const flags, | ||||||||||||||
4697 | SwPaM *const pCpyRange) const | ||||||||||||||
4698 | { | ||||||||||||||
4699 | SwDoc& rDoc = rPos.nNode.GetNode().GetDoc(); | ||||||||||||||
4700 | const bool bColumnSel = rDoc.IsClipBoard() && rDoc.IsColumnSelection(); | ||||||||||||||
| |||||||||||||||
4701 | |||||||||||||||
4702 | SwPosition const*const pStt = rPam.Start(); | ||||||||||||||
4703 | SwPosition *const pEnd = rPam.End(); | ||||||||||||||
4704 | |||||||||||||||
4705 | // Catch when there's no copy to do. | ||||||||||||||
4706 | if (!rPam.HasMark() || (IsEmptyRange(*pStt, *pEnd, flags) && !bColumnSel) || | ||||||||||||||
4707 | //JP 29.6.2001: 88963 - don't copy if inspos is in region of start to end | ||||||||||||||
4708 | //JP 15.11.2001: don't test inclusive the end, ever exclusive | ||||||||||||||
4709 | ( &rDoc == &m_rDoc && *pStt <= rPos && rPos < *pEnd )) | ||||||||||||||
4710 | { | ||||||||||||||
4711 | return false; | ||||||||||||||
4712 | } | ||||||||||||||
4713 | |||||||||||||||
4714 | const bool bEndEqualIns = &rDoc == &m_rDoc && rPos == *pEnd; | ||||||||||||||
4715 | |||||||||||||||
4716 | // If Undo is enabled, create the UndoCopy object | ||||||||||||||
4717 | SwUndoCpyDoc* pUndo = nullptr; | ||||||||||||||
4718 | // lcl_DeleteRedlines may delete the start or end node of the cursor when | ||||||||||||||
4719 | // removing the redlines so use cursor that is corrected by PaMCorrAbs | ||||||||||||||
4720 | std::shared_ptr<SwUnoCursor> const pCopyPam(rDoc.CreateUnoCursor(rPos)); | ||||||||||||||
4721 | |||||||||||||||
4722 | SwTableNumFormatMerge aTNFM( m_rDoc, rDoc ); | ||||||||||||||
4723 | std::unique_ptr<std::vector<SwFrameFormat*>> pFlys; | ||||||||||||||
4724 | std::vector<SwFrameFormat*> const* pFlysAtInsPos; | ||||||||||||||
4725 | |||||||||||||||
4726 | if (rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
4727 | { | ||||||||||||||
4728 | pUndo = new SwUndoCpyDoc(*pCopyPam); | ||||||||||||||
4729 | rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) ); | ||||||||||||||
4730 | pFlysAtInsPos = pUndo->GetFlysAnchoredAt(); | ||||||||||||||
4731 | } | ||||||||||||||
4732 | else | ||||||||||||||
4733 | { | ||||||||||||||
4734 | pFlys = sw::GetFlysAnchoredAt(rDoc, rPos.nNode.GetIndex()); | ||||||||||||||
4735 | pFlysAtInsPos = pFlys.get(); | ||||||||||||||
4736 | } | ||||||||||||||
4737 | |||||||||||||||
4738 | RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags(); | ||||||||||||||
4739 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld | RedlineFlags::Ignore); | ||||||||||||||
4740 | |||||||||||||||
4741 | // Move the PaM one node back from the insert position, so that | ||||||||||||||
4742 | // the position doesn't get moved | ||||||||||||||
4743 | pCopyPam->SetMark(); | ||||||||||||||
4744 | bool bCanMoveBack = pCopyPam->Move(fnMoveBackward, GoInContent); | ||||||||||||||
4745 | // If the position was shifted from more than one node, an end node has been skipped | ||||||||||||||
4746 | bool bAfterTable = false; | ||||||||||||||
4747 | if ((rPos.nNode.GetIndex() - pCopyPam->GetPoint()->nNode.GetIndex()) > 1) | ||||||||||||||
4748 | { | ||||||||||||||
4749 | // First go back to the original place | ||||||||||||||
4750 | pCopyPam->GetPoint()->nNode = rPos.nNode; | ||||||||||||||
4751 | pCopyPam->GetPoint()->nContent = rPos.nContent; | ||||||||||||||
4752 | |||||||||||||||
4753 | bCanMoveBack = false; | ||||||||||||||
4754 | bAfterTable = true; | ||||||||||||||
4755 | } | ||||||||||||||
4756 | if( !bCanMoveBack ) | ||||||||||||||
4757 | { | ||||||||||||||
4758 | pCopyPam->GetPoint()->nNode--; | ||||||||||||||
4759 | assert(pCopyPam->GetPoint()->nContent.GetIndex() == 0)(static_cast <bool> (pCopyPam->GetPoint()->nContent .GetIndex() == 0) ? void (0) : __assert_fail ("pCopyPam->GetPoint()->nContent.GetIndex() == 0" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 4759, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
4760 | } | ||||||||||||||
4761 | |||||||||||||||
4762 | SwNodeRange aRg( pStt->nNode, pEnd->nNode ); | ||||||||||||||
4763 | SwNodeIndex aInsPos( rPos.nNode ); | ||||||||||||||
4764 | const bool bOneNode = pStt->nNode == pEnd->nNode; | ||||||||||||||
4765 | SwTextNode* pSttTextNd = pStt->nNode.GetNode().GetTextNode(); | ||||||||||||||
4766 | SwTextNode* pEndTextNd = pEnd->nNode.GetNode().GetTextNode(); | ||||||||||||||
4767 | SwTextNode* pDestTextNd = aInsPos.GetNode().GetTextNode(); | ||||||||||||||
4768 | bool bCopyCollFormat = !rDoc.IsInsOnlyTextGlossary() && | ||||||||||||||
4769 | ( (pDestTextNd && !pDestTextNd->GetText().getLength()) || | ||||||||||||||
4770 | ( !bOneNode && !rPos.nContent.GetIndex() ) ); | ||||||||||||||
4771 | bool bCopyBookmarks = true; | ||||||||||||||
4772 | bool bCopyPageSource = false; | ||||||||||||||
4773 | int nDeleteTextNodes = 0; | ||||||||||||||
4774 | |||||||||||||||
4775 | // #i104585# copy outline num rule to clipboard (for ASCII filter) | ||||||||||||||
4776 | if (rDoc.IsClipBoard() && m_rDoc.GetOutlineNumRule()) | ||||||||||||||
4777 | { | ||||||||||||||
4778 | rDoc.SetOutlineNumRule(*m_rDoc.GetOutlineNumRule()); | ||||||||||||||
4779 | } | ||||||||||||||
4780 | |||||||||||||||
4781 | // #i86492# | ||||||||||||||
4782 | // Correct the search for a previous list: | ||||||||||||||
4783 | // First search for non-outline numbering list. Then search for non-outline | ||||||||||||||
4784 | // bullet list. | ||||||||||||||
4785 | // Keep also the <ListId> value for possible propagation. | ||||||||||||||
4786 | OUString aListIdToPropagate; | ||||||||||||||
4787 | const SwNumRule* pNumRuleToPropagate = | ||||||||||||||
4788 | rDoc.SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, nullptr, true ); | ||||||||||||||
4789 | if ( !pNumRuleToPropagate ) | ||||||||||||||
4790 | { | ||||||||||||||
4791 | pNumRuleToPropagate = | ||||||||||||||
4792 | rDoc.SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, nullptr, true ); | ||||||||||||||
4793 | } | ||||||||||||||
4794 | // #i86492# | ||||||||||||||
4795 | // Do not propagate previous found list, if | ||||||||||||||
4796 | // - destination is an empty paragraph which is not in a list and | ||||||||||||||
4797 | // - source contains at least one paragraph which is not in a list | ||||||||||||||
4798 | if ( pNumRuleToPropagate
| ||||||||||||||
4799 | pDestTextNd
| ||||||||||||||
4800 | !pDestTextNd->IsInList() && | ||||||||||||||
4801 | !lcl_ContainsOnlyParagraphsInList( rPam ) ) | ||||||||||||||
4802 | { | ||||||||||||||
4803 | pNumRuleToPropagate = nullptr; | ||||||||||||||
4804 | } | ||||||||||||||
4805 | |||||||||||||||
4806 | // This do/while block is only there so that we can break out of it! | ||||||||||||||
4807 | do { | ||||||||||||||
4808 | if( pSttTextNd
| ||||||||||||||
4809 | { | ||||||||||||||
4810 | ++nDeleteTextNodes; // must be joined in Undo | ||||||||||||||
4811 | // Don't copy the beginning completely? | ||||||||||||||
4812 | if( !bCopyCollFormat || bColumnSel || pStt->nContent.GetIndex() ) | ||||||||||||||
4813 | { | ||||||||||||||
4814 | SwIndex aDestIdx( rPos.nContent ); | ||||||||||||||
4815 | bool bCopyOk = false; | ||||||||||||||
4816 | if( !pDestTextNd ) | ||||||||||||||
4817 | { | ||||||||||||||
4818 | if( pStt->nContent.GetIndex() || bOneNode ) | ||||||||||||||
4819 | pDestTextNd = rDoc.GetNodes().MakeTextNode( aInsPos, | ||||||||||||||
4820 | rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD)); | ||||||||||||||
4821 | else | ||||||||||||||
4822 | { | ||||||||||||||
4823 | pDestTextNd = pSttTextNd->MakeCopy(rDoc, aInsPos, true)->GetTextNode(); | ||||||||||||||
4824 | bCopyOk = true; | ||||||||||||||
4825 | } | ||||||||||||||
4826 | aDestIdx.Assign( pDestTextNd, 0 ); | ||||||||||||||
4827 | bCopyCollFormat = true; | ||||||||||||||
4828 | } | ||||||||||||||
4829 | else if( !bOneNode || bColumnSel ) | ||||||||||||||
4830 | { | ||||||||||||||
4831 | const sal_Int32 nContentEnd = pEnd->nContent.GetIndex(); | ||||||||||||||
4832 | { | ||||||||||||||
4833 | ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo()); | ||||||||||||||
4834 | rDoc.getIDocumentContentOperations().SplitNode( rPos, false ); | ||||||||||||||
4835 | } | ||||||||||||||
4836 | |||||||||||||||
4837 | if (bCanMoveBack && rPos == *pCopyPam->GetPoint()) | ||||||||||||||
4838 | { | ||||||||||||||
4839 | // after the SplitNode, span the CpyPam correctly again | ||||||||||||||
4840 | pCopyPam->Move( fnMoveBackward, GoInContent ); | ||||||||||||||
4841 | pCopyPam->Move( fnMoveBackward, GoInContent ); | ||||||||||||||
4842 | } | ||||||||||||||
4843 | |||||||||||||||
4844 | pDestTextNd = rDoc.GetNodes()[ aInsPos.GetIndex()-1 ]->GetTextNode(); | ||||||||||||||
4845 | aDestIdx.Assign( | ||||||||||||||
4846 | pDestTextNd, pDestTextNd->GetText().getLength()); | ||||||||||||||
4847 | |||||||||||||||
4848 | // Correct the area again | ||||||||||||||
4849 | if( bEndEqualIns ) | ||||||||||||||
4850 | { | ||||||||||||||
4851 | bool bChg = pEnd != rPam.GetPoint(); | ||||||||||||||
4852 | if( bChg ) | ||||||||||||||
4853 | rPam.Exchange(); | ||||||||||||||
4854 | rPam.Move( fnMoveBackward, GoInContent ); | ||||||||||||||
4855 | if( bChg ) | ||||||||||||||
4856 | rPam.Exchange(); | ||||||||||||||
4857 | } | ||||||||||||||
4858 | else if( rPos == *pEnd ) | ||||||||||||||
4859 | { | ||||||||||||||
4860 | // The end was also moved | ||||||||||||||
4861 | pEnd->nNode--; | ||||||||||||||
4862 | pEnd->nContent.Assign( pDestTextNd, nContentEnd ); | ||||||||||||||
4863 | } | ||||||||||||||
4864 | // tdf#63022 always reset pEndTextNd after SplitNode | ||||||||||||||
4865 | aRg.aEnd = pEnd->nNode; | ||||||||||||||
4866 | pEndTextNd = pEnd->nNode.GetNode().GetTextNode(); | ||||||||||||||
4867 | } | ||||||||||||||
4868 | |||||||||||||||
4869 | NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr <SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState = SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem> aListIdItem; | ||||||||||||||
4870 | if( bCopyCollFormat && bOneNode ) | ||||||||||||||
4871 | { | ||||||||||||||
4872 | PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd ); | ||||||||||||||
4873 | } | ||||||||||||||
4874 | |||||||||||||||
4875 | if( !bCopyOk ) | ||||||||||||||
4876 | { | ||||||||||||||
4877 | const sal_Int32 nCpyLen = ( bOneNode | ||||||||||||||
4878 | ? pEnd->nContent.GetIndex() | ||||||||||||||
4879 | : pSttTextNd->GetText().getLength()) | ||||||||||||||
4880 | - pStt->nContent.GetIndex(); | ||||||||||||||
4881 | pSttTextNd->CopyText( pDestTextNd, aDestIdx, | ||||||||||||||
4882 | pStt->nContent, nCpyLen ); | ||||||||||||||
4883 | if( bEndEqualIns ) | ||||||||||||||
4884 | pEnd->nContent -= nCpyLen; | ||||||||||||||
4885 | } | ||||||||||||||
4886 | |||||||||||||||
4887 | aRg.aStart++; | ||||||||||||||
4888 | |||||||||||||||
4889 | if( bOneNode ) | ||||||||||||||
4890 | { | ||||||||||||||
4891 | if (bCopyCollFormat) | ||||||||||||||
4892 | { | ||||||||||||||
4893 | pSttTextNd->CopyCollFormat( *pDestTextNd ); | ||||||||||||||
4894 | POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd, rPam ); | ||||||||||||||
4895 | } | ||||||||||||||
4896 | |||||||||||||||
4897 | // copy at-char flys in rPam | ||||||||||||||
4898 | SwNodeIndex temp(*pDestTextNd); // update to new (start) node for flys | ||||||||||||||
4899 | // tdf#126626 prevent duplicate Undos | ||||||||||||||
4900 | ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo()); | ||||||||||||||
4901 | CopyFlyInFlyImpl(aRg, &rPam, temp, false); | ||||||||||||||
4902 | |||||||||||||||
4903 | break; | ||||||||||||||
4904 | } | ||||||||||||||
4905 | } | ||||||||||||||
4906 | } | ||||||||||||||
4907 | else if( pDestTextNd
| ||||||||||||||
4908 | { | ||||||||||||||
4909 | // Problems with insertion of table selections into "normal" text solved. | ||||||||||||||
4910 | // We have to set the correct PaM for Undo, if this PaM starts in a textnode, | ||||||||||||||
4911 | // the undo operation will try to merge this node after removing the table. | ||||||||||||||
4912 | // If we didn't split a textnode, the PaM should start at the inserted table node | ||||||||||||||
4913 | if( rPos.nContent.GetIndex() == pDestTextNd->Len() ) | ||||||||||||||
4914 | { // Insertion at the last position of a textnode (empty or not) | ||||||||||||||
4915 | ++aInsPos; // The table will be inserted behind the text node | ||||||||||||||
4916 | } | ||||||||||||||
4917 | else if( rPos.nContent.GetIndex() ) | ||||||||||||||
4918 | { // Insertion in the middle of a text node, it has to be split | ||||||||||||||
4919 | // (and joined from undo) | ||||||||||||||
4920 | ++nDeleteTextNodes; | ||||||||||||||
4921 | |||||||||||||||
4922 | const sal_Int32 nContentEnd = pEnd->nContent.GetIndex(); | ||||||||||||||
4923 | { | ||||||||||||||
4924 | ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo()); | ||||||||||||||
4925 | rDoc.getIDocumentContentOperations().SplitNode( rPos, false ); | ||||||||||||||
4926 | } | ||||||||||||||
4927 | |||||||||||||||
4928 | if (bCanMoveBack && rPos == *pCopyPam->GetPoint()) | ||||||||||||||
4929 | { | ||||||||||||||
4930 | // after the SplitNode, span the CpyPam correctly again | ||||||||||||||
4931 | pCopyPam->Move( fnMoveBackward, GoInContent ); | ||||||||||||||
4932 | pCopyPam->Move( fnMoveBackward, GoInContent ); | ||||||||||||||
4933 | } | ||||||||||||||
4934 | |||||||||||||||
4935 | // Correct the area again | ||||||||||||||
4936 | if( bEndEqualIns ) | ||||||||||||||
4937 | aRg.aEnd--; | ||||||||||||||
4938 | // The end would also be moved | ||||||||||||||
4939 | else if( rPos == *pEnd ) | ||||||||||||||
4940 | { | ||||||||||||||
4941 | rPos.nNode-=2; | ||||||||||||||
4942 | rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(), | ||||||||||||||
4943 | nContentEnd ); | ||||||||||||||
4944 | rPos.nNode++; | ||||||||||||||
4945 | aRg.aEnd--; | ||||||||||||||
4946 | } | ||||||||||||||
4947 | } | ||||||||||||||
4948 | else if( bCanMoveBack ) | ||||||||||||||
4949 | { // Insertion at the first position of a text node. It will not be split, the table | ||||||||||||||
4950 | // will be inserted before the text node. | ||||||||||||||
4951 | // See below, before the SetInsertRange function of the undo object will be called, | ||||||||||||||
4952 | // the CpyPam would be moved to the next content position. This has to be avoided | ||||||||||||||
4953 | // We want to be moved to the table node itself thus we have to set bCanMoveBack | ||||||||||||||
4954 | // and to manipulate pCopyPam. | ||||||||||||||
4955 | bCanMoveBack = false; | ||||||||||||||
4956 | pCopyPam->GetPoint()->nNode--; | ||||||||||||||
4957 | } | ||||||||||||||
4958 | } | ||||||||||||||
4959 | |||||||||||||||
4960 | pDestTextNd = aInsPos.GetNode().GetTextNode(); | ||||||||||||||
4961 | if (pEndTextNd
| ||||||||||||||
4962 | { | ||||||||||||||
4963 | SwIndex aDestIdx( rPos.nContent ); | ||||||||||||||
4964 | if( !pDestTextNd ) | ||||||||||||||
4965 | { | ||||||||||||||
4966 | pDestTextNd = rDoc.GetNodes().MakeTextNode( aInsPos, | ||||||||||||||
4967 | rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD)); | ||||||||||||||
4968 | aDestIdx.Assign( pDestTextNd, 0 ); | ||||||||||||||
4969 | aInsPos--; | ||||||||||||||
4970 | |||||||||||||||
4971 | // if we have to insert an extra text node | ||||||||||||||
4972 | // at the destination, this node will be our new destination | ||||||||||||||
4973 | // (text) node, and thus we increment nDeleteTextNodes. This | ||||||||||||||
4974 | // will ensure that this node will be deleted during Undo. | ||||||||||||||
4975 | ++nDeleteTextNodes; // must be deleted | ||||||||||||||
4976 | } | ||||||||||||||
4977 | |||||||||||||||
4978 | const bool bEmptyDestNd = pDestTextNd->GetText().isEmpty(); | ||||||||||||||
4979 | |||||||||||||||
4980 | NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr <SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState = SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem> aListIdItem; | ||||||||||||||
4981 | if( bCopyCollFormat && ( bOneNode || bEmptyDestNd )) | ||||||||||||||
4982 | { | ||||||||||||||
4983 | PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd ); | ||||||||||||||
4984 | } | ||||||||||||||
4985 | |||||||||||||||
4986 | pEndTextNd->CopyText( pDestTextNd, aDestIdx, SwIndex( pEndTextNd ), | ||||||||||||||
4987 | pEnd->nContent.GetIndex() ); | ||||||||||||||
4988 | |||||||||||||||
4989 | // Also copy all format templates | ||||||||||||||
4990 | if( bCopyCollFormat && ( bOneNode || bEmptyDestNd )) | ||||||||||||||
4991 | { | ||||||||||||||
4992 | pEndTextNd->CopyCollFormat( *pDestTextNd ); | ||||||||||||||
4993 | if ( bOneNode ) | ||||||||||||||
4994 | { | ||||||||||||||
4995 | POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState , aListIdItem, pDestTextNd, rPam ); | ||||||||||||||
4996 | } | ||||||||||||||
4997 | } | ||||||||||||||
4998 | } | ||||||||||||||
4999 | |||||||||||||||
5000 | SfxItemSet aBrkSet( rDoc.GetAttrPool(), aBreakSetRange ); | ||||||||||||||
5001 | if ((flags & SwCopyFlags::CopyAll) || aRg.aStart != aRg.aEnd) | ||||||||||||||
5002 | { | ||||||||||||||
5003 | if (pSttTextNd && bCopyCollFormat && pDestTextNd->HasSwAttrSet()) | ||||||||||||||
5004 | { | ||||||||||||||
5005 | aBrkSet.Put( *pDestTextNd->GetpSwAttrSet() ); | ||||||||||||||
5006 | if( SfxItemState::SET == aBrkSet.GetItemState( RES_BREAK, false ) ) | ||||||||||||||
5007 | pDestTextNd->ResetAttr( RES_BREAK ); | ||||||||||||||
5008 | if( SfxItemState::SET == aBrkSet.GetItemState( RES_PAGEDESC, false ) ) | ||||||||||||||
5009 | pDestTextNd->ResetAttr( RES_PAGEDESC ); | ||||||||||||||
5010 | } | ||||||||||||||
5011 | } | ||||||||||||||
5012 | |||||||||||||||
5013 | { | ||||||||||||||
5014 | SwPosition startPos(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1), | ||||||||||||||
5015 | SwIndex(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1).GetNode().GetContentNode())); | ||||||||||||||
5016 | if (bCanMoveBack
| ||||||||||||||
5017 | { // pCopyPam is actually 1 before the copy range so move it fwd | ||||||||||||||
5018 | SwPaM temp(*pCopyPam->GetPoint()); | ||||||||||||||
5019 | temp.Move(fnMoveForward, GoInContent); | ||||||||||||||
5020 | startPos = *temp.GetPoint(); | ||||||||||||||
5021 | } | ||||||||||||||
5022 | assert(startPos.nNode.GetNode().IsContentNode())(static_cast <bool> (startPos.nNode.GetNode().IsContentNode ()) ? void (0) : __assert_fail ("startPos.nNode.GetNode().IsContentNode()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 5022, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
5023 | std::pair<SwPaM const&, SwPosition const&> tmp(rPam, startPos); | ||||||||||||||
5024 | if( aInsPos == pEnd->nNode ) | ||||||||||||||
5025 | { | ||||||||||||||
5026 | SwNodeIndex aSaveIdx( aInsPos, -1 ); | ||||||||||||||
5027 | assert(pStt->nNode != pEnd->nNode)(static_cast <bool> (pStt->nNode != pEnd->nNode) ? void (0) : __assert_fail ("pStt->nNode != pEnd->nNode" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 5027, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
5028 | pEnd->nContent = 0; // TODO why this? | ||||||||||||||
5029 | CopyWithFlyInFly(aRg, aInsPos, &tmp, /*bMakeNewFrames*/true, false, /*bCopyFlyAtFly=*/false, flags); | ||||||||||||||
5030 | ++aSaveIdx; | ||||||||||||||
5031 | pEnd->nNode = aSaveIdx; | ||||||||||||||
5032 | pEnd->nContent.Assign( aSaveIdx.GetNode().GetTextNode(), 0 ); | ||||||||||||||
5033 | } | ||||||||||||||
5034 | else | ||||||||||||||
5035 | CopyWithFlyInFly(aRg, aInsPos, &tmp, /*bMakeNewFrames*/true, false, /*bCopyFlyAtFly=*/false, flags); | ||||||||||||||
5036 | |||||||||||||||
5037 | bCopyBookmarks = false; | ||||||||||||||
5038 | } | ||||||||||||||
5039 | |||||||||||||||
5040 | // at-char anchors post SplitNode are on index 0 of 2nd node and will | ||||||||||||||
5041 | // remain there - move them back to the start (end would also work?) | ||||||||||||||
5042 | // ... also for at-para anchors; here start is preferable because | ||||||||||||||
5043 | // it's consistent with SplitNode from SwUndoInserts::RedoImpl() | ||||||||||||||
5044 | if (pFlysAtInsPos) | ||||||||||||||
5045 | { | ||||||||||||||
5046 | // init *again* - because CopyWithFlyInFly moved startPos | ||||||||||||||
5047 | SwPosition startPos(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1), | ||||||||||||||
5048 | SwIndex(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1).GetNode().GetContentNode())); | ||||||||||||||
5049 | if (bCanMoveBack) | ||||||||||||||
5050 | { // pCopyPam is actually 1 before the copy range so move it fwd | ||||||||||||||
5051 | SwPaM temp(*pCopyPam->GetPoint()); | ||||||||||||||
5052 | temp.Move(fnMoveForward, GoInContent); | ||||||||||||||
5053 | startPos = *temp.GetPoint(); | ||||||||||||||
5054 | } | ||||||||||||||
5055 | assert(startPos.nNode.GetNode().IsContentNode())(static_cast <bool> (startPos.nNode.GetNode().IsContentNode ()) ? void (0) : __assert_fail ("startPos.nNode.GetNode().IsContentNode()" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 5055, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
5056 | SwPosition startPosAtPara(startPos); | ||||||||||||||
5057 | startPosAtPara.nContent.Assign(nullptr, 0); | ||||||||||||||
5058 | |||||||||||||||
5059 | for (SwFrameFormat * pFly : *pFlysAtInsPos) | ||||||||||||||
5060 | { | ||||||||||||||
5061 | SwFormatAnchor const*const pAnchor = &pFly->GetAnchor(); | ||||||||||||||
5062 | if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_CHAR) | ||||||||||||||
5063 | { | ||||||||||||||
5064 | SwFormatAnchor anchor(*pAnchor); | ||||||||||||||
5065 | anchor.SetAnchor( &startPos ); | ||||||||||||||
5066 | pFly->SetFormatAttr(anchor); | ||||||||||||||
5067 | } | ||||||||||||||
5068 | else if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA) | ||||||||||||||
5069 | { | ||||||||||||||
5070 | SwFormatAnchor anchor(*pAnchor); | ||||||||||||||
5071 | anchor.SetAnchor( &startPosAtPara ); | ||||||||||||||
5072 | pFly->SetFormatAttr(anchor); | ||||||||||||||
5073 | } | ||||||||||||||
5074 | } | ||||||||||||||
5075 | } | ||||||||||||||
5076 | |||||||||||||||
5077 | if ((flags & SwCopyFlags::CopyAll) || aRg.aStart != aRg.aEnd) | ||||||||||||||
5078 | { | ||||||||||||||
5079 | // Put the breaks back into the first node | ||||||||||||||
5080 | if( aBrkSet.Count() && nullptr != ( pDestTextNd = rDoc.GetNodes()[ | ||||||||||||||
5081 | pCopyPam->GetPoint()->nNode.GetIndex()+1 ]->GetTextNode())) | ||||||||||||||
5082 | { | ||||||||||||||
5083 | pDestTextNd->SetAttr( aBrkSet ); | ||||||||||||||
5084 | bCopyPageSource = true; | ||||||||||||||
5085 | } | ||||||||||||||
5086 | } | ||||||||||||||
5087 | } while( false ); | ||||||||||||||
5088 | |||||||||||||||
5089 | |||||||||||||||
5090 | // it is not possible to make this test when copy from the clipBoard to document | ||||||||||||||
5091 | // in this case the PageNum not exist anymore | ||||||||||||||
5092 | // tdf#39400 and tdf#97526 | ||||||||||||||
5093 | // when copy from document to ClipBoard, and it is from the first page | ||||||||||||||
5094 | // and not the source has the page break | ||||||||||||||
5095 | if (rDoc.IsClipBoard() && (rPam.GetPageNum(pStt == rPam.GetPoint()) == 1) && !bCopyPageSource) | ||||||||||||||
5096 | { | ||||||||||||||
5097 | pDestTextNd->ResetAttr(RES_BREAK); // remove the page-break | ||||||||||||||
5098 | pDestTextNd->ResetAttr(RES_PAGEDESC); | ||||||||||||||
5099 | } | ||||||||||||||
5100 | |||||||||||||||
5101 | |||||||||||||||
5102 | // Adjust position (in case it was moved / in another node) | ||||||||||||||
5103 | rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(), | ||||||||||||||
5104 | rPos.nContent.GetIndex() ); | ||||||||||||||
5105 | |||||||||||||||
5106 | if( rPos.nNode != aInsPos ) | ||||||||||||||
5107 | { | ||||||||||||||
5108 | pCopyPam->GetMark()->nNode = aInsPos; | ||||||||||||||
5109 | if (aInsPos < rPos.nNode) | ||||||||||||||
5110 | { // tdf#134250 decremented in (pEndTextNd && !pDestTextNd) above | ||||||||||||||
5111 | pCopyPam->GetContentNode(false)->MakeEndIndex(&pCopyPam->GetMark()->nContent); | ||||||||||||||
5112 | } | ||||||||||||||
5113 | else // incremented in (!pSttTextNd && pDestTextNd) above | ||||||||||||||
5114 | { | ||||||||||||||
5115 | pCopyPam->GetMark()->nContent.Assign(pCopyPam->GetContentNode(false), 0); | ||||||||||||||
5116 | } | ||||||||||||||
5117 | rPos = *pCopyPam->GetMark(); | ||||||||||||||
5118 | } | ||||||||||||||
5119 | else | ||||||||||||||
5120 | *pCopyPam->GetMark() = rPos; | ||||||||||||||
5121 | |||||||||||||||
5122 | if ( !bAfterTable
| ||||||||||||||
5123 | pCopyPam->Move( fnMoveForward, bCanMoveBack
| ||||||||||||||
5124 | else | ||||||||||||||
5125 | { | ||||||||||||||
5126 | pCopyPam->GetPoint()->nNode++; | ||||||||||||||
5127 | |||||||||||||||
5128 | // Reset the offset to 0 as it was before the insertion | ||||||||||||||
5129 | pCopyPam->GetPoint()->nContent.Assign(pCopyPam->GetPoint()->nNode.GetNode().GetContentNode(), 0); | ||||||||||||||
5130 | // If the next node is a start node, then step back: the start node | ||||||||||||||
5131 | // has been copied and needs to be in the selection for the undo | ||||||||||||||
5132 | if (pCopyPam->GetPoint()->nNode.GetNode().IsStartNode()) | ||||||||||||||
5133 | pCopyPam->GetPoint()->nNode--; | ||||||||||||||
5134 | |||||||||||||||
5135 | } | ||||||||||||||
5136 | pCopyPam->Exchange(); | ||||||||||||||
5137 | |||||||||||||||
5138 | // Also copy all bookmarks | ||||||||||||||
5139 | if( bCopyBookmarks
| ||||||||||||||
5140 | { | ||||||||||||||
5141 | sw::CopyBookmarks(rPam, *pCopyPam->Start()); | ||||||||||||||
5142 | } | ||||||||||||||
5143 | |||||||||||||||
5144 | if( RedlineFlags::DeleteRedlines & eOld ) | ||||||||||||||
5145 | { | ||||||||||||||
5146 | assert(*pCopyPam->GetPoint() == rPos)(static_cast <bool> (*pCopyPam->GetPoint() == rPos) ? void (0) : __assert_fail ("*pCopyPam->GetPoint() == rPos" , "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx" , 5146, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||||
5147 | // the Node rPos points to may be deleted so unregister ... | ||||||||||||||
5148 | rPos.nContent.Assign(nullptr, 0); | ||||||||||||||
5149 | lcl_DeleteRedlines(rPam, *pCopyPam); | ||||||||||||||
5150 | rPos = *pCopyPam->GetPoint(); // ... and restore. | ||||||||||||||
5151 | } | ||||||||||||||
5152 | |||||||||||||||
5153 | // If Undo is enabled, store the inserted area | ||||||||||||||
5154 | if (rDoc.GetIDocumentUndoRedo().DoesUndo()) | ||||||||||||||
5155 | { | ||||||||||||||
5156 | pUndo->SetInsertRange(*pCopyPam, true, nDeleteTextNodes); | ||||||||||||||
| |||||||||||||||
5157 | } | ||||||||||||||
5158 | |||||||||||||||
5159 | if( pCpyRange ) | ||||||||||||||
5160 | { | ||||||||||||||
5161 | pCpyRange->SetMark(); | ||||||||||||||
5162 | *pCpyRange->GetPoint() = *pCopyPam->GetPoint(); | ||||||||||||||
5163 | *pCpyRange->GetMark() = *pCopyPam->GetMark(); | ||||||||||||||
5164 | } | ||||||||||||||
5165 | |||||||||||||||
5166 | if ( pNumRuleToPropagate != nullptr ) | ||||||||||||||
5167 | { | ||||||||||||||
5168 | // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId> | ||||||||||||||
5169 | // Don't reset indent attributes, that would mean loss of direct | ||||||||||||||
5170 | // formatting. | ||||||||||||||
5171 | rDoc.SetNumRule( *pCopyPam, *pNumRuleToPropagate, false, nullptr, | ||||||||||||||
5172 | aListIdToPropagate, true, /*bResetIndentAttrs=*/false ); | ||||||||||||||
5173 | } | ||||||||||||||
5174 | |||||||||||||||
5175 | rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); | ||||||||||||||
5176 | rDoc.getIDocumentState().SetModified(); | ||||||||||||||
5177 | |||||||||||||||
5178 | return true; | ||||||||||||||
5179 | } | ||||||||||||||
5180 | |||||||||||||||
5181 | |||||||||||||||
5182 | } | ||||||||||||||
5183 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_SW_INC_PAM_HXX |
20 | #define INCLUDED_SW_INC_PAM_HXX |
21 | |
22 | #include <sal/types.h> |
23 | #include "ring.hxx" |
24 | #include "index.hxx" |
25 | #include "ndindex.hxx" |
26 | #include "swdllapi.h" |
27 | |
28 | #include <iostream> |
29 | |
30 | class SwDoc; |
31 | class SwPaM; |
32 | class Point; |
33 | |
34 | /// Marks a position in the document model. |
35 | struct SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPosition |
36 | { |
37 | SwNodeIndex nNode; |
38 | SwIndex nContent; |
39 | |
40 | SwPosition( const SwNodeIndex &rNode, const SwIndex &rContent ); |
41 | explicit SwPosition( const SwNodeIndex &rNode ); |
42 | explicit SwPosition( const SwNode& rNode ); |
43 | explicit SwPosition( SwContentNode& rNode, const sal_Int32 nOffset = 0 ); |
44 | |
45 | /** |
46 | Returns the document this position is in. |
47 | |
48 | @return the document this position is in. |
49 | */ |
50 | SwDoc& GetDoc() const; |
51 | |
52 | bool operator < (const SwPosition &) const; |
53 | bool operator > (const SwPosition &) const; |
54 | bool operator <=(const SwPosition &) const; |
55 | bool operator >=(const SwPosition &) const; |
56 | bool operator ==(const SwPosition &) const; |
57 | bool operator !=(const SwPosition &) const; |
58 | void dumpAsXml(xmlTextWriterPtr pWriter) const; |
59 | }; |
60 | |
61 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPosition& position); |
62 | |
63 | // Result of comparing positions. |
64 | enum class SwComparePosition { |
65 | Before, ///< Pos1 before Pos2. |
66 | Behind, ///< Pos1 behind Pos2. |
67 | Inside, ///< Pos1 completely contained in Pos2. |
68 | Outside, ///< Pos2 completely contained in Pos1. |
69 | Equal, ///< Pos1 is as large as Pos2. |
70 | OverlapBefore, ///< Pos1 overlaps Pos2 at the beginning. |
71 | OverlapBehind, ///< Pos1 overlaps Pos2 at the end. |
72 | CollideStart, ///< Pos1 start touches at Pos2 end. |
73 | CollideEnd ///< Pos1 end touches at Pos2 start. |
74 | }; |
75 | |
76 | template<typename T> |
77 | SwComparePosition ComparePosition( |
78 | const T& rStt1, const T& rEnd1, |
79 | const T& rStt2, const T& rEnd2 ) |
80 | { |
81 | SwComparePosition nRet; |
82 | if( rStt1 < rStt2 ) |
83 | { |
84 | if( rEnd1 > rStt2 ) |
85 | { |
86 | if( rEnd1 >= rEnd2 ) |
87 | nRet = SwComparePosition::Outside; |
88 | else |
89 | nRet = SwComparePosition::OverlapBefore; |
90 | |
91 | } |
92 | else if( rEnd1 == rStt2 ) |
93 | nRet = SwComparePosition::CollideEnd; |
94 | else |
95 | nRet = SwComparePosition::Before; |
96 | } |
97 | else if( rEnd2 > rStt1 ) |
98 | { |
99 | if( rEnd2 >= rEnd1 ) |
100 | { |
101 | if( rEnd2 == rEnd1 && rStt2 == rStt1 ) |
102 | nRet = SwComparePosition::Equal; |
103 | else |
104 | nRet = SwComparePosition::Inside; |
105 | } |
106 | else |
107 | { |
108 | if (rStt1 == rStt2) |
109 | nRet = SwComparePosition::Outside; |
110 | else |
111 | nRet = SwComparePosition::OverlapBehind; |
112 | } |
113 | } |
114 | else if( rEnd2 == rStt1 ) |
115 | nRet = SwComparePosition::CollideStart; |
116 | else |
117 | nRet = SwComparePosition::Behind; |
118 | return nRet; |
119 | } |
120 | |
121 | /// SwPointAndMark / SwPaM |
122 | struct SwMoveFnCollection; |
123 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument. |
124 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveBackward; |
125 | |
126 | using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool; |
127 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInDoc( SwPaM&, SwMoveFnCollection const &); |
128 | bool GoInSection( SwPaM&, SwMoveFnCollection const &); |
129 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInNode( SwPaM&, SwMoveFnCollection const &); |
130 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInContent( SwPaM&, SwMoveFnCollection const &); |
131 | bool GoInContentCells( SwPaM&, SwMoveFnCollection const &); |
132 | bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &); |
133 | bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &); |
134 | |
135 | /// PaM is Point and Mark: a selection of the document model. |
136 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPaM : public sw::Ring<SwPaM> |
137 | { |
138 | SwPosition m_Bound1; |
139 | SwPosition m_Bound2; |
140 | SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2 |
141 | SwPosition * m_pMark; ///< points at either m_Bound1 or m_Bound2 |
142 | bool m_bIsInFrontOfLabel; |
143 | |
144 | SwPaM(SwPaM const& rPaM) = delete; |
145 | |
146 | public: |
147 | explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr ); |
148 | SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr ); |
149 | SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt, |
150 | long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr ); |
151 | SwPaM( const SwNode& rMk, const SwNode& rPt, |
152 | long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr ); |
153 | SwPaM( const SwNodeIndex& rMk, sal_Int32 nMkContent, |
154 | const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr ); |
155 | SwPaM( const SwNode& rMk, sal_Int32 nMkContent, |
156 | const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr ); |
157 | SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr ); |
158 | SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr ); |
159 | virtual ~SwPaM() override; |
160 | |
161 | /// this takes a second parameter, which indicates the Ring that |
162 | /// the new PaM should be part of (may be null) |
163 | SwPaM(SwPaM const& rPaM, SwPaM * pRing); |
164 | /// @@@ semantic: no copy assignment for super class Ring. |
165 | SwPaM& operator=( const SwPaM & ); |
166 | |
167 | /// Movement of cursor. |
168 | bool Move( SwMoveFnCollection const & fnMove = fnMoveForward, |
169 | SwGoInDoc fnGo = GoInContent ); |
170 | |
171 | bool IsInFrontOfLabel() const { return m_bIsInFrontOfLabel; } |
172 | void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; } |
173 | |
174 | /// Unless this is called, the getter method of Mark will return Point. |
175 | virtual void SetMark(); |
176 | |
177 | void DeleteMark() |
178 | { |
179 | if (m_pMark != m_pPoint) |
180 | { |
181 | /** clear the mark position; this helps if mark's SwIndex is |
182 | registered at some node, and that node is then deleted */ |
183 | *m_pMark = SwPosition( SwNodeIndex( GetNode().GetNodes() ) ); |
184 | m_pMark = m_pPoint; |
185 | } |
186 | } |
187 | #ifdef DBG_UTIL |
188 | void Exchange(); |
189 | |
190 | #else |
191 | void Exchange() |
192 | { |
193 | if (m_pPoint != m_pMark) |
194 | { |
195 | SwPosition *pTmp = m_pPoint; |
196 | m_pPoint = m_pMark; |
197 | m_pMark = pTmp; |
198 | } |
199 | } |
200 | #endif |
201 | |
202 | /** A PaM marks a selection if Point and Mark are distinct positions. |
203 | @return true if the PaM spans a selection |
204 | */ |
205 | bool HasMark() const { return m_pPoint != m_pMark; } |
206 | |
207 | const SwPosition *GetPoint() const { return m_pPoint; } |
208 | SwPosition *GetPoint() { return m_pPoint; } |
209 | const SwPosition *GetMark() const { return m_pMark; } |
210 | SwPosition *GetMark() { return m_pMark; } |
211 | |
212 | const SwPosition *Start() const |
213 | { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; } |
214 | SwPosition *Start() |
215 | { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; } |
216 | |
217 | const SwPosition *End() const |
218 | { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; } |
219 | SwPosition *End() |
220 | { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; } |
221 | |
222 | /// @return current Node at Point/Mark |
223 | SwNode & GetNode ( bool bPoint = true ) const |
224 | { |
225 | return ( bPoint ? m_pPoint->nNode : m_pMark->nNode ).GetNode(); |
226 | } |
227 | |
228 | /// @return current ContentNode at Point/Mark |
229 | SwContentNode* GetContentNode( bool bPoint = true ) const |
230 | { |
231 | return GetNode(bPoint).GetContentNode(); |
232 | } |
233 | |
234 | /** |
235 | Normalizes PaM, i.e. sort point and mark. |
236 | |
237 | @param bPointFirst true: If the point is behind the mark then swap. |
238 | false: If the mark is behind the point then swap. |
239 | */ |
240 | void Normalize(bool bPointFirst = true); |
241 | |
242 | /// @return the document (SwDoc) at which the PaM is registered |
243 | SwDoc& GetDoc() const { return m_pPoint->nNode.GetNode().GetDoc(); } |
244 | |
245 | SwPosition& GetBound( bool bOne = true ) |
246 | { return bOne ? m_Bound1 : m_Bound2; } |
247 | const SwPosition& GetBound( bool bOne = true ) const |
248 | { return bOne ? m_Bound1 : m_Bound2; } |
249 | |
250 | /// Get number of page which contains cursor. |
251 | sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr ); |
252 | |
253 | /** Is in something protected (readonly) or selection contains |
254 | something protected. */ |
255 | bool HasReadonlySel( bool bFormView ) const; |
256 | |
257 | bool ContainsPosition(const SwPosition & rPos) const |
258 | { |
259 | return *Start() <= rPos && rPos <= *End(); |
260 | } |
261 | |
262 | OUString GetText() const; |
263 | void InvalidatePaM(); |
264 | SwPaM* GetNext() |
265 | { return GetNextInRing(); } |
266 | const SwPaM* GetNext() const |
267 | { return GetNextInRing(); } |
268 | SwPaM* GetPrev() |
269 | { return GetPrevInRing(); } |
270 | const SwPaM* GetPrev() const |
271 | { return GetPrevInRing(); } |
272 | bool IsMultiSelection() const |
273 | { return !unique(); } |
274 | |
275 | void dumpAsXml(xmlTextWriterPtr pWriter) const; |
276 | }; |
277 | |
278 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPaM& pam); |
279 | |
280 | bool CheckNodesRange(const SwNodeIndex&, const SwNodeIndex&, bool bChkSection); |
281 | |
282 | #endif // INCLUDED_SW_INC_PAM_HXX |
283 | |
284 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | // unique_ptr implementation -*- C++ -*- | ||||||||||||||
2 | |||||||||||||||
3 | // Copyright (C) 2008-2020 Free Software Foundation, Inc. | ||||||||||||||
4 | // | ||||||||||||||
5 | // This file is part of the GNU ISO C++ Library. This library is free | ||||||||||||||
6 | // software; you can redistribute it and/or modify it under the | ||||||||||||||
7 | // terms of the GNU General Public License as published by the | ||||||||||||||
8 | // Free Software Foundation; either version 3, or (at your option) | ||||||||||||||
9 | // any later version. | ||||||||||||||
10 | |||||||||||||||
11 | // This library is distributed in the hope that it will be useful, | ||||||||||||||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||||||||||
14 | // GNU General Public License for more details. | ||||||||||||||
15 | |||||||||||||||
16 | // Under Section 7 of GPL version 3, you are granted additional | ||||||||||||||
17 | // permissions described in the GCC Runtime Library Exception, version | ||||||||||||||
18 | // 3.1, as published by the Free Software Foundation. | ||||||||||||||
19 | |||||||||||||||
20 | // You should have received a copy of the GNU General Public License and | ||||||||||||||
21 | // a copy of the GCC Runtime Library Exception along with this program; | ||||||||||||||
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | ||||||||||||||
23 | // <http://www.gnu.org/licenses/>. | ||||||||||||||
24 | |||||||||||||||
25 | /** @file bits/unique_ptr.h | ||||||||||||||
26 | * This is an internal header file, included by other library headers. | ||||||||||||||
27 | * Do not attempt to use it directly. @headername{memory} | ||||||||||||||
28 | */ | ||||||||||||||
29 | |||||||||||||||
30 | #ifndef _UNIQUE_PTR_H1 | ||||||||||||||
31 | #define _UNIQUE_PTR_H1 1 | ||||||||||||||
32 | |||||||||||||||
33 | #include <bits/c++config.h> | ||||||||||||||
34 | #include <debug/assertions.h> | ||||||||||||||
35 | #include <type_traits> | ||||||||||||||
36 | #include <utility> | ||||||||||||||
37 | #include <tuple> | ||||||||||||||
38 | #include <bits/stl_function.h> | ||||||||||||||
39 | #include <bits/functional_hash.h> | ||||||||||||||
40 | #if __cplusplus201703L > 201703L | ||||||||||||||
41 | # include <compare> | ||||||||||||||
42 | # include <ostream> | ||||||||||||||
43 | #endif | ||||||||||||||
44 | |||||||||||||||
45 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) | ||||||||||||||
46 | { | ||||||||||||||
47 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | ||||||||||||||
48 | |||||||||||||||
49 | /** | ||||||||||||||
50 | * @addtogroup pointer_abstractions | ||||||||||||||
51 | * @{ | ||||||||||||||
52 | */ | ||||||||||||||
53 | |||||||||||||||
54 | #if _GLIBCXX_USE_DEPRECATED1 | ||||||||||||||
55 | #pragma GCC diagnostic push | ||||||||||||||
56 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | ||||||||||||||
57 | template<typename> class auto_ptr; | ||||||||||||||
58 | #pragma GCC diagnostic pop | ||||||||||||||
59 | #endif | ||||||||||||||
60 | |||||||||||||||
61 | /// Primary template of default_delete, used by unique_ptr for single objects | ||||||||||||||
62 | template<typename _Tp> | ||||||||||||||
63 | struct default_delete | ||||||||||||||
64 | { | ||||||||||||||
65 | /// Default constructor | ||||||||||||||
66 | constexpr default_delete() noexcept = default; | ||||||||||||||
67 | |||||||||||||||
68 | /** @brief Converting constructor. | ||||||||||||||
69 | * | ||||||||||||||
70 | * Allows conversion from a deleter for objects of another type, `_Up`, | ||||||||||||||
71 | * only if `_Up*` is convertible to `_Tp*`. | ||||||||||||||
72 | */ | ||||||||||||||
73 | template<typename _Up, | ||||||||||||||
74 | typename = _Require<is_convertible<_Up*, _Tp*>>> | ||||||||||||||
75 | default_delete(const default_delete<_Up>&) noexcept { } | ||||||||||||||
76 | |||||||||||||||
77 | /// Calls `delete __ptr` | ||||||||||||||
78 | void | ||||||||||||||
79 | operator()(_Tp* __ptr) const | ||||||||||||||
80 | { | ||||||||||||||
81 | static_assert(!is_void<_Tp>::value, | ||||||||||||||
82 | "can't delete pointer to incomplete type"); | ||||||||||||||
83 | static_assert(sizeof(_Tp)>0, | ||||||||||||||
84 | "can't delete pointer to incomplete type"); | ||||||||||||||
85 | delete __ptr; | ||||||||||||||
86 | } | ||||||||||||||
87 | }; | ||||||||||||||
88 | |||||||||||||||
89 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | ||||||||||||||
90 | // DR 740 - omit specialization for array objects with a compile time length | ||||||||||||||
91 | |||||||||||||||
92 | /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>` | ||||||||||||||
93 | template<typename _Tp> | ||||||||||||||
94 | struct default_delete<_Tp[]> | ||||||||||||||
95 | { | ||||||||||||||
96 | public: | ||||||||||||||
97 | /// Default constructor | ||||||||||||||
98 | constexpr default_delete() noexcept = default; | ||||||||||||||
99 | |||||||||||||||
100 | /** @brief Converting constructor. | ||||||||||||||
101 | * | ||||||||||||||
102 | * Allows conversion from a deleter for arrays of another type, such as | ||||||||||||||
103 | * a const-qualified version of `_Tp`. | ||||||||||||||
104 | * | ||||||||||||||
105 | * Conversions from types derived from `_Tp` are not allowed because | ||||||||||||||
106 | * it is undefined to `delete[]` an array of derived types through a | ||||||||||||||
107 | * pointer to the base type. | ||||||||||||||
108 | */ | ||||||||||||||
109 | template<typename _Up, | ||||||||||||||
110 | typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>> | ||||||||||||||
111 | default_delete(const default_delete<_Up[]>&) noexcept { } | ||||||||||||||
112 | |||||||||||||||
113 | /// Calls `delete[] __ptr` | ||||||||||||||
114 | template<typename _Up> | ||||||||||||||
115 | typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type | ||||||||||||||
116 | operator()(_Up* __ptr) const | ||||||||||||||
117 | { | ||||||||||||||
118 | static_assert(sizeof(_Tp)>0, | ||||||||||||||
119 | "can't delete pointer to incomplete type"); | ||||||||||||||
120 | delete [] __ptr; | ||||||||||||||
121 | } | ||||||||||||||
122 | }; | ||||||||||||||
123 | |||||||||||||||
124 | /// @cond undocumented | ||||||||||||||
125 | |||||||||||||||
126 | // Manages the pointer and deleter of a unique_ptr | ||||||||||||||
127 | template <typename _Tp, typename _Dp> | ||||||||||||||
128 | class __uniq_ptr_impl | ||||||||||||||
129 | { | ||||||||||||||
130 | template <typename _Up, typename _Ep, typename = void> | ||||||||||||||
131 | struct _Ptr | ||||||||||||||
132 | { | ||||||||||||||
133 | using type = _Up*; | ||||||||||||||
134 | }; | ||||||||||||||
135 | |||||||||||||||
136 | template <typename _Up, typename _Ep> | ||||||||||||||
137 | struct | ||||||||||||||
138 | _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>> | ||||||||||||||
139 | { | ||||||||||||||
140 | using type = typename remove_reference<_Ep>::type::pointer; | ||||||||||||||
141 | }; | ||||||||||||||
142 | |||||||||||||||
143 | public: | ||||||||||||||
144 | using _DeleterConstraint = enable_if< | ||||||||||||||
145 | __and_<__not_<is_pointer<_Dp>>, | ||||||||||||||
146 | is_default_constructible<_Dp>>::value>; | ||||||||||||||
147 | |||||||||||||||
148 | using pointer = typename _Ptr<_Tp, _Dp>::type; | ||||||||||||||
149 | |||||||||||||||
150 | static_assert( !is_rvalue_reference<_Dp>::value, | ||||||||||||||
151 | "unique_ptr's deleter type must be a function object type" | ||||||||||||||
152 | " or an lvalue reference type" ); | ||||||||||||||
153 | |||||||||||||||
154 | __uniq_ptr_impl() = default; | ||||||||||||||
155 | __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } | ||||||||||||||
156 | |||||||||||||||
157 | template<typename _Del> | ||||||||||||||
158 | __uniq_ptr_impl(pointer __p, _Del&& __d) | ||||||||||||||
159 | : _M_t(__p, std::forward<_Del>(__d)) { } | ||||||||||||||
160 | |||||||||||||||
161 | __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept | ||||||||||||||
162 | : _M_t(std::move(__u._M_t)) | ||||||||||||||
163 | { __u._M_ptr() = nullptr; } | ||||||||||||||
164 | |||||||||||||||
165 | __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept | ||||||||||||||
166 | { | ||||||||||||||
167 | reset(__u.release()); | ||||||||||||||
168 | _M_deleter() = std::forward<_Dp>(__u._M_deleter()); | ||||||||||||||
169 | return *this; | ||||||||||||||
170 | } | ||||||||||||||
171 | |||||||||||||||
172 | pointer& _M_ptr() { return std::get<0>(_M_t); } | ||||||||||||||
173 | pointer _M_ptr() const { return std::get<0>(_M_t); } | ||||||||||||||
174 | _Dp& _M_deleter() { return std::get<1>(_M_t); } | ||||||||||||||
175 | const _Dp& _M_deleter() const { return std::get<1>(_M_t); } | ||||||||||||||
176 | |||||||||||||||
177 | void reset(pointer __p) noexcept | ||||||||||||||
178 | { | ||||||||||||||
179 | const pointer __old_p = _M_ptr(); | ||||||||||||||
180 | _M_ptr() = __p; | ||||||||||||||
181 | if (__old_p
| ||||||||||||||
182 | _M_deleter()(__old_p); | ||||||||||||||
183 | } | ||||||||||||||
184 | |||||||||||||||
185 | pointer release() noexcept | ||||||||||||||
186 | { | ||||||||||||||
187 | pointer __p = _M_ptr(); | ||||||||||||||
188 | _M_ptr() = nullptr; | ||||||||||||||
189 | return __p; | ||||||||||||||
190 | } | ||||||||||||||
191 | |||||||||||||||
192 | void | ||||||||||||||
193 | swap(__uniq_ptr_impl& __rhs) noexcept | ||||||||||||||
194 | { | ||||||||||||||
195 | using std::swap; | ||||||||||||||
196 | swap(this->_M_ptr(), __rhs._M_ptr()); | ||||||||||||||
197 | swap(this->_M_deleter(), __rhs._M_deleter()); | ||||||||||||||
198 | } | ||||||||||||||
199 | |||||||||||||||
200 | private: | ||||||||||||||
201 | tuple<pointer, _Dp> _M_t; | ||||||||||||||
202 | }; | ||||||||||||||
203 | |||||||||||||||
204 | // Defines move construction + assignment as either defaulted or deleted. | ||||||||||||||
205 | template <typename _Tp, typename _Dp, | ||||||||||||||
206 | bool = is_move_constructible<_Dp>::value, | ||||||||||||||
207 | bool = is_move_assignable<_Dp>::value> | ||||||||||||||
208 | struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp> | ||||||||||||||
209 | { | ||||||||||||||
210 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; | ||||||||||||||
211 | __uniq_ptr_data(__uniq_ptr_data&&) = default; | ||||||||||||||
212 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; | ||||||||||||||
213 | }; | ||||||||||||||
214 | |||||||||||||||
215 | template <typename _Tp, typename _Dp> | ||||||||||||||
216 | struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp> | ||||||||||||||
217 | { | ||||||||||||||
218 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; | ||||||||||||||
219 | __uniq_ptr_data(__uniq_ptr_data&&) = default; | ||||||||||||||
220 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; | ||||||||||||||
221 | }; | ||||||||||||||
222 | |||||||||||||||
223 | template <typename _Tp, typename _Dp> | ||||||||||||||
224 | struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp> | ||||||||||||||
225 | { | ||||||||||||||
226 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; | ||||||||||||||
227 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; | ||||||||||||||
228 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; | ||||||||||||||
229 | }; | ||||||||||||||
230 | |||||||||||||||
231 | template <typename _Tp, typename _Dp> | ||||||||||||||
232 | struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp> | ||||||||||||||
233 | { | ||||||||||||||
234 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; | ||||||||||||||
235 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; | ||||||||||||||
236 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; | ||||||||||||||
237 | }; | ||||||||||||||
238 | /// @endcond | ||||||||||||||
239 | |||||||||||||||
240 | /// 20.7.1.2 unique_ptr for single objects. | ||||||||||||||
241 | template <typename _Tp, typename _Dp = default_delete<_Tp>> | ||||||||||||||
242 | class unique_ptr | ||||||||||||||
243 | { | ||||||||||||||
244 | template <typename _Up> | ||||||||||||||
245 | using _DeleterConstraint = | ||||||||||||||
246 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; | ||||||||||||||
247 | |||||||||||||||
248 | __uniq_ptr_data<_Tp, _Dp> _M_t; | ||||||||||||||
249 | |||||||||||||||
250 | public: | ||||||||||||||
251 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; | ||||||||||||||
252 | using element_type = _Tp; | ||||||||||||||
253 | using deleter_type = _Dp; | ||||||||||||||
254 | |||||||||||||||
255 | private: | ||||||||||||||
256 | // helper template for detecting a safe conversion from another | ||||||||||||||
257 | // unique_ptr | ||||||||||||||
258 | template<typename _Up, typename _Ep> | ||||||||||||||
259 | using __safe_conversion_up = __and_< | ||||||||||||||
260 | is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, | ||||||||||||||
261 | __not_<is_array<_Up>> | ||||||||||||||
262 | >; | ||||||||||||||
263 | |||||||||||||||
264 | public: | ||||||||||||||
265 | // Constructors. | ||||||||||||||
266 | |||||||||||||||
267 | /// Default constructor, creates a unique_ptr that owns nothing. | ||||||||||||||
268 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> | ||||||||||||||
269 | constexpr unique_ptr() noexcept | ||||||||||||||
270 | : _M_t() | ||||||||||||||
271 | { } | ||||||||||||||
272 | |||||||||||||||
273 | /** Takes ownership of a pointer. | ||||||||||||||
274 | * | ||||||||||||||
275 | * @param __p A pointer to an object of @c element_type | ||||||||||||||
276 | * | ||||||||||||||
277 | * The deleter will be value-initialized. | ||||||||||||||
278 | */ | ||||||||||||||
279 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> | ||||||||||||||
280 | explicit | ||||||||||||||
281 | unique_ptr(pointer __p) noexcept | ||||||||||||||
282 | : _M_t(__p) | ||||||||||||||
283 | { } | ||||||||||||||
284 | |||||||||||||||
285 | /** Takes ownership of a pointer. | ||||||||||||||
286 | * | ||||||||||||||
287 | * @param __p A pointer to an object of @c element_type | ||||||||||||||
288 | * @param __d A reference to a deleter. | ||||||||||||||
289 | * | ||||||||||||||
290 | * The deleter will be initialized with @p __d | ||||||||||||||
291 | */ | ||||||||||||||
292 | template<typename _Del = deleter_type, | ||||||||||||||
293 | typename = _Require<is_copy_constructible<_Del>>> | ||||||||||||||
294 | unique_ptr(pointer __p, const deleter_type& __d) noexcept | ||||||||||||||
295 | : _M_t(__p, __d) { } | ||||||||||||||
296 | |||||||||||||||
297 | /** Takes ownership of a pointer. | ||||||||||||||
298 | * | ||||||||||||||
299 | * @param __p A pointer to an object of @c element_type | ||||||||||||||
300 | * @param __d An rvalue reference to a (non-reference) deleter. | ||||||||||||||
301 | * | ||||||||||||||
302 | * The deleter will be initialized with @p std::move(__d) | ||||||||||||||
303 | */ | ||||||||||||||
304 | template<typename _Del = deleter_type, | ||||||||||||||
305 | typename = _Require<is_move_constructible<_Del>>> | ||||||||||||||
306 | unique_ptr(pointer __p, | ||||||||||||||
307 | __enable_if_t<!is_lvalue_reference<_Del>::value, | ||||||||||||||
308 | _Del&&> __d) noexcept | ||||||||||||||
309 | : _M_t(__p, std::move(__d)) | ||||||||||||||
310 | { } | ||||||||||||||
311 | |||||||||||||||
312 | template<typename _Del = deleter_type, | ||||||||||||||
313 | typename _DelUnref = typename remove_reference<_Del>::type> | ||||||||||||||
314 | unique_ptr(pointer, | ||||||||||||||
315 | __enable_if_t<is_lvalue_reference<_Del>::value, | ||||||||||||||
316 | _DelUnref&&>) = delete; | ||||||||||||||
317 | |||||||||||||||
318 | /// Creates a unique_ptr that owns nothing. | ||||||||||||||
319 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> | ||||||||||||||
320 | constexpr unique_ptr(nullptr_t) noexcept | ||||||||||||||
321 | : _M_t() | ||||||||||||||
322 | { } | ||||||||||||||
323 | |||||||||||||||
324 | // Move constructors. | ||||||||||||||
325 | |||||||||||||||
326 | /// Move constructor. | ||||||||||||||
327 | unique_ptr(unique_ptr&&) = default; | ||||||||||||||
328 | |||||||||||||||
329 | /** @brief Converting constructor from another type | ||||||||||||||
330 | * | ||||||||||||||
331 | * Requires that the pointer owned by @p __u is convertible to the | ||||||||||||||
332 | * type of pointer owned by this object, @p __u does not own an array, | ||||||||||||||
333 | * and @p __u has a compatible deleter type. | ||||||||||||||
334 | */ | ||||||||||||||
335 | template<typename _Up, typename _Ep, typename = _Require< | ||||||||||||||
336 | __safe_conversion_up<_Up, _Ep>, | ||||||||||||||
337 | typename conditional<is_reference<_Dp>::value, | ||||||||||||||
338 | is_same<_Ep, _Dp>, | ||||||||||||||
339 | is_convertible<_Ep, _Dp>>::type>> | ||||||||||||||
340 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept | ||||||||||||||
341 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) | ||||||||||||||
342 | { } | ||||||||||||||
343 | |||||||||||||||
344 | #if _GLIBCXX_USE_DEPRECATED1 | ||||||||||||||
345 | #pragma GCC diagnostic push | ||||||||||||||
346 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | ||||||||||||||
347 | /// Converting constructor from @c auto_ptr | ||||||||||||||
348 | template<typename _Up, typename = _Require< | ||||||||||||||
349 | is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>> | ||||||||||||||
350 | unique_ptr(auto_ptr<_Up>&& __u) noexcept; | ||||||||||||||
351 | #pragma GCC diagnostic pop | ||||||||||||||
352 | #endif | ||||||||||||||
353 | |||||||||||||||
354 | /// Destructor, invokes the deleter if the stored pointer is not null. | ||||||||||||||
355 | ~unique_ptr() noexcept | ||||||||||||||
356 | { | ||||||||||||||
357 | static_assert(__is_invocable<deleter_type&, pointer>::value, | ||||||||||||||
358 | "unique_ptr's deleter must be invocable with a pointer"); | ||||||||||||||
359 | auto& __ptr = _M_t._M_ptr(); | ||||||||||||||
360 | if (__ptr != nullptr) | ||||||||||||||
361 | get_deleter()(std::move(__ptr)); | ||||||||||||||
362 | __ptr = pointer(); | ||||||||||||||
363 | } | ||||||||||||||
364 | |||||||||||||||
365 | // Assignment. | ||||||||||||||
366 | |||||||||||||||
367 | /** @brief Move assignment operator. | ||||||||||||||
368 | * | ||||||||||||||
369 | * Invokes the deleter if this object owns a pointer. | ||||||||||||||
370 | */ | ||||||||||||||
371 | unique_ptr& operator=(unique_ptr&&) = default; | ||||||||||||||
372 | |||||||||||||||
373 | /** @brief Assignment from another type. | ||||||||||||||
374 | * | ||||||||||||||
375 | * @param __u The object to transfer ownership from, which owns a | ||||||||||||||
376 | * convertible pointer to a non-array object. | ||||||||||||||
377 | * | ||||||||||||||
378 | * Invokes the deleter if this object owns a pointer. | ||||||||||||||
379 | */ | ||||||||||||||
380 | template<typename _Up, typename _Ep> | ||||||||||||||
381 | typename enable_if< __and_< | ||||||||||||||
382 | __safe_conversion_up<_Up, _Ep>, | ||||||||||||||
383 | is_assignable<deleter_type&, _Ep&&> | ||||||||||||||
384 | >::value, | ||||||||||||||
385 | unique_ptr&>::type | ||||||||||||||
386 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept | ||||||||||||||
387 | { | ||||||||||||||
388 | reset(__u.release()); | ||||||||||||||
389 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); | ||||||||||||||
390 | return *this; | ||||||||||||||
391 | } | ||||||||||||||
392 | |||||||||||||||
393 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. | ||||||||||||||
394 | unique_ptr& | ||||||||||||||
395 | operator=(nullptr_t) noexcept | ||||||||||||||
396 | { | ||||||||||||||
397 | reset(); | ||||||||||||||
398 | return *this; | ||||||||||||||
399 | } | ||||||||||||||
400 | |||||||||||||||
401 | // Observers. | ||||||||||||||
402 | |||||||||||||||
403 | /// Dereference the stored pointer. | ||||||||||||||
404 | typename add_lvalue_reference<element_type>::type | ||||||||||||||
405 | operator*() const | ||||||||||||||
406 | { | ||||||||||||||
407 | __glibcxx_assert(get() != pointer()); | ||||||||||||||
408 | return *get(); | ||||||||||||||
409 | } | ||||||||||||||
410 | |||||||||||||||
411 | /// Return the stored pointer. | ||||||||||||||
412 | pointer | ||||||||||||||
413 | operator->() const noexcept | ||||||||||||||
414 | { | ||||||||||||||
415 | _GLIBCXX_DEBUG_PEDASSERT(get() != pointer()); | ||||||||||||||
416 | return get(); | ||||||||||||||
417 | } | ||||||||||||||
418 | |||||||||||||||
419 | /// Return the stored pointer. | ||||||||||||||
420 | pointer | ||||||||||||||
421 | get() const noexcept | ||||||||||||||
422 | { return _M_t._M_ptr(); } | ||||||||||||||
423 | |||||||||||||||
424 | /// Return a reference to the stored deleter. | ||||||||||||||
425 | deleter_type& | ||||||||||||||
426 | get_deleter() noexcept | ||||||||||||||
427 | { return _M_t._M_deleter(); } | ||||||||||||||
428 | |||||||||||||||
429 | /// Return a reference to the stored deleter. | ||||||||||||||
430 | const deleter_type& | ||||||||||||||
431 | get_deleter() const noexcept | ||||||||||||||
432 | { return _M_t._M_deleter(); } | ||||||||||||||
433 | |||||||||||||||
434 | /// Return @c true if the stored pointer is not null. | ||||||||||||||
435 | explicit operator bool() const noexcept | ||||||||||||||
436 | { return get() == pointer() ? false : true; } | ||||||||||||||
437 | |||||||||||||||
438 | // Modifiers. | ||||||||||||||
439 | |||||||||||||||
440 | /// Release ownership of any stored pointer. | ||||||||||||||
441 | pointer | ||||||||||||||
442 | release() noexcept | ||||||||||||||
443 | { return _M_t.release(); } | ||||||||||||||
444 | |||||||||||||||
445 | /** @brief Replace the stored pointer. | ||||||||||||||
446 | * | ||||||||||||||
447 | * @param __p The new pointer to store. | ||||||||||||||
448 | * | ||||||||||||||
449 | * The deleter will be invoked if a pointer is already owned. | ||||||||||||||
450 | */ | ||||||||||||||
451 | void | ||||||||||||||
452 | reset(pointer __p = pointer()) noexcept | ||||||||||||||
453 | { | ||||||||||||||
454 | static_assert(__is_invocable<deleter_type&, pointer>::value, | ||||||||||||||
455 | "unique_ptr's deleter must be invocable with a pointer"); | ||||||||||||||
456 | _M_t.reset(std::move(__p)); | ||||||||||||||
457 | } | ||||||||||||||
458 | |||||||||||||||
459 | /// Exchange the pointer and deleter with another object. | ||||||||||||||
460 | void | ||||||||||||||
461 | swap(unique_ptr& __u) noexcept | ||||||||||||||
462 | { | ||||||||||||||
463 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); | ||||||||||||||
464 | _M_t.swap(__u._M_t); | ||||||||||||||
465 | } | ||||||||||||||
466 | |||||||||||||||
467 | // Disable copy from lvalue. | ||||||||||||||
468 | unique_ptr(const unique_ptr&) = delete; | ||||||||||||||
469 | unique_ptr& operator=(const unique_ptr&) = delete; | ||||||||||||||
470 | }; | ||||||||||||||
471 | |||||||||||||||
472 | /// 20.7.1.3 unique_ptr for array objects with a runtime length | ||||||||||||||
473 | // [unique.ptr.runtime] | ||||||||||||||
474 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | ||||||||||||||
475 | // DR 740 - omit specialization for array objects with a compile time length | ||||||||||||||
476 | template<typename _Tp, typename _Dp> | ||||||||||||||
477 | class unique_ptr<_Tp[], _Dp> | ||||||||||||||
478 | { | ||||||||||||||
479 | template <typename _Up> | ||||||||||||||
480 | using _DeleterConstraint = | ||||||||||||||
481 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; | ||||||||||||||
482 | |||||||||||||||
483 | __uniq_ptr_data<_Tp, _Dp> _M_t; | ||||||||||||||
484 | |||||||||||||||
485 | template<typename _Up> | ||||||||||||||
486 | using __remove_cv = typename remove_cv<_Up>::type; | ||||||||||||||
487 | |||||||||||||||
488 | // like is_base_of<_Tp, _Up> but false if unqualified types are the same | ||||||||||||||
489 | template<typename _Up> | ||||||||||||||
490 | using __is_derived_Tp | ||||||||||||||
491 | = __and_< is_base_of<_Tp, _Up>, | ||||||||||||||
492 | __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; | ||||||||||||||
493 | |||||||||||||||
494 | public: | ||||||||||||||
495 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; | ||||||||||||||
496 | using element_type = _Tp; | ||||||||||||||
497 | using deleter_type = _Dp; | ||||||||||||||
498 | |||||||||||||||
499 | // helper template for detecting a safe conversion from another | ||||||||||||||
500 | // unique_ptr | ||||||||||||||
501 | template<typename _Up, typename _Ep, | ||||||||||||||
502 | typename _UPtr = unique_ptr<_Up, _Ep>, | ||||||||||||||
503 | typename _UP_pointer = typename _UPtr::pointer, | ||||||||||||||
504 | typename _UP_element_type = typename _UPtr::element_type> | ||||||||||||||
505 | using __safe_conversion_up = __and_< | ||||||||||||||
506 | is_array<_Up>, | ||||||||||||||
507 | is_same<pointer, element_type*>, | ||||||||||||||
508 | is_same<_UP_pointer, _UP_element_type*>, | ||||||||||||||
509 | is_convertible<_UP_element_type(*)[], element_type(*)[]> | ||||||||||||||
510 | >; | ||||||||||||||
511 | |||||||||||||||
512 | // helper template for detecting a safe conversion from a raw pointer | ||||||||||||||
513 | template<typename _Up> | ||||||||||||||
514 | using __safe_conversion_raw = __and_< | ||||||||||||||
515 | __or_<__or_<is_same<_Up, pointer>, | ||||||||||||||
516 | is_same<_Up, nullptr_t>>, | ||||||||||||||
517 | __and_<is_pointer<_Up>, | ||||||||||||||
518 | is_same<pointer, element_type*>, | ||||||||||||||
519 | is_convertible< | ||||||||||||||
520 | typename remove_pointer<_Up>::type(*)[], | ||||||||||||||
521 | element_type(*)[]> | ||||||||||||||
522 | > | ||||||||||||||
523 | > | ||||||||||||||
524 | >; | ||||||||||||||
525 | |||||||||||||||
526 | // Constructors. | ||||||||||||||
527 | |||||||||||||||
528 | /// Default constructor, creates a unique_ptr that owns nothing. | ||||||||||||||
529 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> | ||||||||||||||
530 | constexpr unique_ptr() noexcept | ||||||||||||||
531 | : _M_t() | ||||||||||||||
532 | { } | ||||||||||||||
533 | |||||||||||||||
534 | /** Takes ownership of a pointer. | ||||||||||||||
535 | * | ||||||||||||||
536 | * @param __p A pointer to an array of a type safely convertible | ||||||||||||||
537 | * to an array of @c element_type | ||||||||||||||
538 | * | ||||||||||||||
539 | * The deleter will be value-initialized. | ||||||||||||||
540 | */ | ||||||||||||||
541 | template<typename _Up, | ||||||||||||||
542 | typename _Vp = _Dp, | ||||||||||||||
543 | typename = _DeleterConstraint<_Vp>, | ||||||||||||||
544 | typename = typename enable_if< | ||||||||||||||
545 | __safe_conversion_raw<_Up>::value, bool>::type> | ||||||||||||||
546 | explicit | ||||||||||||||
547 | unique_ptr(_Up __p) noexcept | ||||||||||||||
548 | : _M_t(__p) | ||||||||||||||
549 | { } | ||||||||||||||
550 | |||||||||||||||
551 | /** Takes ownership of a pointer. | ||||||||||||||
552 | * | ||||||||||||||
553 | * @param __p A pointer to an array of a type safely convertible | ||||||||||||||
554 | * to an array of @c element_type | ||||||||||||||
555 | * @param __d A reference to a deleter. | ||||||||||||||
556 | * | ||||||||||||||
557 | * The deleter will be initialized with @p __d | ||||||||||||||
558 | */ | ||||||||||||||
559 | template<typename _Up, typename _Del = deleter_type, | ||||||||||||||
560 | typename = _Require<__safe_conversion_raw<_Up>, | ||||||||||||||
561 | is_copy_constructible<_Del>>> | ||||||||||||||
562 | unique_ptr(_Up __p, const deleter_type& __d) noexcept | ||||||||||||||
563 | : _M_t(__p, __d) { } | ||||||||||||||
564 | |||||||||||||||
565 | /** Takes ownership of a pointer. | ||||||||||||||
566 | * | ||||||||||||||
567 | * @param __p A pointer to an array of a type safely convertible | ||||||||||||||
568 | * to an array of @c element_type | ||||||||||||||
569 | * @param __d A reference to a deleter. | ||||||||||||||
570 | * | ||||||||||||||
571 | * The deleter will be initialized with @p std::move(__d) | ||||||||||||||
572 | */ | ||||||||||||||
573 | template<typename _Up, typename _Del = deleter_type, | ||||||||||||||
574 | typename = _Require<__safe_conversion_raw<_Up>, | ||||||||||||||
575 | is_move_constructible<_Del>>> | ||||||||||||||
576 | unique_ptr(_Up __p, | ||||||||||||||
577 | __enable_if_t<!is_lvalue_reference<_Del>::value, | ||||||||||||||
578 | _Del&&> __d) noexcept | ||||||||||||||
579 | : _M_t(std::move(__p), std::move(__d)) | ||||||||||||||
580 | { } | ||||||||||||||
581 | |||||||||||||||
582 | template<typename _Up, typename _Del = deleter_type, | ||||||||||||||
583 | typename _DelUnref = typename remove_reference<_Del>::type, | ||||||||||||||
584 | typename = _Require<__safe_conversion_raw<_Up>>> | ||||||||||||||
585 | unique_ptr(_Up, | ||||||||||||||
586 | __enable_if_t<is_lvalue_reference<_Del>::value, | ||||||||||||||
587 | _DelUnref&&>) = delete; | ||||||||||||||
588 | |||||||||||||||
589 | /// Move constructor. | ||||||||||||||
590 | unique_ptr(unique_ptr&&) = default; | ||||||||||||||
591 | |||||||||||||||
592 | /// Creates a unique_ptr that owns nothing. | ||||||||||||||
593 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> | ||||||||||||||
594 | constexpr unique_ptr(nullptr_t) noexcept | ||||||||||||||
595 | : _M_t() | ||||||||||||||
596 | { } | ||||||||||||||
597 | |||||||||||||||
598 | template<typename _Up, typename _Ep, typename = _Require< | ||||||||||||||
599 | __safe_conversion_up<_Up, _Ep>, | ||||||||||||||
600 | typename conditional<is_reference<_Dp>::value, | ||||||||||||||
601 | is_same<_Ep, _Dp>, | ||||||||||||||
602 | is_convertible<_Ep, _Dp>>::type>> | ||||||||||||||
603 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept | ||||||||||||||
604 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) | ||||||||||||||
605 | { } | ||||||||||||||
606 | |||||||||||||||
607 | /// Destructor, invokes the deleter if the stored pointer is not null. | ||||||||||||||
608 | ~unique_ptr() | ||||||||||||||
609 | { | ||||||||||||||
610 | auto& __ptr = _M_t._M_ptr(); | ||||||||||||||
611 | if (__ptr != nullptr) | ||||||||||||||
612 | get_deleter()(__ptr); | ||||||||||||||
613 | __ptr = pointer(); | ||||||||||||||
614 | } | ||||||||||||||
615 | |||||||||||||||
616 | // Assignment. | ||||||||||||||
617 | |||||||||||||||
618 | /** @brief Move assignment operator. | ||||||||||||||
619 | * | ||||||||||||||
620 | * Invokes the deleter if this object owns a pointer. | ||||||||||||||
621 | */ | ||||||||||||||
622 | unique_ptr& | ||||||||||||||
623 | operator=(unique_ptr&&) = default; | ||||||||||||||
624 | |||||||||||||||
625 | /** @brief Assignment from another type. | ||||||||||||||
626 | * | ||||||||||||||
627 | * @param __u The object to transfer ownership from, which owns a | ||||||||||||||
628 | * convertible pointer to an array object. | ||||||||||||||
629 | * | ||||||||||||||
630 | * Invokes the deleter if this object owns a pointer. | ||||||||||||||
631 | */ | ||||||||||||||
632 | template<typename _Up, typename _Ep> | ||||||||||||||
633 | typename | ||||||||||||||
634 | enable_if<__and_<__safe_conversion_up<_Up, _Ep>, | ||||||||||||||
635 | is_assignable<deleter_type&, _Ep&&> | ||||||||||||||
636 | >::value, | ||||||||||||||
637 | unique_ptr&>::type | ||||||||||||||
638 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept | ||||||||||||||
639 | { | ||||||||||||||
640 | reset(__u.release()); | ||||||||||||||
641 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); | ||||||||||||||
642 | return *this; | ||||||||||||||
643 | } | ||||||||||||||
644 | |||||||||||||||
645 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. | ||||||||||||||
646 | unique_ptr& | ||||||||||||||
647 | operator=(nullptr_t) noexcept | ||||||||||||||
648 | { | ||||||||||||||
649 | reset(); | ||||||||||||||
650 | return *this; | ||||||||||||||
651 | } | ||||||||||||||
652 | |||||||||||||||
653 | // Observers. | ||||||||||||||
654 | |||||||||||||||
655 | /// Access an element of owned array. | ||||||||||||||
656 | typename std::add_lvalue_reference<element_type>::type | ||||||||||||||
657 | operator[](size_t __i) const | ||||||||||||||
658 | { | ||||||||||||||
659 | __glibcxx_assert(get() != pointer()); | ||||||||||||||
660 | return get()[__i]; | ||||||||||||||
661 | } | ||||||||||||||
662 | |||||||||||||||
663 | /// Return the stored pointer. | ||||||||||||||
664 | pointer | ||||||||||||||
665 | get() const noexcept | ||||||||||||||
666 | { return _M_t._M_ptr(); } | ||||||||||||||
667 | |||||||||||||||
668 | /// Return a reference to the stored deleter. | ||||||||||||||
669 | deleter_type& | ||||||||||||||
670 | get_deleter() noexcept | ||||||||||||||
671 | { return _M_t._M_deleter(); } | ||||||||||||||
672 | |||||||||||||||
673 | /// Return a reference to the stored deleter. | ||||||||||||||
674 | const deleter_type& | ||||||||||||||
675 | get_deleter() const noexcept | ||||||||||||||
676 | { return _M_t._M_deleter(); } | ||||||||||||||
677 | |||||||||||||||
678 | /// Return @c true if the stored pointer is not null. | ||||||||||||||
679 | explicit operator bool() const noexcept | ||||||||||||||
680 | { return get() == pointer() ? false : true; } | ||||||||||||||
681 | |||||||||||||||
682 | // Modifiers. | ||||||||||||||
683 | |||||||||||||||
684 | /// Release ownership of any stored pointer. | ||||||||||||||
685 | pointer | ||||||||||||||
686 | release() noexcept | ||||||||||||||
687 | { return _M_t.release(); } | ||||||||||||||
688 | |||||||||||||||
689 | /** @brief Replace the stored pointer. | ||||||||||||||
690 | * | ||||||||||||||
691 | * @param __p The new pointer to store. | ||||||||||||||
692 | * | ||||||||||||||
693 | * The deleter will be invoked if a pointer is already owned. | ||||||||||||||
694 | */ | ||||||||||||||
695 | template <typename _Up, | ||||||||||||||
696 | typename = _Require< | ||||||||||||||
697 | __or_<is_same<_Up, pointer>, | ||||||||||||||
698 | __and_<is_same<pointer, element_type*>, | ||||||||||||||
699 | is_pointer<_Up>, | ||||||||||||||
700 | is_convertible< | ||||||||||||||
701 | typename remove_pointer<_Up>::type(*)[], | ||||||||||||||
702 | element_type(*)[] | ||||||||||||||
703 | > | ||||||||||||||
704 | > | ||||||||||||||
705 | > | ||||||||||||||
706 | >> | ||||||||||||||
707 | void | ||||||||||||||
708 | reset(_Up __p) noexcept | ||||||||||||||
709 | { _M_t.reset(std::move(__p)); } | ||||||||||||||
710 | |||||||||||||||
711 | void reset(nullptr_t = nullptr) noexcept | ||||||||||||||
712 | { reset(pointer()); } | ||||||||||||||
713 | |||||||||||||||
714 | /// Exchange the pointer and deleter with another object. | ||||||||||||||
715 | void | ||||||||||||||
716 | swap(unique_ptr& __u) noexcept | ||||||||||||||
717 | { | ||||||||||||||
718 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); | ||||||||||||||
719 | _M_t.swap(__u._M_t); | ||||||||||||||
720 | } | ||||||||||||||
721 | |||||||||||||||
722 | // Disable copy from lvalue. | ||||||||||||||
723 | unique_ptr(const unique_ptr&) = delete; | ||||||||||||||
724 | unique_ptr& operator=(const unique_ptr&) = delete; | ||||||||||||||
725 | }; | ||||||||||||||
726 | |||||||||||||||
727 | /// @relates unique_ptr @{ | ||||||||||||||
728 | |||||||||||||||
729 | /// Swap overload for unique_ptr | ||||||||||||||
730 | template<typename _Tp, typename _Dp> | ||||||||||||||
731 | inline | ||||||||||||||
732 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 | ||||||||||||||
733 | // Constrained free swap overload, see p0185r1 | ||||||||||||||
734 | typename enable_if<__is_swappable<_Dp>::value>::type | ||||||||||||||
735 | #else | ||||||||||||||
736 | void | ||||||||||||||
737 | #endif | ||||||||||||||
738 | swap(unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
739 | unique_ptr<_Tp, _Dp>& __y) noexcept | ||||||||||||||
740 | { __x.swap(__y); } | ||||||||||||||
741 | |||||||||||||||
742 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 | ||||||||||||||
743 | template<typename _Tp, typename _Dp> | ||||||||||||||
744 | typename enable_if<!__is_swappable<_Dp>::value>::type | ||||||||||||||
745 | swap(unique_ptr<_Tp, _Dp>&, | ||||||||||||||
746 | unique_ptr<_Tp, _Dp>&) = delete; | ||||||||||||||
747 | #endif | ||||||||||||||
748 | |||||||||||||||
749 | /// Equality operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
750 | template<typename _Tp, typename _Dp, | ||||||||||||||
751 | typename _Up, typename _Ep> | ||||||||||||||
752 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
753 | operator==(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
754 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
755 | { return __x.get() == __y.get(); } | ||||||||||||||
756 | |||||||||||||||
757 | /// unique_ptr comparison with nullptr | ||||||||||||||
758 | template<typename _Tp, typename _Dp> | ||||||||||||||
759 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
760 | operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept | ||||||||||||||
761 | { return !__x; } | ||||||||||||||
762 | |||||||||||||||
763 | #ifndef __cpp_lib_three_way_comparison | ||||||||||||||
764 | /// unique_ptr comparison with nullptr | ||||||||||||||
765 | template<typename _Tp, typename _Dp> | ||||||||||||||
766 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
767 | operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept | ||||||||||||||
768 | { return !__x; } | ||||||||||||||
769 | |||||||||||||||
770 | /// Inequality operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
771 | template<typename _Tp, typename _Dp, | ||||||||||||||
772 | typename _Up, typename _Ep> | ||||||||||||||
773 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
774 | operator!=(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
775 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
776 | { return __x.get() != __y.get(); } | ||||||||||||||
777 | |||||||||||||||
778 | /// unique_ptr comparison with nullptr | ||||||||||||||
779 | template<typename _Tp, typename _Dp> | ||||||||||||||
780 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
781 | operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept | ||||||||||||||
782 | { return (bool)__x; } | ||||||||||||||
783 | |||||||||||||||
784 | /// unique_ptr comparison with nullptr | ||||||||||||||
785 | template<typename _Tp, typename _Dp> | ||||||||||||||
786 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
787 | operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept | ||||||||||||||
788 | { return (bool)__x; } | ||||||||||||||
789 | #endif // three way comparison | ||||||||||||||
790 | |||||||||||||||
791 | /// Relational operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
792 | template<typename _Tp, typename _Dp, | ||||||||||||||
793 | typename _Up, typename _Ep> | ||||||||||||||
794 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
795 | operator<(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
796 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
797 | { | ||||||||||||||
798 | typedef typename | ||||||||||||||
799 | std::common_type<typename unique_ptr<_Tp, _Dp>::pointer, | ||||||||||||||
800 | typename unique_ptr<_Up, _Ep>::pointer>::type _CT; | ||||||||||||||
801 | return std::less<_CT>()(__x.get(), __y.get()); | ||||||||||||||
802 | } | ||||||||||||||
803 | |||||||||||||||
804 | /// unique_ptr comparison with nullptr | ||||||||||||||
805 | template<typename _Tp, typename _Dp> | ||||||||||||||
806 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
807 | operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) | ||||||||||||||
808 | { | ||||||||||||||
809 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), | ||||||||||||||
810 | nullptr); | ||||||||||||||
811 | } | ||||||||||||||
812 | |||||||||||||||
813 | /// unique_ptr comparison with nullptr | ||||||||||||||
814 | template<typename _Tp, typename _Dp> | ||||||||||||||
815 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
816 | operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) | ||||||||||||||
817 | { | ||||||||||||||
818 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, | ||||||||||||||
819 | __x.get()); | ||||||||||||||
820 | } | ||||||||||||||
821 | |||||||||||||||
822 | /// Relational operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
823 | template<typename _Tp, typename _Dp, | ||||||||||||||
824 | typename _Up, typename _Ep> | ||||||||||||||
825 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
826 | operator<=(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
827 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
828 | { return !(__y < __x); } | ||||||||||||||
829 | |||||||||||||||
830 | /// unique_ptr comparison with nullptr | ||||||||||||||
831 | template<typename _Tp, typename _Dp> | ||||||||||||||
832 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
833 | operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) | ||||||||||||||
834 | { return !(nullptr < __x); } | ||||||||||||||
835 | |||||||||||||||
836 | /// unique_ptr comparison with nullptr | ||||||||||||||
837 | template<typename _Tp, typename _Dp> | ||||||||||||||
838 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
839 | operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) | ||||||||||||||
840 | { return !(__x < nullptr); } | ||||||||||||||
841 | |||||||||||||||
842 | /// Relational operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
843 | template<typename _Tp, typename _Dp, | ||||||||||||||
844 | typename _Up, typename _Ep> | ||||||||||||||
845 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
846 | operator>(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
847 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
848 | { return (__y < __x); } | ||||||||||||||
849 | |||||||||||||||
850 | /// unique_ptr comparison with nullptr | ||||||||||||||
851 | template<typename _Tp, typename _Dp> | ||||||||||||||
852 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
853 | operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) | ||||||||||||||
854 | { | ||||||||||||||
855 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, | ||||||||||||||
856 | __x.get()); | ||||||||||||||
857 | } | ||||||||||||||
858 | |||||||||||||||
859 | /// unique_ptr comparison with nullptr | ||||||||||||||
860 | template<typename _Tp, typename _Dp> | ||||||||||||||
861 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
862 | operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) | ||||||||||||||
863 | { | ||||||||||||||
864 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), | ||||||||||||||
865 | nullptr); | ||||||||||||||
866 | } | ||||||||||||||
867 | |||||||||||||||
868 | /// Relational operator for unique_ptr objects, compares the owned pointers | ||||||||||||||
869 | template<typename _Tp, typename _Dp, | ||||||||||||||
870 | typename _Up, typename _Ep> | ||||||||||||||
871 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
872 | operator>=(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
873 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
874 | { return !(__x < __y); } | ||||||||||||||
875 | |||||||||||||||
876 | /// unique_ptr comparison with nullptr | ||||||||||||||
877 | template<typename _Tp, typename _Dp> | ||||||||||||||
878 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
879 | operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) | ||||||||||||||
880 | { return !(__x < nullptr); } | ||||||||||||||
881 | |||||||||||||||
882 | /// unique_ptr comparison with nullptr | ||||||||||||||
883 | template<typename _Tp, typename _Dp> | ||||||||||||||
884 | _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool | ||||||||||||||
885 | operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) | ||||||||||||||
886 | { return !(nullptr < __x); } | ||||||||||||||
887 | |||||||||||||||
888 | #ifdef __cpp_lib_three_way_comparison | ||||||||||||||
889 | template<typename _Tp, typename _Dp, typename _Up, typename _Ep> | ||||||||||||||
890 | requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer, | ||||||||||||||
891 | typename unique_ptr<_Up, _Ep>::pointer> | ||||||||||||||
892 | inline | ||||||||||||||
893 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer, | ||||||||||||||
894 | typename unique_ptr<_Up, _Ep>::pointer> | ||||||||||||||
895 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, | ||||||||||||||
896 | const unique_ptr<_Up, _Ep>& __y) | ||||||||||||||
897 | { return compare_three_way()(__x.get(), __y.get()); } | ||||||||||||||
898 | |||||||||||||||
899 | template<typename _Tp, typename _Dp> | ||||||||||||||
900 | requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer> | ||||||||||||||
901 | inline | ||||||||||||||
902 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer> | ||||||||||||||
903 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) | ||||||||||||||
904 | { | ||||||||||||||
905 | using pointer = typename unique_ptr<_Tp, _Dp>::pointer; | ||||||||||||||
906 | return compare_three_way()(__x.get(), static_cast<pointer>(nullptr)); | ||||||||||||||
907 | } | ||||||||||||||
908 | #endif | ||||||||||||||
909 | // @} relates unique_ptr | ||||||||||||||
910 | |||||||||||||||
911 | /// @cond undocumented | ||||||||||||||
912 | template<typename _Up, typename _Ptr = typename _Up::pointer, | ||||||||||||||
913 | bool = __poison_hash<_Ptr>::__enable_hash_call> | ||||||||||||||
914 | struct __uniq_ptr_hash | ||||||||||||||
915 | #if ! _GLIBCXX_INLINE_VERSION0 | ||||||||||||||
916 | : private __poison_hash<_Ptr> | ||||||||||||||
917 | #endif | ||||||||||||||
918 | { | ||||||||||||||
919 | size_t | ||||||||||||||
920 | operator()(const _Up& __u) const | ||||||||||||||
921 | noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>()))) | ||||||||||||||
922 | { return hash<_Ptr>()(__u.get()); } | ||||||||||||||
923 | }; | ||||||||||||||
924 | |||||||||||||||
925 | template<typename _Up, typename _Ptr> | ||||||||||||||
926 | struct __uniq_ptr_hash<_Up, _Ptr, false> | ||||||||||||||
927 | : private __poison_hash<_Ptr> | ||||||||||||||
928 | { }; | ||||||||||||||
929 | /// @endcond | ||||||||||||||
930 | |||||||||||||||
931 | /// std::hash specialization for unique_ptr. | ||||||||||||||
932 | template<typename _Tp, typename _Dp> | ||||||||||||||
933 | struct hash<unique_ptr<_Tp, _Dp>> | ||||||||||||||
934 | : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>, | ||||||||||||||
935 | public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>> | ||||||||||||||
936 | { }; | ||||||||||||||
937 | |||||||||||||||
938 | #if __cplusplus201703L >= 201402L | ||||||||||||||
939 | /// @relates unique_ptr @{ | ||||||||||||||
940 | #define __cpp_lib_make_unique201304 201304 | ||||||||||||||
941 | |||||||||||||||
942 | /// @cond undocumented | ||||||||||||||
943 | |||||||||||||||
944 | template<typename _Tp> | ||||||||||||||
945 | struct _MakeUniq | ||||||||||||||
946 | { typedef unique_ptr<_Tp> __single_object; }; | ||||||||||||||
947 | |||||||||||||||
948 | template<typename _Tp> | ||||||||||||||
949 | struct _MakeUniq<_Tp[]> | ||||||||||||||
950 | { typedef unique_ptr<_Tp[]> __array; }; | ||||||||||||||
951 | |||||||||||||||
952 | template<typename _Tp, size_t _Bound> | ||||||||||||||
953 | struct _MakeUniq<_Tp[_Bound]> | ||||||||||||||
954 | { struct __invalid_type { }; }; | ||||||||||||||
955 | |||||||||||||||
956 | /// @endcond | ||||||||||||||
957 | |||||||||||||||
958 | /// std::make_unique for single objects | ||||||||||||||
959 | template<typename _Tp, typename... _Args> | ||||||||||||||
960 | inline typename _MakeUniq<_Tp>::__single_object | ||||||||||||||
961 | make_unique(_Args&&... __args) | ||||||||||||||
962 | { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } | ||||||||||||||
963 | |||||||||||||||
964 | /// std::make_unique for arrays of unknown bound | ||||||||||||||
965 | template<typename _Tp> | ||||||||||||||
966 | inline typename _MakeUniq<_Tp>::__array | ||||||||||||||
967 | make_unique(size_t __num) | ||||||||||||||
968 | { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } | ||||||||||||||
969 | |||||||||||||||
970 | /// Disable std::make_unique for arrays of known bound | ||||||||||||||
971 | template<typename _Tp, typename... _Args> | ||||||||||||||
972 | inline typename _MakeUniq<_Tp>::__invalid_type | ||||||||||||||
973 | make_unique(_Args&&...) = delete; | ||||||||||||||
974 | // @} relates unique_ptr | ||||||||||||||
975 | #endif // C++14 | ||||||||||||||
976 | |||||||||||||||
977 | #if __cplusplus201703L > 201703L && __cpp_concepts | ||||||||||||||
978 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | ||||||||||||||
979 | // 2948. unique_ptr does not define operator<< for stream output | ||||||||||||||
980 | /// Stream output operator for unique_ptr | ||||||||||||||
981 | template<typename _CharT, typename _Traits, typename _Tp, typename _Dp> | ||||||||||||||
982 | inline basic_ostream<_CharT, _Traits>& | ||||||||||||||
983 | operator<<(basic_ostream<_CharT, _Traits>& __os, | ||||||||||||||
984 | const unique_ptr<_Tp, _Dp>& __p) | ||||||||||||||
985 | requires requires { __os << __p.get(); } | ||||||||||||||
986 | { | ||||||||||||||
987 | __os << __p.get(); | ||||||||||||||
988 | return __os; | ||||||||||||||
989 | } | ||||||||||||||
990 | #endif // C++20 | ||||||||||||||
991 | |||||||||||||||
992 | // @} group pointer_abstractions | ||||||||||||||
993 | |||||||||||||||
994 | #if __cplusplus201703L >= 201703L | ||||||||||||||
995 | namespace __detail::__variant | ||||||||||||||
996 | { | ||||||||||||||
997 | template<typename> struct _Never_valueless_alt; // see <variant> | ||||||||||||||
998 | |||||||||||||||
999 | // Provide the strong exception-safety guarantee when emplacing a | ||||||||||||||
1000 | // unique_ptr into a variant. | ||||||||||||||
1001 | template<typename _Tp, typename _Del> | ||||||||||||||
1002 | struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>> | ||||||||||||||
1003 | : std::true_type | ||||||||||||||
1004 | { }; | ||||||||||||||
1005 | } // namespace __detail::__variant | ||||||||||||||
1006 | #endif // C++17 | ||||||||||||||
1007 | |||||||||||||||
1008 | _GLIBCXX_END_NAMESPACE_VERSION | ||||||||||||||
1009 | } // namespace | ||||||||||||||
1010 | |||||||||||||||
1011 | #endif /* _UNIQUE_PTR_H */ |
1 | // <tuple> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2007-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/tuple |
26 | * This is a Standard C++ Library header. |
27 | */ |
28 | |
29 | #ifndef _GLIBCXX_TUPLE1 |
30 | #define _GLIBCXX_TUPLE1 1 |
31 | |
32 | #pragma GCC system_header |
33 | |
34 | #if __cplusplus201703L < 201103L |
35 | # include <bits/c++0x_warning.h> |
36 | #else |
37 | |
38 | #include <utility> |
39 | #include <array> |
40 | #include <bits/uses_allocator.h> |
41 | #include <bits/invoke.h> |
42 | #if __cplusplus201703L > 201703L |
43 | # include <compare> |
44 | # define __cpp_lib_constexpr_tuple 201811L |
45 | #endif |
46 | |
47 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
48 | { |
49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
50 | |
51 | /** |
52 | * @addtogroup utilities |
53 | * @{ |
54 | */ |
55 | |
56 | template<typename... _Elements> |
57 | class tuple; |
58 | |
59 | template<typename _Tp> |
60 | struct __is_empty_non_tuple : is_empty<_Tp> { }; |
61 | |
62 | // Using EBO for elements that are tuples causes ambiguous base errors. |
63 | template<typename _El0, typename... _El> |
64 | struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { }; |
65 | |
66 | // Use the Empty Base-class Optimization for empty, non-final types. |
67 | template<typename _Tp> |
68 | using __empty_not_final |
69 | = typename conditional<__is_final(_Tp), false_type, |
70 | __is_empty_non_tuple<_Tp>>::type; |
71 | |
72 | template<std::size_t _Idx, typename _Head, |
73 | bool = __empty_not_final<_Head>::value> |
74 | struct _Head_base; |
75 | |
76 | template<std::size_t _Idx, typename _Head> |
77 | struct _Head_base<_Idx, _Head, true> |
78 | : public _Head |
79 | { |
80 | constexpr _Head_base() |
81 | : _Head() { } |
82 | |
83 | constexpr _Head_base(const _Head& __h) |
84 | : _Head(__h) { } |
85 | |
86 | constexpr _Head_base(const _Head_base&) = default; |
87 | constexpr _Head_base(_Head_base&&) = default; |
88 | |
89 | template<typename _UHead> |
90 | constexpr _Head_base(_UHead&& __h) |
91 | : _Head(std::forward<_UHead>(__h)) { } |
92 | |
93 | _Head_base(allocator_arg_t, __uses_alloc0) |
94 | : _Head() { } |
95 | |
96 | template<typename _Alloc> |
97 | _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) |
98 | : _Head(allocator_arg, *__a._M_a) { } |
99 | |
100 | template<typename _Alloc> |
101 | _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) |
102 | : _Head(*__a._M_a) { } |
103 | |
104 | template<typename _UHead> |
105 | _Head_base(__uses_alloc0, _UHead&& __uhead) |
106 | : _Head(std::forward<_UHead>(__uhead)) { } |
107 | |
108 | template<typename _Alloc, typename _UHead> |
109 | _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) |
110 | : _Head(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) { } |
111 | |
112 | template<typename _Alloc, typename _UHead> |
113 | _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) |
114 | : _Head(std::forward<_UHead>(__uhead), *__a._M_a) { } |
115 | |
116 | static constexpr _Head& |
117 | _M_head(_Head_base& __b) noexcept { return __b; } |
118 | |
119 | static constexpr const _Head& |
120 | _M_head(const _Head_base& __b) noexcept { return __b; } |
121 | }; |
122 | |
123 | template<std::size_t _Idx, typename _Head> |
124 | struct _Head_base<_Idx, _Head, false> |
125 | { |
126 | constexpr _Head_base() |
127 | : _M_head_impl() { } |
128 | |
129 | constexpr _Head_base(const _Head& __h) |
130 | : _M_head_impl(__h) { } |
131 | |
132 | constexpr _Head_base(const _Head_base&) = default; |
133 | constexpr _Head_base(_Head_base&&) = default; |
134 | |
135 | template<typename _UHead> |
136 | constexpr _Head_base(_UHead&& __h) |
137 | : _M_head_impl(std::forward<_UHead>(__h)) { } |
138 | |
139 | _GLIBCXX20_CONSTEXPR |
140 | _Head_base(allocator_arg_t, __uses_alloc0) |
141 | : _M_head_impl() { } |
142 | |
143 | template<typename _Alloc> |
144 | _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) |
145 | : _M_head_impl(allocator_arg, *__a._M_a) { } |
146 | |
147 | template<typename _Alloc> |
148 | _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) |
149 | : _M_head_impl(*__a._M_a) { } |
150 | |
151 | template<typename _UHead> |
152 | _GLIBCXX20_CONSTEXPR |
153 | _Head_base(__uses_alloc0, _UHead&& __uhead) |
154 | : _M_head_impl(std::forward<_UHead>(__uhead)) { } |
155 | |
156 | template<typename _Alloc, typename _UHead> |
157 | _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) |
158 | : _M_head_impl(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) |
159 | { } |
160 | |
161 | template<typename _Alloc, typename _UHead> |
162 | _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) |
163 | : _M_head_impl(std::forward<_UHead>(__uhead), *__a._M_a) { } |
164 | |
165 | static constexpr _Head& |
166 | _M_head(_Head_base& __b) noexcept { return __b._M_head_impl; } |
167 | |
168 | static constexpr const _Head& |
169 | _M_head(const _Head_base& __b) noexcept { return __b._M_head_impl; } |
170 | |
171 | _Head _M_head_impl; |
172 | }; |
173 | |
174 | /** |
175 | * Contains the actual implementation of the @c tuple template, stored |
176 | * as a recursive inheritance hierarchy from the first element (most |
177 | * derived class) to the last (least derived class). The @c Idx |
178 | * parameter gives the 0-based index of the element stored at this |
179 | * point in the hierarchy; we use it to implement a constant-time |
180 | * get() operation. |
181 | */ |
182 | template<std::size_t _Idx, typename... _Elements> |
183 | struct _Tuple_impl; |
184 | |
185 | /** |
186 | * Recursive tuple implementation. Here we store the @c Head element |
187 | * and derive from a @c Tuple_impl containing the remaining elements |
188 | * (which contains the @c Tail). |
189 | */ |
190 | template<std::size_t _Idx, typename _Head, typename... _Tail> |
191 | struct _Tuple_impl<_Idx, _Head, _Tail...> |
192 | : public _Tuple_impl<_Idx + 1, _Tail...>, |
193 | private _Head_base<_Idx, _Head> |
194 | { |
195 | template<std::size_t, typename...> friend class _Tuple_impl; |
196 | |
197 | typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited; |
198 | typedef _Head_base<_Idx, _Head> _Base; |
199 | |
200 | static constexpr _Head& |
201 | _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
202 | |
203 | static constexpr const _Head& |
204 | _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
205 | |
206 | static constexpr _Inherited& |
207 | _M_tail(_Tuple_impl& __t) noexcept { return __t; } |
208 | |
209 | static constexpr const _Inherited& |
210 | _M_tail(const _Tuple_impl& __t) noexcept { return __t; } |
211 | |
212 | constexpr _Tuple_impl() |
213 | : _Inherited(), _Base() { } |
214 | |
215 | explicit |
216 | constexpr _Tuple_impl(const _Head& __head, const _Tail&... __tail) |
217 | : _Inherited(__tail...), _Base(__head) { } |
218 | |
219 | template<typename _UHead, typename... _UTail, typename = typename |
220 | enable_if<sizeof...(_Tail) == sizeof...(_UTail)>::type> |
221 | explicit |
222 | constexpr _Tuple_impl(_UHead&& __head, _UTail&&... __tail) |
223 | : _Inherited(std::forward<_UTail>(__tail)...), |
224 | _Base(std::forward<_UHead>(__head)) { } |
225 | |
226 | constexpr _Tuple_impl(const _Tuple_impl&) = default; |
227 | |
228 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
229 | // 2729. Missing SFINAE on std::pair::operator= |
230 | _Tuple_impl& operator=(const _Tuple_impl&) = delete; |
231 | |
232 | constexpr |
233 | _Tuple_impl(_Tuple_impl&& __in) |
234 | noexcept(__and_<is_nothrow_move_constructible<_Head>, |
235 | is_nothrow_move_constructible<_Inherited>>::value) |
236 | : _Inherited(std::move(_M_tail(__in))), |
237 | _Base(std::forward<_Head>(_M_head(__in))) { } |
238 | |
239 | template<typename... _UElements> |
240 | constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in) |
241 | : _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), |
242 | _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { } |
243 | |
244 | template<typename _UHead, typename... _UTails> |
245 | constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
246 | : _Inherited(std::move |
247 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), |
248 | _Base(std::forward<_UHead> |
249 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } |
250 | |
251 | template<typename _Alloc> |
252 | _GLIBCXX20_CONSTEXPR |
253 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) |
254 | : _Inherited(__tag, __a), |
255 | _Base(__tag, __use_alloc<_Head>(__a)) { } |
256 | |
257 | template<typename _Alloc> |
258 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
259 | const _Head& __head, const _Tail&... __tail) |
260 | : _Inherited(__tag, __a, __tail...), |
261 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } |
262 | |
263 | template<typename _Alloc, typename _UHead, typename... _UTail, |
264 | typename = typename enable_if<sizeof...(_Tail) |
265 | == sizeof...(_UTail)>::type> |
266 | _GLIBCXX20_CONSTEXPR |
267 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
268 | _UHead&& __head, _UTail&&... __tail) |
269 | : _Inherited(__tag, __a, std::forward<_UTail>(__tail)...), |
270 | _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
271 | std::forward<_UHead>(__head)) { } |
272 | |
273 | template<typename _Alloc> |
274 | _GLIBCXX20_CONSTEXPR |
275 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
276 | const _Tuple_impl& __in) |
277 | : _Inherited(__tag, __a, _M_tail(__in)), |
278 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } |
279 | |
280 | template<typename _Alloc> |
281 | _GLIBCXX20_CONSTEXPR |
282 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
283 | _Tuple_impl&& __in) |
284 | : _Inherited(__tag, __a, std::move(_M_tail(__in))), |
285 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
286 | std::forward<_Head>(_M_head(__in))) { } |
287 | |
288 | template<typename _Alloc, typename... _UElements> |
289 | _GLIBCXX20_CONSTEXPR |
290 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
291 | const _Tuple_impl<_Idx, _UElements...>& __in) |
292 | : _Inherited(__tag, __a, |
293 | _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), |
294 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
295 | _Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { } |
296 | |
297 | template<typename _Alloc, typename _UHead, typename... _UTails> |
298 | _GLIBCXX20_CONSTEXPR |
299 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
300 | _Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
301 | : _Inherited(__tag, __a, std::move |
302 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), |
303 | _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
304 | std::forward<_UHead> |
305 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } |
306 | |
307 | template<typename... _UElements> |
308 | _GLIBCXX20_CONSTEXPR |
309 | void |
310 | _M_assign(const _Tuple_impl<_Idx, _UElements...>& __in) |
311 | { |
312 | _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in); |
313 | _M_tail(*this)._M_assign( |
314 | _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)); |
315 | } |
316 | |
317 | template<typename _UHead, typename... _UTails> |
318 | _GLIBCXX20_CONSTEXPR |
319 | void |
320 | _M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
321 | { |
322 | _M_head(*this) = std::forward<_UHead> |
323 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)); |
324 | _M_tail(*this)._M_assign( |
325 | std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))); |
326 | } |
327 | |
328 | protected: |
329 | _GLIBCXX20_CONSTEXPR |
330 | void |
331 | _M_swap(_Tuple_impl& __in) |
332 | { |
333 | using std::swap; |
334 | swap(_M_head(*this), _M_head(__in)); |
335 | _Inherited::_M_swap(_M_tail(__in)); |
336 | } |
337 | }; |
338 | |
339 | // Basis case of inheritance recursion. |
340 | template<std::size_t _Idx, typename _Head> |
341 | struct _Tuple_impl<_Idx, _Head> |
342 | : private _Head_base<_Idx, _Head> |
343 | { |
344 | template<std::size_t, typename...> friend class _Tuple_impl; |
345 | |
346 | typedef _Head_base<_Idx, _Head> _Base; |
347 | |
348 | static constexpr _Head& |
349 | _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
350 | |
351 | static constexpr const _Head& |
352 | _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
353 | |
354 | constexpr _Tuple_impl() |
355 | : _Base() { } |
356 | |
357 | explicit |
358 | constexpr _Tuple_impl(const _Head& __head) |
359 | : _Base(__head) { } |
360 | |
361 | template<typename _UHead> |
362 | explicit |
363 | constexpr _Tuple_impl(_UHead&& __head) |
364 | : _Base(std::forward<_UHead>(__head)) { } |
365 | |
366 | constexpr _Tuple_impl(const _Tuple_impl&) = default; |
367 | |
368 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
369 | // 2729. Missing SFINAE on std::pair::operator= |
370 | _Tuple_impl& operator=(const _Tuple_impl&) = delete; |
371 | |
372 | constexpr |
373 | _Tuple_impl(_Tuple_impl&& __in) |
374 | noexcept(is_nothrow_move_constructible<_Head>::value) |
375 | : _Base(std::forward<_Head>(_M_head(__in))) { } |
376 | |
377 | template<typename _UHead> |
378 | constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) |
379 | : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } |
380 | |
381 | template<typename _UHead> |
382 | constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) |
383 | : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) |
384 | { } |
385 | |
386 | template<typename _Alloc> |
387 | _GLIBCXX20_CONSTEXPR |
388 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) |
389 | : _Base(__tag, __use_alloc<_Head>(__a)) { } |
390 | |
391 | template<typename _Alloc> |
392 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
393 | const _Head& __head) |
394 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } |
395 | |
396 | template<typename _Alloc, typename _UHead> |
397 | _GLIBCXX20_CONSTEXPR |
398 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
399 | _UHead&& __head) |
400 | : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
401 | std::forward<_UHead>(__head)) { } |
402 | |
403 | template<typename _Alloc> |
404 | _GLIBCXX20_CONSTEXPR |
405 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
406 | const _Tuple_impl& __in) |
407 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } |
408 | |
409 | template<typename _Alloc> |
410 | _GLIBCXX20_CONSTEXPR |
411 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
412 | _Tuple_impl&& __in) |
413 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
414 | std::forward<_Head>(_M_head(__in))) { } |
415 | |
416 | template<typename _Alloc, typename _UHead> |
417 | _GLIBCXX20_CONSTEXPR |
418 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
419 | const _Tuple_impl<_Idx, _UHead>& __in) |
420 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
421 | _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } |
422 | |
423 | template<typename _Alloc, typename _UHead> |
424 | _GLIBCXX20_CONSTEXPR |
425 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
426 | _Tuple_impl<_Idx, _UHead>&& __in) |
427 | : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
428 | std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) |
429 | { } |
430 | |
431 | template<typename _UHead> |
432 | _GLIBCXX20_CONSTEXPR |
433 | void |
434 | _M_assign(const _Tuple_impl<_Idx, _UHead>& __in) |
435 | { |
436 | _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); |
437 | } |
438 | |
439 | template<typename _UHead> |
440 | _GLIBCXX20_CONSTEXPR |
441 | void |
442 | _M_assign(_Tuple_impl<_Idx, _UHead>&& __in) |
443 | { |
444 | _M_head(*this) |
445 | = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); |
446 | } |
447 | |
448 | protected: |
449 | _GLIBCXX20_CONSTEXPR |
450 | void |
451 | _M_swap(_Tuple_impl& __in) |
452 | { |
453 | using std::swap; |
454 | swap(_M_head(*this), _M_head(__in)); |
455 | } |
456 | }; |
457 | |
458 | // Concept utility functions, reused in conditionally-explicit |
459 | // constructors. |
460 | template<bool, typename... _Types> |
461 | struct _TupleConstraints |
462 | { |
463 | // Constraint for a non-explicit constructor. |
464 | // True iff each Ti in _Types... can be constructed from Ui in _UTypes... |
465 | // and every Ui is implicitly convertible to Ti. |
466 | template<typename... _UTypes> |
467 | static constexpr bool __is_implicitly_constructible() |
468 | { |
469 | return __and_<is_constructible<_Types, _UTypes>..., |
470 | is_convertible<_UTypes, _Types>... |
471 | >::value; |
472 | } |
473 | |
474 | // Constraint for a non-explicit constructor. |
475 | // True iff each Ti in _Types... can be constructed from Ui in _UTypes... |
476 | // but not every Ui is implicitly convertible to Ti. |
477 | template<typename... _UTypes> |
478 | static constexpr bool __is_explicitly_constructible() |
479 | { |
480 | return __and_<is_constructible<_Types, _UTypes>..., |
481 | __not_<__and_<is_convertible<_UTypes, _Types>...>> |
482 | >::value; |
483 | } |
484 | |
485 | static constexpr bool __is_implicitly_default_constructible() |
486 | { |
487 | return __and_<std::__is_implicitly_default_constructible<_Types>... |
488 | >::value; |
489 | } |
490 | |
491 | static constexpr bool __is_explicitly_default_constructible() |
492 | { |
493 | return __and_<is_default_constructible<_Types>..., |
494 | __not_<__and_< |
495 | std::__is_implicitly_default_constructible<_Types>...> |
496 | >>::value; |
497 | } |
498 | }; |
499 | |
500 | // Partial specialization used when a required precondition isn't met, |
501 | // e.g. when sizeof...(_Types) != sizeof...(_UTypes). |
502 | template<typename... _Types> |
503 | struct _TupleConstraints<false, _Types...> |
504 | { |
505 | template<typename... _UTypes> |
506 | static constexpr bool __is_implicitly_constructible() |
507 | { return false; } |
508 | |
509 | template<typename... _UTypes> |
510 | static constexpr bool __is_explicitly_constructible() |
511 | { return false; } |
512 | }; |
513 | |
514 | /// Primary class template, tuple |
515 | template<typename... _Elements> |
516 | class tuple : public _Tuple_impl<0, _Elements...> |
517 | { |
518 | typedef _Tuple_impl<0, _Elements...> _Inherited; |
519 | |
520 | template<bool _Cond> |
521 | using _TCC = _TupleConstraints<_Cond, _Elements...>; |
522 | |
523 | // Constraint for non-explicit default constructor |
524 | template<bool _Dummy> |
525 | using _ImplicitDefaultCtor = __enable_if_t< |
526 | _TCC<_Dummy>::__is_implicitly_default_constructible(), |
527 | bool>; |
528 | |
529 | // Constraint for explicit default constructor |
530 | template<bool _Dummy> |
531 | using _ExplicitDefaultCtor = __enable_if_t< |
532 | _TCC<_Dummy>::__is_explicitly_default_constructible(), |
533 | bool>; |
534 | |
535 | // Constraint for non-explicit constructors |
536 | template<bool _Cond, typename... _Args> |
537 | using _ImplicitCtor = __enable_if_t< |
538 | _TCC<_Cond>::template __is_implicitly_constructible<_Args...>(), |
539 | bool>; |
540 | |
541 | // Constraint for non-explicit constructors |
542 | template<bool _Cond, typename... _Args> |
543 | using _ExplicitCtor = __enable_if_t< |
544 | _TCC<_Cond>::template __is_explicitly_constructible<_Args...>(), |
545 | bool>; |
546 | |
547 | template<typename... _UElements> |
548 | static constexpr |
549 | __enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool> |
550 | __assignable() |
551 | { return __and_<is_assignable<_Elements&, _UElements>...>::value; } |
552 | |
553 | // Condition for noexcept-specifier of an assignment operator. |
554 | template<typename... _UElements> |
555 | static constexpr bool __nothrow_assignable() |
556 | { |
557 | return |
558 | __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value; |
559 | } |
560 | |
561 | // Condition for noexcept-specifier of a constructor. |
562 | template<typename... _UElements> |
563 | static constexpr bool __nothrow_constructible() |
564 | { |
565 | return |
566 | __and_<is_nothrow_constructible<_Elements, _UElements>...>::value; |
567 | } |
568 | |
569 | // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1. |
570 | template<typename _Up> |
571 | static constexpr bool __valid_args() |
572 | { |
573 | return sizeof...(_Elements) == 1 |
574 | && !is_same<tuple, __remove_cvref_t<_Up>>::value; |
575 | } |
576 | |
577 | // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1. |
578 | template<typename, typename, typename... _Tail> |
579 | static constexpr bool __valid_args() |
580 | { return (sizeof...(_Tail) + 2) == sizeof...(_Elements); } |
581 | |
582 | /* Constraint for constructors with a tuple<UTypes...> parameter ensures |
583 | * that the constructor is only viable when it would not interfere with |
584 | * tuple(UTypes&&...) or tuple(const tuple&) or tuple(tuple&&). |
585 | * Such constructors are only viable if: |
586 | * either sizeof...(Types) != 1, |
587 | * or (when Types... expands to T and UTypes... expands to U) |
588 | * is_convertible_v<TUPLE, T>, is_constructible_v<T, TUPLE>, |
589 | * and is_same_v<T, U> are all false. |
590 | */ |
591 | template<typename _Tuple, typename = tuple, |
592 | typename = __remove_cvref_t<_Tuple>> |
593 | struct _UseOtherCtor |
594 | : false_type |
595 | { }; |
596 | // If TUPLE is convertible to the single element in *this, |
597 | // then TUPLE should match tuple(UTypes&&...) instead. |
598 | template<typename _Tuple, typename _Tp, typename _Up> |
599 | struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Up>> |
600 | : __or_<is_convertible<_Tuple, _Tp>, is_constructible<_Tp, _Tuple>> |
601 | { }; |
602 | // If TUPLE and *this each have a single element of the same type, |
603 | // then TUPLE should match a copy/move constructor instead. |
604 | template<typename _Tuple, typename _Tp> |
605 | struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Tp>> |
606 | : true_type |
607 | { }; |
608 | |
609 | // Return true iff sizeof...(Types) == 1 && tuple_size_v<TUPLE> == 1 |
610 | // and the single element in Types can be initialized from TUPLE, |
611 | // or is the same type as tuple_element_t<0, TUPLE>. |
612 | template<typename _Tuple> |
613 | static constexpr bool __use_other_ctor() |
614 | { return _UseOtherCtor<_Tuple>::value; } |
615 | |
616 | public: |
617 | template<typename _Dummy = void, |
618 | _ImplicitDefaultCtor<is_void<_Dummy>::value> = true> |
619 | constexpr |
620 | tuple() |
621 | noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) |
622 | : _Inherited() { } |
623 | |
624 | template<typename _Dummy = void, |
625 | _ExplicitDefaultCtor<is_void<_Dummy>::value> = false> |
626 | explicit constexpr |
627 | tuple() |
628 | noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) |
629 | : _Inherited() { } |
630 | |
631 | template<bool _NotEmpty = (sizeof...(_Elements) >= 1), |
632 | _ImplicitCtor<_NotEmpty, const _Elements&...> = true> |
633 | constexpr |
634 | tuple(const _Elements&... __elements) |
635 | noexcept(__nothrow_constructible<const _Elements&...>()) |
636 | : _Inherited(__elements...) { } |
637 | |
638 | template<bool _NotEmpty = (sizeof...(_Elements) >= 1), |
639 | _ExplicitCtor<_NotEmpty, const _Elements&...> = false> |
640 | explicit constexpr |
641 | tuple(const _Elements&... __elements) |
642 | noexcept(__nothrow_constructible<const _Elements&...>()) |
643 | : _Inherited(__elements...) { } |
644 | |
645 | template<typename... _UElements, |
646 | bool _Valid = __valid_args<_UElements...>(), |
647 | _ImplicitCtor<_Valid, _UElements...> = true> |
648 | constexpr |
649 | tuple(_UElements&&... __elements) |
650 | noexcept(__nothrow_constructible<_UElements...>()) |
651 | : _Inherited(std::forward<_UElements>(__elements)...) { } |
652 | |
653 | template<typename... _UElements, |
654 | bool _Valid = __valid_args<_UElements...>(), |
655 | _ExplicitCtor<_Valid, _UElements...> = false> |
656 | explicit constexpr |
657 | tuple(_UElements&&... __elements) |
658 | noexcept(__nothrow_constructible<_UElements...>()) |
659 | : _Inherited(std::forward<_UElements>(__elements)...) { } |
660 | |
661 | constexpr tuple(const tuple&) = default; |
662 | |
663 | constexpr tuple(tuple&&) = default; |
664 | |
665 | template<typename... _UElements, |
666 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
667 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
668 | _ImplicitCtor<_Valid, const _UElements&...> = true> |
669 | constexpr |
670 | tuple(const tuple<_UElements...>& __in) |
671 | noexcept(__nothrow_constructible<const _UElements&...>()) |
672 | : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
673 | { } |
674 | |
675 | template<typename... _UElements, |
676 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
677 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
678 | _ExplicitCtor<_Valid, const _UElements&...> = false> |
679 | explicit constexpr |
680 | tuple(const tuple<_UElements...>& __in) |
681 | noexcept(__nothrow_constructible<const _UElements&...>()) |
682 | : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
683 | { } |
684 | |
685 | template<typename... _UElements, |
686 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
687 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
688 | _ImplicitCtor<_Valid, _UElements...> = true> |
689 | constexpr |
690 | tuple(tuple<_UElements...>&& __in) |
691 | noexcept(__nothrow_constructible<_UElements...>()) |
692 | : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } |
693 | |
694 | template<typename... _UElements, |
695 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
696 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
697 | _ExplicitCtor<_Valid, _UElements...> = false> |
698 | explicit constexpr |
699 | tuple(tuple<_UElements...>&& __in) |
700 | noexcept(__nothrow_constructible<_UElements...>()) |
701 | : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } |
702 | |
703 | // Allocator-extended constructors. |
704 | |
705 | template<typename _Alloc, |
706 | _ImplicitDefaultCtor<is_object<_Alloc>::value> = true> |
707 | _GLIBCXX20_CONSTEXPR |
708 | tuple(allocator_arg_t __tag, const _Alloc& __a) |
709 | : _Inherited(__tag, __a) { } |
710 | |
711 | template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1), |
712 | _ImplicitCtor<_NotEmpty, const _Elements&...> = true> |
713 | _GLIBCXX20_CONSTEXPR |
714 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
715 | const _Elements&... __elements) |
716 | : _Inherited(__tag, __a, __elements...) { } |
717 | |
718 | template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1), |
719 | _ExplicitCtor<_NotEmpty, const _Elements&...> = false> |
720 | _GLIBCXX20_CONSTEXPR |
721 | explicit |
722 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
723 | const _Elements&... __elements) |
724 | : _Inherited(__tag, __a, __elements...) { } |
725 | |
726 | template<typename _Alloc, typename... _UElements, |
727 | bool _Valid = __valid_args<_UElements...>(), |
728 | _ImplicitCtor<_Valid, _UElements...> = true> |
729 | _GLIBCXX20_CONSTEXPR |
730 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
731 | _UElements&&... __elements) |
732 | : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) |
733 | { } |
734 | |
735 | template<typename _Alloc, typename... _UElements, |
736 | bool _Valid = __valid_args<_UElements...>(), |
737 | _ExplicitCtor<_Valid, _UElements...> = false> |
738 | _GLIBCXX20_CONSTEXPR |
739 | explicit |
740 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
741 | _UElements&&... __elements) |
742 | : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) |
743 | { } |
744 | |
745 | template<typename _Alloc> |
746 | _GLIBCXX20_CONSTEXPR |
747 | tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) |
748 | : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } |
749 | |
750 | template<typename _Alloc> |
751 | _GLIBCXX20_CONSTEXPR |
752 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) |
753 | : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } |
754 | |
755 | template<typename _Alloc, typename... _UElements, |
756 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
757 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
758 | _ImplicitCtor<_Valid, const _UElements&...> = true> |
759 | _GLIBCXX20_CONSTEXPR |
760 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
761 | const tuple<_UElements...>& __in) |
762 | : _Inherited(__tag, __a, |
763 | static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
764 | { } |
765 | |
766 | template<typename _Alloc, typename... _UElements, |
767 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
768 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
769 | _ExplicitCtor<_Valid, const _UElements&...> = false> |
770 | _GLIBCXX20_CONSTEXPR |
771 | explicit |
772 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
773 | const tuple<_UElements...>& __in) |
774 | : _Inherited(__tag, __a, |
775 | static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
776 | { } |
777 | |
778 | template<typename _Alloc, typename... _UElements, |
779 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
780 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
781 | _ImplicitCtor<_Valid, _UElements...> = true> |
782 | _GLIBCXX20_CONSTEXPR |
783 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
784 | tuple<_UElements...>&& __in) |
785 | : _Inherited(__tag, __a, |
786 | static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) |
787 | { } |
788 | |
789 | template<typename _Alloc, typename... _UElements, |
790 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
791 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
792 | _ExplicitCtor<_Valid, _UElements...> = false> |
793 | _GLIBCXX20_CONSTEXPR |
794 | explicit |
795 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
796 | tuple<_UElements...>&& __in) |
797 | : _Inherited(__tag, __a, |
798 | static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) |
799 | { } |
800 | |
801 | // tuple assignment |
802 | |
803 | _GLIBCXX20_CONSTEXPR |
804 | tuple& |
805 | operator=(typename conditional<__assignable<const _Elements&...>(), |
806 | const tuple&, |
807 | const __nonesuch&>::type __in) |
808 | noexcept(__nothrow_assignable<const _Elements&...>()) |
809 | { |
810 | this->_M_assign(__in); |
811 | return *this; |
812 | } |
813 | |
814 | _GLIBCXX20_CONSTEXPR |
815 | tuple& |
816 | operator=(typename conditional<__assignable<_Elements...>(), |
817 | tuple&&, |
818 | __nonesuch&&>::type __in) |
819 | noexcept(__nothrow_assignable<_Elements...>()) |
820 | { |
821 | this->_M_assign(std::move(__in)); |
822 | return *this; |
823 | } |
824 | |
825 | template<typename... _UElements> |
826 | _GLIBCXX20_CONSTEXPR |
827 | __enable_if_t<__assignable<const _UElements&...>(), tuple&> |
828 | operator=(const tuple<_UElements...>& __in) |
829 | noexcept(__nothrow_assignable<const _UElements&...>()) |
830 | { |
831 | this->_M_assign(__in); |
832 | return *this; |
833 | } |
834 | |
835 | template<typename... _UElements> |
836 | _GLIBCXX20_CONSTEXPR |
837 | __enable_if_t<__assignable<_UElements...>(), tuple&> |
838 | operator=(tuple<_UElements...>&& __in) |
839 | noexcept(__nothrow_assignable<_UElements...>()) |
840 | { |
841 | this->_M_assign(std::move(__in)); |
842 | return *this; |
843 | } |
844 | |
845 | // tuple swap |
846 | _GLIBCXX20_CONSTEXPR |
847 | void |
848 | swap(tuple& __in) |
849 | noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value) |
850 | { _Inherited::_M_swap(__in); } |
851 | }; |
852 | |
853 | #if __cpp_deduction_guides201703L >= 201606 |
854 | template<typename... _UTypes> |
855 | tuple(_UTypes...) -> tuple<_UTypes...>; |
856 | template<typename _T1, typename _T2> |
857 | tuple(pair<_T1, _T2>) -> tuple<_T1, _T2>; |
858 | template<typename _Alloc, typename... _UTypes> |
859 | tuple(allocator_arg_t, _Alloc, _UTypes...) -> tuple<_UTypes...>; |
860 | template<typename _Alloc, typename _T1, typename _T2> |
861 | tuple(allocator_arg_t, _Alloc, pair<_T1, _T2>) -> tuple<_T1, _T2>; |
862 | template<typename _Alloc, typename... _UTypes> |
863 | tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) -> tuple<_UTypes...>; |
864 | #endif |
865 | |
866 | // Explicit specialization, zero-element tuple. |
867 | template<> |
868 | class tuple<> |
869 | { |
870 | public: |
871 | void swap(tuple&) noexcept { /* no-op */ } |
872 | // We need the default since we're going to define no-op |
873 | // allocator constructors. |
874 | tuple() = default; |
875 | // No-op allocator constructors. |
876 | template<typename _Alloc> |
877 | _GLIBCXX20_CONSTEXPR |
878 | tuple(allocator_arg_t, const _Alloc&) noexcept { } |
879 | template<typename _Alloc> |
880 | _GLIBCXX20_CONSTEXPR |
881 | tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { } |
882 | }; |
883 | |
884 | /// Partial specialization, 2-element tuple. |
885 | /// Includes construction and assignment from a pair. |
886 | template<typename _T1, typename _T2> |
887 | class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2> |
888 | { |
889 | typedef _Tuple_impl<0, _T1, _T2> _Inherited; |
890 | |
891 | // Constraint for non-explicit default constructor |
892 | template<bool _Dummy, typename _U1, typename _U2> |
893 | using _ImplicitDefaultCtor = __enable_if_t< |
894 | _TupleConstraints<_Dummy, _U1, _U2>:: |
895 | __is_implicitly_default_constructible(), |
896 | bool>; |
897 | |
898 | // Constraint for explicit default constructor |
899 | template<bool _Dummy, typename _U1, typename _U2> |
900 | using _ExplicitDefaultCtor = __enable_if_t< |
901 | _TupleConstraints<_Dummy, _U1, _U2>:: |
902 | __is_explicitly_default_constructible(), |
903 | bool>; |
904 | |
905 | template<bool _Dummy> |
906 | using _TCC = _TupleConstraints<_Dummy, _T1, _T2>; |
907 | |
908 | // Constraint for non-explicit constructors |
909 | template<bool _Cond, typename _U1, typename _U2> |
910 | using _ImplicitCtor = __enable_if_t< |
911 | _TCC<_Cond>::template __is_implicitly_constructible<_U1, _U2>(), |
912 | bool>; |
913 | |
914 | // Constraint for non-explicit constructors |
915 | template<bool _Cond, typename _U1, typename _U2> |
916 | using _ExplicitCtor = __enable_if_t< |
917 | _TCC<_Cond>::template __is_explicitly_constructible<_U1, _U2>(), |
918 | bool>; |
919 | |
920 | template<typename _U1, typename _U2> |
921 | static constexpr bool __assignable() |
922 | { |
923 | return __and_<is_assignable<_T1&, _U1>, |
924 | is_assignable<_T2&, _U2>>::value; |
925 | } |
926 | |
927 | template<typename _U1, typename _U2> |
928 | static constexpr bool __nothrow_assignable() |
929 | { |
930 | return __and_<is_nothrow_assignable<_T1&, _U1>, |
931 | is_nothrow_assignable<_T2&, _U2>>::value; |
932 | } |
933 | |
934 | template<typename _U1, typename _U2> |
935 | static constexpr bool __nothrow_constructible() |
936 | { |
937 | return __and_<is_nothrow_constructible<_T1, _U1>, |
938 | is_nothrow_constructible<_T2, _U2>>::value; |
939 | } |
940 | |
941 | static constexpr bool __nothrow_default_constructible() |
942 | { |
943 | return __and_<is_nothrow_default_constructible<_T1>, |
944 | is_nothrow_default_constructible<_T2>>::value; |
945 | } |
946 | |
947 | template<typename _U1> |
948 | static constexpr bool __is_alloc_arg() |
949 | { return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; } |
950 | |
951 | public: |
952 | template<bool _Dummy = true, |
953 | _ImplicitDefaultCtor<_Dummy, _T1, _T2> = true> |
954 | constexpr |
955 | tuple() |
956 | noexcept(__nothrow_default_constructible()) |
957 | : _Inherited() { } |
958 | |
959 | template<bool _Dummy = true, |
960 | _ExplicitDefaultCtor<_Dummy, _T1, _T2> = false> |
961 | explicit constexpr |
962 | tuple() |
963 | noexcept(__nothrow_default_constructible()) |
964 | : _Inherited() { } |
965 | |
966 | template<bool _Dummy = true, |
967 | _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true> |
968 | constexpr |
969 | tuple(const _T1& __a1, const _T2& __a2) |
970 | noexcept(__nothrow_constructible<const _T1&, const _T2&>()) |
971 | : _Inherited(__a1, __a2) { } |
972 | |
973 | template<bool _Dummy = true, |
974 | _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false> |
975 | explicit constexpr |
976 | tuple(const _T1& __a1, const _T2& __a2) |
977 | noexcept(__nothrow_constructible<const _T1&, const _T2&>()) |
978 | : _Inherited(__a1, __a2) { } |
979 | |
980 | template<typename _U1, typename _U2, |
981 | _ImplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = true> |
982 | constexpr |
983 | tuple(_U1&& __a1, _U2&& __a2) |
984 | noexcept(__nothrow_constructible<_U1, _U2>()) |
985 | : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } |
986 | |
987 | template<typename _U1, typename _U2, |
988 | _ExplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = false> |
989 | explicit constexpr |
990 | tuple(_U1&& __a1, _U2&& __a2) |
991 | noexcept(__nothrow_constructible<_U1, _U2>()) |
992 | : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } |
993 | |
994 | constexpr tuple(const tuple&) = default; |
995 | |
996 | constexpr tuple(tuple&&) = default; |
997 | |
998 | template<typename _U1, typename _U2, |
999 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
1000 | constexpr |
1001 | tuple(const tuple<_U1, _U2>& __in) |
1002 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
1003 | : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } |
1004 | |
1005 | template<typename _U1, typename _U2, |
1006 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
1007 | explicit constexpr |
1008 | tuple(const tuple<_U1, _U2>& __in) |
1009 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
1010 | : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } |
1011 | |
1012 | template<typename _U1, typename _U2, |
1013 | _ImplicitCtor<true, _U1, _U2> = true> |
1014 | constexpr |
1015 | tuple(tuple<_U1, _U2>&& __in) |
1016 | noexcept(__nothrow_constructible<_U1, _U2>()) |
1017 | : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } |
1018 | |
1019 | template<typename _U1, typename _U2, |
1020 | _ExplicitCtor<true, _U1, _U2> = false> |
1021 | explicit constexpr |
1022 | tuple(tuple<_U1, _U2>&& __in) |
1023 | noexcept(__nothrow_constructible<_U1, _U2>()) |
1024 | : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } |
1025 | |
1026 | template<typename _U1, typename _U2, |
1027 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
1028 | constexpr |
1029 | tuple(const pair<_U1, _U2>& __in) |
1030 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
1031 | : _Inherited(__in.first, __in.second) { } |
1032 | |
1033 | template<typename _U1, typename _U2, |
1034 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
1035 | explicit constexpr |
1036 | tuple(const pair<_U1, _U2>& __in) |
1037 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
1038 | : _Inherited(__in.first, __in.second) { } |
1039 | |
1040 | template<typename _U1, typename _U2, |
1041 | _ImplicitCtor<true, _U1, _U2> = true> |
1042 | constexpr |
1043 | tuple(pair<_U1, _U2>&& __in) |
1044 | noexcept(__nothrow_constructible<_U1, _U2>()) |
1045 | : _Inherited(std::forward<_U1>(__in.first), |
1046 | std::forward<_U2>(__in.second)) { } |
1047 | |
1048 | template<typename _U1, typename _U2, |
1049 | _ExplicitCtor<true, _U1, _U2> = false> |
1050 | explicit constexpr |
1051 | tuple(pair<_U1, _U2>&& __in) |
1052 | noexcept(__nothrow_constructible<_U1, _U2>()) |
1053 | : _Inherited(std::forward<_U1>(__in.first), |
1054 | std::forward<_U2>(__in.second)) { } |
1055 | |
1056 | // Allocator-extended constructors. |
1057 | |
1058 | template<typename _Alloc, |
1059 | _ImplicitDefaultCtor<is_object<_Alloc>::value, _T1, _T2> = true> |
1060 | _GLIBCXX20_CONSTEXPR |
1061 | tuple(allocator_arg_t __tag, const _Alloc& __a) |
1062 | : _Inherited(__tag, __a) { } |
1063 | |
1064 | template<typename _Alloc, bool _Dummy = true, |
1065 | _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true> |
1066 | _GLIBCXX20_CONSTEXPR |
1067 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1068 | const _T1& __a1, const _T2& __a2) |
1069 | : _Inherited(__tag, __a, __a1, __a2) { } |
1070 | |
1071 | template<typename _Alloc, bool _Dummy = true, |
1072 | _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false> |
1073 | explicit |
1074 | _GLIBCXX20_CONSTEXPR |
1075 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1076 | const _T1& __a1, const _T2& __a2) |
1077 | : _Inherited(__tag, __a, __a1, __a2) { } |
1078 | |
1079 | template<typename _Alloc, typename _U1, typename _U2, |
1080 | _ImplicitCtor<true, _U1, _U2> = true> |
1081 | _GLIBCXX20_CONSTEXPR |
1082 | tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) |
1083 | : _Inherited(__tag, __a, std::forward<_U1>(__a1), |
1084 | std::forward<_U2>(__a2)) { } |
1085 | |
1086 | template<typename _Alloc, typename _U1, typename _U2, |
1087 | _ExplicitCtor<true, _U1, _U2> = false> |
1088 | explicit |
1089 | _GLIBCXX20_CONSTEXPR |
1090 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1091 | _U1&& __a1, _U2&& __a2) |
1092 | : _Inherited(__tag, __a, std::forward<_U1>(__a1), |
1093 | std::forward<_U2>(__a2)) { } |
1094 | |
1095 | template<typename _Alloc> |
1096 | _GLIBCXX20_CONSTEXPR |
1097 | tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) |
1098 | : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } |
1099 | |
1100 | template<typename _Alloc> |
1101 | _GLIBCXX20_CONSTEXPR |
1102 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) |
1103 | : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } |
1104 | |
1105 | template<typename _Alloc, typename _U1, typename _U2, |
1106 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
1107 | _GLIBCXX20_CONSTEXPR |
1108 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1109 | const tuple<_U1, _U2>& __in) |
1110 | : _Inherited(__tag, __a, |
1111 | static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) |
1112 | { } |
1113 | |
1114 | template<typename _Alloc, typename _U1, typename _U2, |
1115 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
1116 | explicit |
1117 | _GLIBCXX20_CONSTEXPR |
1118 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1119 | const tuple<_U1, _U2>& __in) |
1120 | : _Inherited(__tag, __a, |
1121 | static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) |
1122 | { } |
1123 | |
1124 | template<typename _Alloc, typename _U1, typename _U2, |
1125 | _ImplicitCtor<true, _U1, _U2> = true> |
1126 | _GLIBCXX20_CONSTEXPR |
1127 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) |
1128 | : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) |
1129 | { } |
1130 | |
1131 | template<typename _Alloc, typename _U1, typename _U2, |
1132 | _ExplicitCtor<true, _U1, _U2> = false> |
1133 | explicit |
1134 | _GLIBCXX20_CONSTEXPR |
1135 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) |
1136 | : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) |
1137 | { } |
1138 | |
1139 | template<typename _Alloc, typename _U1, typename _U2, |
1140 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
1141 | _GLIBCXX20_CONSTEXPR |
1142 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1143 | const pair<_U1, _U2>& __in) |
1144 | : _Inherited(__tag, __a, __in.first, __in.second) { } |
1145 | |
1146 | template<typename _Alloc, typename _U1, typename _U2, |
1147 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
1148 | explicit |
1149 | _GLIBCXX20_CONSTEXPR |
1150 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
1151 | const pair<_U1, _U2>& __in) |
1152 | : _Inherited(__tag, __a, __in.first, __in.second) { } |
1153 | |
1154 | template<typename _Alloc, typename _U1, typename _U2, |
1155 | _ImplicitCtor<true, _U1, _U2> = true> |
1156 | _GLIBCXX20_CONSTEXPR |
1157 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) |
1158 | : _Inherited(__tag, __a, std::forward<_U1>(__in.first), |
1159 | std::forward<_U2>(__in.second)) { } |
1160 | |
1161 | template<typename _Alloc, typename _U1, typename _U2, |
1162 | _ExplicitCtor<true, _U1, _U2> = false> |
1163 | explicit |
1164 | _GLIBCXX20_CONSTEXPR |
1165 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) |
1166 | : _Inherited(__tag, __a, std::forward<_U1>(__in.first), |
1167 | std::forward<_U2>(__in.second)) { } |
1168 | |
1169 | // Tuple assignment. |
1170 | |
1171 | _GLIBCXX20_CONSTEXPR |
1172 | tuple& |
1173 | operator=(typename conditional<__assignable<const _T1&, const _T2&>(), |
1174 | const tuple&, |
1175 | const __nonesuch&>::type __in) |
1176 | noexcept(__nothrow_assignable<const _T1&, const _T2&>()) |
1177 | { |
1178 | this->_M_assign(__in); |
1179 | return *this; |
1180 | } |
1181 | |
1182 | _GLIBCXX20_CONSTEXPR |
1183 | tuple& |
1184 | operator=(typename conditional<__assignable<_T1, _T2>(), |
1185 | tuple&&, |
1186 | __nonesuch&&>::type __in) |
1187 | noexcept(__nothrow_assignable<_T1, _T2>()) |
1188 | { |
1189 | this->_M_assign(std::move(__in)); |
1190 | return *this; |
1191 | } |
1192 | |
1193 | template<typename _U1, typename _U2> |
1194 | _GLIBCXX20_CONSTEXPR |
1195 | __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&> |
1196 | operator=(const tuple<_U1, _U2>& __in) |
1197 | noexcept(__nothrow_assignable<const _U1&, const _U2&>()) |
1198 | { |
1199 | this->_M_assign(__in); |
1200 | return *this; |
1201 | } |
1202 | |
1203 | template<typename _U1, typename _U2> |
1204 | _GLIBCXX20_CONSTEXPR |
1205 | __enable_if_t<__assignable<_U1, _U2>(), tuple&> |
1206 | operator=(tuple<_U1, _U2>&& __in) |
1207 | noexcept(__nothrow_assignable<_U1, _U2>()) |
1208 | { |
1209 | this->_M_assign(std::move(__in)); |
1210 | return *this; |
1211 | } |
1212 | |
1213 | template<typename _U1, typename _U2> |
1214 | _GLIBCXX20_CONSTEXPR |
1215 | __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&> |
1216 | operator=(const pair<_U1, _U2>& __in) |
1217 | noexcept(__nothrow_assignable<const _U1&, const _U2&>()) |
1218 | { |
1219 | this->_M_head(*this) = __in.first; |
1220 | this->_M_tail(*this)._M_head(*this) = __in.second; |
1221 | return *this; |
1222 | } |
1223 | |
1224 | template<typename _U1, typename _U2> |
1225 | _GLIBCXX20_CONSTEXPR |
1226 | __enable_if_t<__assignable<_U1, _U2>(), tuple&> |
1227 | operator=(pair<_U1, _U2>&& __in) |
1228 | noexcept(__nothrow_assignable<_U1, _U2>()) |
1229 | { |
1230 | this->_M_head(*this) = std::forward<_U1>(__in.first); |
1231 | this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second); |
1232 | return *this; |
1233 | } |
1234 | |
1235 | _GLIBCXX20_CONSTEXPR |
1236 | void |
1237 | swap(tuple& __in) |
1238 | noexcept(__and_<__is_nothrow_swappable<_T1>, |
1239 | __is_nothrow_swappable<_T2>>::value) |
1240 | { _Inherited::_M_swap(__in); } |
1241 | }; |
1242 | |
1243 | |
1244 | /// class tuple_size |
1245 | template<typename... _Elements> |
1246 | struct tuple_size<tuple<_Elements...>> |
1247 | : public integral_constant<std::size_t, sizeof...(_Elements)> { }; |
1248 | |
1249 | #if __cplusplus201703L > 201402L |
1250 | template <typename _Tp> |
1251 | inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value; |
1252 | #endif |
1253 | |
1254 | /** |
1255 | * Recursive case for tuple_element: strip off the first element in |
1256 | * the tuple and retrieve the (i-1)th element of the remaining tuple. |
1257 | */ |
1258 | template<std::size_t __i, typename _Head, typename... _Tail> |
1259 | struct tuple_element<__i, tuple<_Head, _Tail...> > |
1260 | : tuple_element<__i - 1, tuple<_Tail...> > { }; |
1261 | |
1262 | /** |
1263 | * Basis case for tuple_element: The first element is the one we're seeking. |
1264 | */ |
1265 | template<typename _Head, typename... _Tail> |
1266 | struct tuple_element<0, tuple<_Head, _Tail...> > |
1267 | { |
1268 | typedef _Head type; |
1269 | }; |
1270 | |
1271 | /** |
1272 | * Error case for tuple_element: invalid index. |
1273 | */ |
1274 | template<size_t __i> |
1275 | struct tuple_element<__i, tuple<>> |
1276 | { |
1277 | static_assert(__i < tuple_size<tuple<>>::value, |
1278 | "tuple index is in range"); |
1279 | }; |
1280 | |
1281 | template<std::size_t __i, typename _Head, typename... _Tail> |
1282 | constexpr _Head& |
1283 | __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
1284 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
1285 | |
1286 | template<std::size_t __i, typename _Head, typename... _Tail> |
1287 | constexpr const _Head& |
1288 | __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
1289 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
1290 | |
1291 | /// Return a reference to the ith element of a tuple. |
1292 | template<std::size_t __i, typename... _Elements> |
1293 | constexpr __tuple_element_t<__i, tuple<_Elements...>>& |
1294 | get(tuple<_Elements...>& __t) noexcept |
1295 | { return std::__get_helper<__i>(__t); } |
1296 | |
1297 | /// Return a const reference to the ith element of a const tuple. |
1298 | template<std::size_t __i, typename... _Elements> |
1299 | constexpr const __tuple_element_t<__i, tuple<_Elements...>>& |
1300 | get(const tuple<_Elements...>& __t) noexcept |
1301 | { return std::__get_helper<__i>(__t); } |
1302 | |
1303 | /// Return an rvalue reference to the ith element of a tuple rvalue. |
1304 | template<std::size_t __i, typename... _Elements> |
1305 | constexpr __tuple_element_t<__i, tuple<_Elements...>>&& |
1306 | get(tuple<_Elements...>&& __t) noexcept |
1307 | { |
1308 | typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type; |
1309 | return std::forward<__element_type&&>(std::get<__i>(__t)); |
1310 | } |
1311 | |
1312 | /// Return a const rvalue reference to the ith element of a const tuple rvalue. |
1313 | template<std::size_t __i, typename... _Elements> |
1314 | constexpr const __tuple_element_t<__i, tuple<_Elements...>>&& |
1315 | get(const tuple<_Elements...>&& __t) noexcept |
1316 | { |
1317 | typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type; |
1318 | return std::forward<const __element_type&&>(std::get<__i>(__t)); |
1319 | } |
1320 | |
1321 | #if __cplusplus201703L >= 201402L |
1322 | |
1323 | #define __cpp_lib_tuples_by_type201304 201304 |
1324 | |
1325 | template<typename _Head, size_t __i, typename... _Tail> |
1326 | constexpr _Head& |
1327 | __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
1328 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
1329 | |
1330 | template<typename _Head, size_t __i, typename... _Tail> |
1331 | constexpr const _Head& |
1332 | __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
1333 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
1334 | |
1335 | /// Return a reference to the unique element of type _Tp of a tuple. |
1336 | template <typename _Tp, typename... _Types> |
1337 | constexpr _Tp& |
1338 | get(tuple<_Types...>& __t) noexcept |
1339 | { return std::__get_helper2<_Tp>(__t); } |
1340 | |
1341 | /// Return a reference to the unique element of type _Tp of a tuple rvalue. |
1342 | template <typename _Tp, typename... _Types> |
1343 | constexpr _Tp&& |
1344 | get(tuple<_Types...>&& __t) noexcept |
1345 | { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } |
1346 | |
1347 | /// Return a const reference to the unique element of type _Tp of a tuple. |
1348 | template <typename _Tp, typename... _Types> |
1349 | constexpr const _Tp& |
1350 | get(const tuple<_Types...>& __t) noexcept |
1351 | { return std::__get_helper2<_Tp>(__t); } |
1352 | |
1353 | /// Return a const reference to the unique element of type _Tp of |
1354 | /// a const tuple rvalue. |
1355 | template <typename _Tp, typename... _Types> |
1356 | constexpr const _Tp&& |
1357 | get(const tuple<_Types...>&& __t) noexcept |
1358 | { return std::forward<const _Tp&&>(std::__get_helper2<_Tp>(__t)); } |
1359 | #endif |
1360 | |
1361 | // This class performs the comparison operations on tuples |
1362 | template<typename _Tp, typename _Up, size_t __i, size_t __size> |
1363 | struct __tuple_compare |
1364 | { |
1365 | static constexpr bool |
1366 | __eq(const _Tp& __t, const _Up& __u) |
1367 | { |
1368 | return bool(std::get<__i>(__t) == std::get<__i>(__u)) |
1369 | && __tuple_compare<_Tp, _Up, __i + 1, __size>::__eq(__t, __u); |
1370 | } |
1371 | |
1372 | static constexpr bool |
1373 | __less(const _Tp& __t, const _Up& __u) |
1374 | { |
1375 | return bool(std::get<__i>(__t) < std::get<__i>(__u)) |
1376 | || (!bool(std::get<__i>(__u) < std::get<__i>(__t)) |
1377 | && __tuple_compare<_Tp, _Up, __i + 1, __size>::__less(__t, __u)); |
1378 | } |
1379 | }; |
1380 | |
1381 | template<typename _Tp, typename _Up, size_t __size> |
1382 | struct __tuple_compare<_Tp, _Up, __size, __size> |
1383 | { |
1384 | static constexpr bool |
1385 | __eq(const _Tp&, const _Up&) { return true; } |
1386 | |
1387 | static constexpr bool |
1388 | __less(const _Tp&, const _Up&) { return false; } |
1389 | }; |
1390 | |
1391 | template<typename... _TElements, typename... _UElements> |
1392 | constexpr bool |
1393 | operator==(const tuple<_TElements...>& __t, |
1394 | const tuple<_UElements...>& __u) |
1395 | { |
1396 | static_assert(sizeof...(_TElements) == sizeof...(_UElements), |
1397 | "tuple objects can only be compared if they have equal sizes."); |
1398 | using __compare = __tuple_compare<tuple<_TElements...>, |
1399 | tuple<_UElements...>, |
1400 | 0, sizeof...(_TElements)>; |
1401 | return __compare::__eq(__t, __u); |
1402 | } |
1403 | |
1404 | #if __cpp_lib_three_way_comparison |
1405 | template<typename _Cat, typename _Tp, typename _Up> |
1406 | constexpr _Cat |
1407 | __tuple_cmp(const _Tp&, const _Up&, index_sequence<>) |
1408 | { return _Cat::equivalent; } |
1409 | |
1410 | template<typename _Cat, typename _Tp, typename _Up, |
1411 | size_t _Idx0, size_t... _Idxs> |
1412 | constexpr _Cat |
1413 | __tuple_cmp(const _Tp& __t, const _Up& __u, |
1414 | index_sequence<_Idx0, _Idxs...>) |
1415 | { |
1416 | auto __c |
1417 | = __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u)); |
1418 | if (__c != 0) |
1419 | return __c; |
1420 | return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>()); |
1421 | } |
1422 | |
1423 | template<typename... _Tps, typename... _Ups> |
1424 | constexpr |
1425 | common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...> |
1426 | operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u) |
1427 | { |
1428 | using _Cat |
1429 | = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>; |
1430 | return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>()); |
1431 | } |
1432 | #else |
1433 | template<typename... _TElements, typename... _UElements> |
1434 | constexpr bool |
1435 | operator<(const tuple<_TElements...>& __t, |
1436 | const tuple<_UElements...>& __u) |
1437 | { |
1438 | static_assert(sizeof...(_TElements) == sizeof...(_UElements), |
1439 | "tuple objects can only be compared if they have equal sizes."); |
1440 | using __compare = __tuple_compare<tuple<_TElements...>, |
1441 | tuple<_UElements...>, |
1442 | 0, sizeof...(_TElements)>; |
1443 | return __compare::__less(__t, __u); |
1444 | } |
1445 | |
1446 | template<typename... _TElements, typename... _UElements> |
1447 | constexpr bool |
1448 | operator!=(const tuple<_TElements...>& __t, |
1449 | const tuple<_UElements...>& __u) |
1450 | { return !(__t == __u); } |
1451 | |
1452 | template<typename... _TElements, typename... _UElements> |
1453 | constexpr bool |
1454 | operator>(const tuple<_TElements...>& __t, |
1455 | const tuple<_UElements...>& __u) |
1456 | { return __u < __t; } |
1457 | |
1458 | template<typename... _TElements, typename... _UElements> |
1459 | constexpr bool |
1460 | operator<=(const tuple<_TElements...>& __t, |
1461 | const tuple<_UElements...>& __u) |
1462 | { return !(__u < __t); } |
1463 | |
1464 | template<typename... _TElements, typename... _UElements> |
1465 | constexpr bool |
1466 | operator>=(const tuple<_TElements...>& __t, |
1467 | const tuple<_UElements...>& __u) |
1468 | { return !(__t < __u); } |
1469 | #endif // three_way_comparison |
1470 | |
1471 | // NB: DR 705. |
1472 | template<typename... _Elements> |
1473 | constexpr tuple<typename __decay_and_strip<_Elements>::__type...> |
1474 | make_tuple(_Elements&&... __args) |
1475 | { |
1476 | typedef tuple<typename __decay_and_strip<_Elements>::__type...> |
1477 | __result_type; |
1478 | return __result_type(std::forward<_Elements>(__args)...); |
1479 | } |
1480 | |
1481 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1482 | // 2275. Why is forward_as_tuple not constexpr? |
1483 | /// std::forward_as_tuple |
1484 | template<typename... _Elements> |
1485 | constexpr tuple<_Elements&&...> |
1486 | forward_as_tuple(_Elements&&... __args) noexcept |
1487 | { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } |
1488 | |
1489 | template<size_t, typename, typename, size_t> |
1490 | struct __make_tuple_impl; |
1491 | |
1492 | template<size_t _Idx, typename _Tuple, typename... _Tp, size_t _Nm> |
1493 | struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm> |
1494 | : __make_tuple_impl<_Idx + 1, |
1495 | tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>, |
1496 | _Tuple, _Nm> |
1497 | { }; |
1498 | |
1499 | template<std::size_t _Nm, typename _Tuple, typename... _Tp> |
1500 | struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm> |
1501 | { |
1502 | typedef tuple<_Tp...> __type; |
1503 | }; |
1504 | |
1505 | template<typename _Tuple> |
1506 | struct __do_make_tuple |
1507 | : __make_tuple_impl<0, tuple<>, _Tuple, std::tuple_size<_Tuple>::value> |
1508 | { }; |
1509 | |
1510 | // Returns the std::tuple equivalent of a tuple-like type. |
1511 | template<typename _Tuple> |
1512 | struct __make_tuple |
1513 | : public __do_make_tuple<__remove_cvref_t<_Tuple>> |
1514 | { }; |
1515 | |
1516 | // Combines several std::tuple's into a single one. |
1517 | template<typename...> |
1518 | struct __combine_tuples; |
1519 | |
1520 | template<> |
1521 | struct __combine_tuples<> |
1522 | { |
1523 | typedef tuple<> __type; |
1524 | }; |
1525 | |
1526 | template<typename... _Ts> |
1527 | struct __combine_tuples<tuple<_Ts...>> |
1528 | { |
1529 | typedef tuple<_Ts...> __type; |
1530 | }; |
1531 | |
1532 | template<typename... _T1s, typename... _T2s, typename... _Rem> |
1533 | struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...> |
1534 | { |
1535 | typedef typename __combine_tuples<tuple<_T1s..., _T2s...>, |
1536 | _Rem...>::__type __type; |
1537 | }; |
1538 | |
1539 | // Computes the result type of tuple_cat given a set of tuple-like types. |
1540 | template<typename... _Tpls> |
1541 | struct __tuple_cat_result |
1542 | { |
1543 | typedef typename __combine_tuples |
1544 | <typename __make_tuple<_Tpls>::__type...>::__type __type; |
1545 | }; |
1546 | |
1547 | // Helper to determine the index set for the first tuple-like |
1548 | // type of a given set. |
1549 | template<typename...> |
1550 | struct __make_1st_indices; |
1551 | |
1552 | template<> |
1553 | struct __make_1st_indices<> |
1554 | { |
1555 | typedef std::_Index_tuple<> __type; |
1556 | }; |
1557 | |
1558 | template<typename _Tp, typename... _Tpls> |
1559 | struct __make_1st_indices<_Tp, _Tpls...> |
1560 | { |
1561 | typedef typename std::_Build_index_tuple<std::tuple_size< |
1562 | typename std::remove_reference<_Tp>::type>::value>::__type __type; |
1563 | }; |
1564 | |
1565 | // Performs the actual concatenation by step-wise expanding tuple-like |
1566 | // objects into the elements, which are finally forwarded into the |
1567 | // result tuple. |
1568 | template<typename _Ret, typename _Indices, typename... _Tpls> |
1569 | struct __tuple_concater; |
1570 | |
1571 | template<typename _Ret, std::size_t... _Is, typename _Tp, typename... _Tpls> |
1572 | struct __tuple_concater<_Ret, std::_Index_tuple<_Is...>, _Tp, _Tpls...> |
1573 | { |
1574 | template<typename... _Us> |
1575 | static constexpr _Ret |
1576 | _S_do(_Tp&& __tp, _Tpls&&... __tps, _Us&&... __us) |
1577 | { |
1578 | typedef typename __make_1st_indices<_Tpls...>::__type __idx; |
1579 | typedef __tuple_concater<_Ret, __idx, _Tpls...> __next; |
1580 | return __next::_S_do(std::forward<_Tpls>(__tps)..., |
1581 | std::forward<_Us>(__us)..., |
1582 | std::get<_Is>(std::forward<_Tp>(__tp))...); |
1583 | } |
1584 | }; |
1585 | |
1586 | template<typename _Ret> |
1587 | struct __tuple_concater<_Ret, std::_Index_tuple<>> |
1588 | { |
1589 | template<typename... _Us> |
1590 | static constexpr _Ret |
1591 | _S_do(_Us&&... __us) |
1592 | { |
1593 | return _Ret(std::forward<_Us>(__us)...); |
1594 | } |
1595 | }; |
1596 | |
1597 | /// tuple_cat |
1598 | template<typename... _Tpls, typename = typename |
1599 | enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type> |
1600 | constexpr auto |
1601 | tuple_cat(_Tpls&&... __tpls) |
1602 | -> typename __tuple_cat_result<_Tpls...>::__type |
1603 | { |
1604 | typedef typename __tuple_cat_result<_Tpls...>::__type __ret; |
1605 | typedef typename __make_1st_indices<_Tpls...>::__type __idx; |
1606 | typedef __tuple_concater<__ret, __idx, _Tpls...> __concater; |
1607 | return __concater::_S_do(std::forward<_Tpls>(__tpls)...); |
1608 | } |
1609 | |
1610 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1611 | // 2301. Why is tie not constexpr? |
1612 | /// tie |
1613 | template<typename... _Elements> |
1614 | constexpr tuple<_Elements&...> |
1615 | tie(_Elements&... __args) noexcept |
1616 | { return tuple<_Elements&...>(__args...); } |
1617 | |
1618 | /// swap |
1619 | template<typename... _Elements> |
1620 | _GLIBCXX20_CONSTEXPR |
1621 | inline |
1622 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
1623 | // Constrained free swap overload, see p0185r1 |
1624 | typename enable_if<__and_<__is_swappable<_Elements>...>::value |
1625 | >::type |
1626 | #else |
1627 | void |
1628 | #endif |
1629 | swap(tuple<_Elements...>& __x, tuple<_Elements...>& __y) |
1630 | noexcept(noexcept(__x.swap(__y))) |
1631 | { __x.swap(__y); } |
1632 | |
1633 | #if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
1634 | template<typename... _Elements> |
1635 | _GLIBCXX20_CONSTEXPR |
1636 | typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type |
1637 | swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete; |
1638 | #endif |
1639 | |
1640 | // A class (and instance) which can be used in 'tie' when an element |
1641 | // of a tuple is not required. |
1642 | // _GLIBCXX14_CONSTEXPR |
1643 | // 2933. PR for LWG 2773 could be clearer |
1644 | struct _Swallow_assign |
1645 | { |
1646 | template<class _Tp> |
1647 | _GLIBCXX14_CONSTEXPRconstexpr const _Swallow_assign& |
1648 | operator=(const _Tp&) const |
1649 | { return *this; } |
1650 | }; |
1651 | |
1652 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1653 | // 2773. Making std::ignore constexpr |
1654 | _GLIBCXX17_INLINEinline constexpr _Swallow_assign ignore{}; |
1655 | |
1656 | /// Partial specialization for tuples |
1657 | template<typename... _Types, typename _Alloc> |
1658 | struct uses_allocator<tuple<_Types...>, _Alloc> : true_type { }; |
1659 | |
1660 | // See stl_pair.h... |
1661 | /** "piecewise construction" using a tuple of arguments for each member. |
1662 | * |
1663 | * @param __first Arguments for the first member of the pair. |
1664 | * @param __second Arguments for the second member of the pair. |
1665 | * |
1666 | * The elements of each tuple will be used as the constructor arguments |
1667 | * for the data members of the pair. |
1668 | */ |
1669 | template<class _T1, class _T2> |
1670 | template<typename... _Args1, typename... _Args2> |
1671 | _GLIBCXX20_CONSTEXPR |
1672 | inline |
1673 | pair<_T1, _T2>:: |
1674 | pair(piecewise_construct_t, |
1675 | tuple<_Args1...> __first, tuple<_Args2...> __second) |
1676 | : pair(__first, __second, |
1677 | typename _Build_index_tuple<sizeof...(_Args1)>::__type(), |
1678 | typename _Build_index_tuple<sizeof...(_Args2)>::__type()) |
1679 | { } |
1680 | |
1681 | template<class _T1, class _T2> |
1682 | template<typename... _Args1, std::size_t... _Indexes1, |
1683 | typename... _Args2, std::size_t... _Indexes2> |
1684 | _GLIBCXX20_CONSTEXPR inline |
1685 | pair<_T1, _T2>:: |
1686 | pair(tuple<_Args1...>& __tuple1, tuple<_Args2...>& __tuple2, |
1687 | _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>) |
1688 | : first(std::forward<_Args1>(std::get<_Indexes1>(__tuple1))...), |
1689 | second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...) |
1690 | { } |
1691 | |
1692 | #if __cplusplus201703L >= 201703L |
1693 | |
1694 | // Unpack a std::tuple into a type trait and use its value. |
1695 | // For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value. |
1696 | // For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value. |
1697 | // Otherwise the result is false (because we don't know if std::get throws). |
1698 | template<template<typename...> class _Trait, typename _Tp, typename _Tuple> |
1699 | inline constexpr bool __unpack_std_tuple = false; |
1700 | |
1701 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
1702 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>> |
1703 | = _Trait<_Tp, _Up...>::value; |
1704 | |
1705 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
1706 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&> |
1707 | = _Trait<_Tp, _Up&...>::value; |
1708 | |
1709 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
1710 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>> |
1711 | = _Trait<_Tp, const _Up...>::value; |
1712 | |
1713 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
1714 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&> |
1715 | = _Trait<_Tp, const _Up&...>::value; |
1716 | |
1717 | # define __cpp_lib_apply201603 201603 |
1718 | |
1719 | template <typename _Fn, typename _Tuple, size_t... _Idx> |
1720 | constexpr decltype(auto) |
1721 | __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>) |
1722 | { |
1723 | return std::__invoke(std::forward<_Fn>(__f), |
1724 | std::get<_Idx>(std::forward<_Tuple>(__t))...); |
1725 | } |
1726 | |
1727 | template <typename _Fn, typename _Tuple> |
1728 | constexpr decltype(auto) |
1729 | apply(_Fn&& __f, _Tuple&& __t) |
1730 | noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>) |
1731 | { |
1732 | using _Indices |
1733 | = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>; |
1734 | return std::__apply_impl(std::forward<_Fn>(__f), |
1735 | std::forward<_Tuple>(__t), |
1736 | _Indices{}); |
1737 | } |
1738 | |
1739 | #define __cpp_lib_make_from_tuple201606 201606 |
1740 | |
1741 | template <typename _Tp, typename _Tuple, size_t... _Idx> |
1742 | constexpr _Tp |
1743 | __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) |
1744 | { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } |
1745 | |
1746 | template <typename _Tp, typename _Tuple> |
1747 | constexpr _Tp |
1748 | make_from_tuple(_Tuple&& __t) |
1749 | noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) |
1750 | { |
1751 | return __make_from_tuple_impl<_Tp>( |
1752 | std::forward<_Tuple>(__t), |
1753 | make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{}); |
1754 | } |
1755 | #endif // C++17 |
1756 | |
1757 | /// @} |
1758 | |
1759 | _GLIBCXX_END_NAMESPACE_VERSION |
1760 | } // namespace std |
1761 | |
1762 | #endif // C++11 |
1763 | |
1764 | #endif // _GLIBCXX_TUPLE |
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 | #ifndef INCLUDED_SW_INC_NDTXT_HXX |
20 | #define INCLUDED_SW_INC_NDTXT_HXX |
21 | |
22 | #include <cppuhelper/weakref.hxx> |
23 | |
24 | #include "swdllapi.h" |
25 | #include "node.hxx" |
26 | #include "hintids.hxx" |
27 | #include "ndhints.hxx" |
28 | #include "SwNumberTreeTypes.hxx" |
29 | #include "IDocumentContentOperations.hxx" |
30 | #include "modeltoviewhelper.hxx" |
31 | |
32 | #include <sfx2/Metadatable.hxx> |
33 | |
34 | #include <memory> |
35 | #include <vector> |
36 | #include <set> |
37 | #include <functional> |
38 | |
39 | class SfxHint; |
40 | class SwNumRule; |
41 | class SwNodeNum; |
42 | class SvxLRSpaceItem; |
43 | |
44 | namespace utl { |
45 | class TransliterationWrapper; |
46 | } |
47 | namespace vcl |
48 | { |
49 | class Font; |
50 | } |
51 | |
52 | class SwContentFrame; |
53 | class SwTextField; |
54 | class SwTextInputField; |
55 | class SfxItemSet; |
56 | class SwUndoTransliterate; |
57 | struct SwSpellArgs; |
58 | struct SwConversionArgs; |
59 | class SwInterHyphInfo; |
60 | class SwWrongList; |
61 | class SwGrammarMarkUp; |
62 | struct SwDocStat; |
63 | struct SwParaIdleData_Impl; |
64 | enum class ExpandMode; |
65 | enum class SwFieldIds : sal_uInt16; |
66 | class SwField; |
67 | |
68 | namespace sw::mark { enum class RestoreMode; } |
69 | |
70 | namespace com::sun::star { |
71 | namespace uno { |
72 | template < class > class Sequence; |
73 | } |
74 | namespace text { class XTextContent; } |
75 | } |
76 | |
77 | typedef std::set< sal_Int32 > SwSoftPageBreakList; |
78 | |
79 | /// SwTextNode is a paragraph in the document model. |
80 | class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwTextNode |
81 | : public SwContentNode |
82 | , public ::sfx2::Metadatable |
83 | { |
84 | friend class SwContentNode; |
85 | /// For creating the first TextNode. |
86 | friend class SwDoc; ///< CTOR and AppendTextNode() |
87 | friend class SwNodes; |
88 | friend class SwTextFrame; |
89 | friend class SwScriptInfo; |
90 | |
91 | /** May be 0. It is only then not 0 if it contains hard attributes. |
92 | Therefore: never access directly! */ |
93 | std::unique_ptr<SwpHints> m_pSwpHints; |
94 | |
95 | mutable std::unique_ptr<SwNodeNum> mpNodeNum; ///< Numbering for this paragraph. |
96 | mutable std::unique_ptr<SwNodeNum> mpNodeNumRLHidden; ///< Numbering for this paragraph (hidden redlines) |
97 | |
98 | OUString m_Text; |
99 | |
100 | SwParaIdleData_Impl* m_pParaIdleData_Impl; |
101 | |
102 | /** Some of the chars this para are hidden. Paragraph has to be reformatted |
103 | on changing the view to print preview. */ |
104 | mutable bool m_bContainsHiddenChars : 1; |
105 | /// The whole paragraph is hidden because of the hidden text attribute |
106 | mutable bool m_bHiddenCharsHidePara : 1; |
107 | /// The last two flags have to be recalculated if this flag is set: |
108 | mutable bool m_bRecalcHiddenCharFlags : 1; |
109 | |
110 | mutable bool m_bLastOutlineState : 1; |
111 | bool m_bNotifiable; |
112 | |
113 | bool mbEmptyListStyleSetDueToSetOutlineLevelAttr; |
114 | |
115 | /** boolean, indicating that a <SetAttr(..)> or <ResetAttr(..)> or |
116 | <ResetAllAttr(..)> method is running. |
117 | Needed to avoid duplicate handling of attribute change actions. */ |
118 | bool mbInSetOrResetAttr; |
119 | |
120 | std::unique_ptr< OUString > m_pNumStringCache; |
121 | |
122 | css::uno::WeakReference<css::text::XTextContent> m_wXParagraph; |
123 | |
124 | // DrawingLayer FillAttributes in a preprocessed form for primitive usage |
125 | drawinglayer::attribute::SdrAllFillAttributesHelperPtr maFillAttributes; |
126 | |
127 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl, |
128 | const SfxItemSet* pAutoAttr = nullptr ); |
129 | |
130 | /// Copies the attributes at nStart to pDest. |
131 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CopyAttr( SwTextNode *pDest, const sal_Int32 nStart, const sal_Int32 nOldPos); |
132 | |
133 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwTextNode* MakeNewTextNode( const SwNodeIndex&, bool bNext = true, |
134 | bool bChgFollow = true ); |
135 | |
136 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CutImpl( |
137 | SwTextNode * const pDest, const SwIndex & rDestStart, |
138 | const SwIndex & rStart, /*const*/ sal_Int32 nLen, |
139 | const bool bUpdate = true ); |
140 | |
141 | /// Move all comprising hard attributes to the AttrSet of the paragraph. |
142 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void MoveTextAttr_To_AttrSet(); // Called by SplitNode. |
143 | |
144 | /// Create the specific AttrSet. |
145 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) virtual void NewAttrSet( SwAttrPool& ) override; |
146 | |
147 | /// Optimization: Asking for information about hidden characters at SwScriptInfo |
148 | /// updates these flags. |
149 | bool IsCalcHiddenCharFlags() const |
150 | { return m_bRecalcHiddenCharFlags; } |
151 | void SetHiddenCharAttribute( bool bNewHiddenCharsHidePara, bool bNewContainsHiddenChars ) const |
152 | { |
153 | m_bHiddenCharsHidePara = bNewHiddenCharsHidePara; |
154 | m_bContainsHiddenChars = bNewContainsHiddenChars; |
155 | m_bRecalcHiddenCharFlags = false; |
156 | } |
157 | |
158 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CalcHiddenCharFlags() const; |
159 | |
160 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void SetLanguageAndFont( const SwPaM &rPaM, |
161 | LanguageType nLang, sal_uInt16 nLangWhichId, |
162 | const vcl::Font *pFont, sal_uInt16 nFontWhichId ); |
163 | |
164 | /// Start: Data collected during idle time |
165 | |
166 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void InitSwParaStatistics( bool bNew ); |
167 | |
168 | inline void TryDeleteSwpHints(); |
169 | |
170 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void impl_FormatToTextAttr(const SfxItemSet& i_rAttrSet); |
171 | |
172 | const SwTextInputField* GetOverlappingInputField( const SwTextAttr& rTextAttr ) const; |
173 | |
174 | void DelFrames_TextNodePart(); |
175 | |
176 | public: |
177 | enum class WrongState { TODO, PENDING, DONE }; |
178 | |
179 | bool IsWordCountDirty() const; |
180 | WrongState GetWrongDirty() const; |
181 | bool IsWrongDirty() const; |
182 | bool IsGrammarCheckDirty() const; |
183 | bool IsSmartTagDirty() const; |
184 | bool IsAutoCompleteWordDirty() const; |
185 | void SetWordCountDirty( bool bNew ) const; |
186 | void SetWrongDirty(WrongState eNew) const; |
187 | void SetGrammarCheckDirty( bool bNew ) const; |
188 | void SetSmartTagDirty( bool bNew ) const; |
189 | void SetAutoCompleteWordDirty( bool bNew ) const; |
190 | void SetWrong( SwWrongList* pNew, bool bDelete = true ); |
191 | SwWrongList* GetWrong(); |
192 | const SwWrongList* GetWrong() const; |
193 | void SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete = true ); |
194 | SwGrammarMarkUp* GetGrammarCheck(); |
195 | // return SwWrongList because *function pointer* return values aren't covariant |
196 | SwWrongList const* GetGrammarCheck() const; |
197 | void SetSmartTags( SwWrongList* pNew, bool bDelete = true ); |
198 | SwWrongList* GetSmartTags(); |
199 | SwWrongList const* GetSmartTags() const; |
200 | void TryCharSetExpandToNum(const SfxItemSet& pCharSet); |
201 | |
202 | /// End: Data collected during idle time |
203 | |
204 | protected: |
205 | /// for hanging TextFormatCollections somewhere else (Outline-Numbering!) |
206 | virtual void SwClientNotify( const SwModify&, const SfxHint& ) override; |
207 | |
208 | public: |
209 | using SwContentNode::GetAttr; |
210 | |
211 | const OUString& GetText() const { return m_Text; } |
212 | |
213 | // returns the maximum number of characters that can still be added to the node |
214 | inline sal_Int32 GetSpaceLeft() const; |
215 | |
216 | /// getters for SwpHints |
217 | inline SwpHints &GetSwpHints(); |
218 | inline const SwpHints &GetSwpHints() const; |
219 | SwpHints *GetpSwpHints() { return m_pSwpHints.get(); } |
220 | const SwpHints *GetpSwpHints() const { return m_pSwpHints.get(); } |
221 | bool HasHints() const { return m_pSwpHints != nullptr; } |
222 | inline SwpHints &GetOrCreateSwpHints(); |
223 | |
224 | virtual ~SwTextNode() override; |
225 | |
226 | virtual sal_Int32 Len() const override; |
227 | |
228 | /// Is in itratr. |
229 | void GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax, sal_uLong &rAbs ) const; |
230 | |
231 | /// overriding to handle change of certain paragraph attributes |
232 | virtual bool SetAttr( const SfxPoolItem& ) override; |
233 | virtual bool SetAttr( const SfxItemSet& rSet ) override; |
234 | virtual bool ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 = 0 ) override; |
235 | virtual bool ResetAttr( const std::vector<sal_uInt16>& rWhichArr ) override; |
236 | virtual sal_uInt16 ResetAllAttr() override; |
237 | |
238 | /// insert text content |
239 | /// @param rStr text to insert; in case it does not fit into the capacity |
240 | /// of the node, the longest prefix that fits is inserted |
241 | /// @return the prefix of rStr that was actually inserted |
242 | OUString InsertText( const OUString & rStr, const SwIndex & rIdx, |
243 | const SwInsertFlags nMode |
244 | = SwInsertFlags::DEFAULT ); |
245 | |
246 | /** delete text content |
247 | ATTENTION: must not be called with a range that overlaps the start of |
248 | an attribute with both extent and dummy char |
249 | */ |
250 | void EraseText ( const SwIndex &rIdx, const sal_Int32 nCount = SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF), |
251 | const SwInsertFlags nMode = SwInsertFlags::DEFAULT ); |
252 | |
253 | /** delete all attributes. |
254 | If neither pSet nor nWhich is given, delete all attributes (except |
255 | refmarks, toxmarks, meta) in range. |
256 | @param rIdx start position |
257 | @param nLen range in which attributes will be deleted |
258 | @param pSet if not 0, delete only attributes contained in pSet |
259 | @param nWhich if not 0, delete only attributes with matching which |
260 | @param bInclRefToxMark |
261 | refmarks, toxmarks, and metas will be ignored unless this is true |
262 | ATTENTION: setting bInclRefToxMark is only allowed from UNDO! |
263 | @param bExactRange From the attributes included in the range, delete |
264 | only the ones which have exactly same range. Don't delete the ones |
265 | which are simply included in the range. |
266 | */ |
267 | void RstTextAttr( |
268 | const SwIndex &rIdx, |
269 | const sal_Int32 nLen, |
270 | const sal_uInt16 nWhich = 0, |
271 | const SfxItemSet* pSet = nullptr, |
272 | const bool bInclRefToxMark = false, |
273 | const bool bExactRange = false ); |
274 | void GCAttr(); |
275 | |
276 | // Delete text attribute (needs to be deregistered at Pool!) |
277 | void DestroyAttr( SwTextAttr* pAttr ); |
278 | |
279 | // delete all attributes from SwpHintsArray. |
280 | void ClearSwpHintsArr( bool bDelFields ); |
281 | |
282 | /// initialize the hints after file loading (which takes shortcuts) |
283 | void FileLoadedInitHints(); |
284 | |
285 | /// Insert pAttr into hints array. @return true iff inserted successfully |
286 | bool InsertHint( SwTextAttr * const pAttr, |
287 | const SetAttrMode nMode = SetAttrMode::DEFAULT ); |
288 | /// create new text attribute from rAttr and insert it |
289 | /// @return inserted hint; 0 if not sure the hint is inserted |
290 | SwTextAttr* InsertItem( SfxPoolItem& rAttr, |
291 | const sal_Int32 nStart, const sal_Int32 nEnd, |
292 | const SetAttrMode nMode = SetAttrMode::DEFAULT ); |
293 | |
294 | /** Set these attributes at TextNode. If the whole range is comprised |
295 | set them only in AutoAttrSet (SwContentNode::SetAttr). */ |
296 | bool SetAttr( const SfxItemSet& rSet, |
297 | sal_Int32 nStt, sal_Int32 nEnd, |
298 | const SetAttrMode nMode = SetAttrMode::DEFAULT, |
299 | SwTextAttr **ppNewTextAttr = nullptr); |
300 | /** Query the attributes of textnode over the range. |
301 | Introduce 4th optional parameter <bMergeIndentValuesOfNumRule>. |
302 | If <bMergeIndentValuesOfNumRule> == true, the indent attributes of |
303 | the corresponding list level of an applied list style is merged into |
304 | the requested item set as a LR-SPACE item, if <bOnlyTextAttr> == false, |
305 | corresponding node has not its own indent attributes and the |
306 | position-and-space mode of the list level is SvxNumberFormat::LABEL_ALIGNMENT. */ |
307 | bool GetParaAttr( SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd, |
308 | const bool bOnlyTextAttr = false, |
309 | const bool bGetFromChrFormat = true, |
310 | const bool bMergeIndentValuesOfNumRule = false, |
311 | SwRootFrame const* pLayout = nullptr) const; |
312 | |
313 | /// Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray. |
314 | void FormatToTextAttr( SwTextNode* pNd ); |
315 | |
316 | /// delete all attributes of type nWhich at nStart (opt. end nEnd) |
317 | void DeleteAttributes( const sal_uInt16 nWhich, |
318 | const sal_Int32 nStart, const sal_Int32 nEnd = 0 ); |
319 | /// delete the attribute pTextAttr |
320 | void DeleteAttribute ( SwTextAttr * const pTextAttr ); |
321 | |
322 | /** Actions on text and attributes. |
323 | introduce optional parameter to control, if all attributes have to be copied. */ |
324 | void CopyText( SwTextNode * const pDest, |
325 | const SwIndex &rStart, |
326 | const sal_Int32 nLen, |
327 | const bool bForceCopyOfAllAttrs ); |
328 | void CopyText( SwTextNode * const pDest, |
329 | const SwIndex &rDestStart, |
330 | const SwIndex &rStart, |
331 | sal_Int32 nLen, |
332 | const bool bForceCopyOfAllAttrs = false ); |
333 | |
334 | void CutText(SwTextNode * const pDest, |
335 | const SwIndex & rStart, const sal_Int32 nLen); |
336 | inline void CutText(SwTextNode * const pDest, const SwIndex &rDestStart, |
337 | const SwIndex & rStart, const sal_Int32 nLen); |
338 | |
339 | /// replace nDelLen characters at rStart with rText |
340 | /// in case the replacement does not fit, it is partially inserted up to |
341 | /// the capacity of the node |
342 | void ReplaceText( const SwIndex& rStart, const sal_Int32 nDelLen, |
343 | const OUString & rText ); |
344 | void ReplaceTextOnly( sal_Int32 nPos, sal_Int32 nLen, |
345 | const OUString& rText, |
346 | const css::uno::Sequence<sal_Int32>& rOffsets ); |
347 | |
348 | /// Virtual methods from ContentNode. |
349 | virtual SwContentFrame *MakeFrame( SwFrame* ) override; |
350 | SwTextNode * SplitContentNode(const SwPosition &, |
351 | std::function<void (SwTextNode *, sw::mark::RestoreMode)> const* pContentIndexRestore); |
352 | virtual SwContentNode *JoinNext() override; |
353 | void JoinPrev(); |
354 | |
355 | SwContentNode *AppendNode( const SwPosition & ); |
356 | |
357 | /// When appropriate set DontExpand-flag at INet or character styles respectively. |
358 | bool DontExpandFormat( const SwIndex& rIdx, bool bFlag = true, |
359 | bool bFormatToTextAttributes = true ); |
360 | |
361 | enum GetTextAttrMode { |
362 | DEFAULT, /// DEFAULT: (Start <= nIndex < End) |
363 | EXPAND, /// EXPAND : (Start < nIndex <= End) |
364 | PARENT, /// PARENT : (Start < nIndex < End) |
365 | }; |
366 | |
367 | /** get the innermost text attribute covering position nIndex. |
368 | @param nWhich only attribute with this id is returned. |
369 | @param eMode the predicate for matching (@see GetTextAttrMode). |
370 | |
371 | ATTENTION: this function is not well-defined for those |
372 | hints of which several may cover a single position, like |
373 | RES_TXTATR_CHARFMT, RES_TXTATR_REFMARK, RES_TXTATR_TOXMARK |
374 | */ |
375 | SwTextAttr *GetTextAttrAt( |
376 | sal_Int32 const nIndex, |
377 | sal_uInt16 const nWhich, |
378 | enum GetTextAttrMode const eMode = DEFAULT ) const; |
379 | |
380 | /** get the innermost text attributes covering position nIndex. |
381 | @param nWhich only attributes with this id are returned. |
382 | @param eMode the predicate for matching (@see GetTextAttrMode). |
383 | */ |
384 | std::vector<SwTextAttr *> GetTextAttrsAt( |
385 | sal_Int32 const nIndex, |
386 | sal_uInt16 const nWhich ) const; |
387 | |
388 | /** get the text attribute at position nIndex which owns |
389 | the dummy character CH_TXTATR_* at that position, if one exists. |
390 | @param nIndex the position in the text |
391 | @param nWhich if different from RES_TXTATR_END, return only |
392 | attribute with given which id |
393 | @return the text attribute at nIndex of type nWhich, if it exists |
394 | */ |
395 | SwTextAttr *GetTextAttrForCharAt( |
396 | const sal_Int32 nIndex, |
397 | const sal_uInt16 nWhich = RES_TXTATR_END ) const; |
398 | |
399 | SwTextField* GetFieldTextAttrAt( |
400 | const sal_Int32 nIndex, |
401 | const bool bIncludeInputFieldAtStart = false ) const; |
402 | |
403 | bool Spell(SwSpellArgs*); |
404 | bool Convert( SwConversionArgs & ); |
405 | |
406 | inline SwTextFormatColl *GetTextColl() const; |
407 | virtual SwFormatColl *ChgFormatColl( SwFormatColl* ) override; |
408 | void ChgTextCollUpdateNum( const SwTextFormatColl* pOld, |
409 | const SwTextFormatColl* pNew ); |
410 | |
411 | /** Copy collection with all auto formats to dest-node. |
412 | The latter might be in another document! |
413 | (Method in ndcopy.cxx!!). */ |
414 | void CopyCollFormat( SwTextNode& rDestNd ); |
415 | |
416 | // BEGIN OF BULLET/NUMBERING/OUTLINE STUFF: |
417 | |
418 | /** |
419 | Returns numbering rule of this text node. |
420 | |
421 | @param bInParent search in parent attributes, too |
422 | |
423 | @return numbering rule of this text node or NULL if none is set |
424 | */ |
425 | SwNumRule *GetNumRule(bool bInParent = true) const; |
426 | |
427 | const SwNodeNum* GetNum(SwRootFrame const* pLayout = nullptr) const; |
428 | void DoNum(std::function<void (SwNodeNum &)> const&); |
429 | |
430 | SwNumberTree::tNumberVector GetNumberVector(SwRootFrame const* pLayout = nullptr) const; |
431 | |
432 | /** |
433 | Returns if this text node is an outline. |
434 | |
435 | @retval true this text node is an outline |
436 | @retval false else |
437 | */ |
438 | bool IsOutline() const; |
439 | |
440 | bool IsOutlineStateChanged() const; |
441 | |
442 | void UpdateOutlineState(); |
443 | |
444 | /** |
445 | Notify this textnode that its numbering rule has changed. |
446 | */ |
447 | void NumRuleChgd(); |
448 | |
449 | /** Returns outline of numbering string |
450 | |
451 | Introduce parameter <_bInclPrefixAndSuffixStrings> in order to control, |
452 | if the prefix and the suffix strings have to been included or not. |
453 | |
454 | @param _bInclPrefixAndSuffixStrings |
455 | optional input parameter - boolean indicating, if the prefix and the |
456 | suffix strings have to been included or not. default value = <true> |
457 | |
458 | @param _nRestrictToThisLevel |
459 | optional input parameter - unsigned integer indicating the maximum outline |
460 | level to which the output string must be restricted to. Default value is |
461 | MAXLEVEL |
462 | */ |
463 | OUString GetNumString( const bool _bInclPrefixAndSuffixStrings = true, |
464 | const unsigned int _nRestrictToThisLevel = MAXLEVEL, |
465 | SwRootFrame const* pLayout = nullptr) const; |
466 | |
467 | /** |
468 | Returns the additional indents of this text node and its numbering. |
469 | |
470 | @param bTextLeft ??? |
471 | |
472 | @return additional indents |
473 | */ |
474 | long GetLeftMarginWithNum( bool bTextLeft = false ) const; |
475 | |
476 | /** |
477 | Returns the combined first line indent of this text node and |
478 | its numbering. |
479 | |
480 | @param the first line indent of this text node taking the |
481 | numbering into account (return parameter) |
482 | |
483 | @retval true this node has SwNodeNum and has numbering rule |
484 | @retval false else |
485 | */ |
486 | bool GetFirstLineOfsWithNum( short& rFirstOffset ) const; |
487 | |
488 | SwTwips GetAdditionalIndentForStartingNewList() const; |
489 | |
490 | void ClearLRSpaceItemDueToListLevelIndents( std::shared_ptr<SvxLRSpaceItem>& o_rLRSpaceItem ) const; |
491 | |
492 | /** return left margin for tab stop position calculation |
493 | |
494 | Needed for text formatting |
495 | Method considers new list level attributes, which also can provide a left margin value |
496 | */ |
497 | long GetLeftMarginForTabCalculation() const; |
498 | |
499 | /** Returns if this text node has a number. |
500 | |
501 | This text node has a number if it has a SwNodeNum and a |
502 | numbering rule and the numbering format specified for the |
503 | level of the SwNodeNum is of an enumeration type. |
504 | |
505 | @retval true This text node has a number. |
506 | @retval false else |
507 | */ |
508 | bool HasNumber() const; |
509 | |
510 | /** Returns if this text node has a bullet. |
511 | |
512 | This text node has a bullet if it has a SwNodeNum and a |
513 | numbering rule and the numbering format specified for the |
514 | level of the SwNodeNum is of a bullet type. |
515 | |
516 | @retval true This text node has a bullet. |
517 | @retval false else |
518 | */ |
519 | bool HasBullet() const; |
520 | |
521 | /** Returns is this text node is numbered. |
522 | |
523 | This node is numbered if it has a SwNodeNum and it has a |
524 | numbering rule and has not a hidden SwNodeNum. |
525 | |
526 | ATTENTION: Returns true even if the SwNumFormat has type |
527 | SVX_NUM_NUMBER_NONE. |
528 | |
529 | @retval true This node is numbered. |
530 | @retval false else |
531 | */ |
532 | bool IsNumbered(SwRootFrame const* pLayout = nullptr) const; |
533 | |
534 | /** Returns if this text node has a marked label. |
535 | |
536 | @retval true This text node has a marked label. |
537 | @retval false else |
538 | */ |
539 | bool HasMarkedLabel() const; |
540 | |
541 | /** Sets the list level of this text node. |
542 | |
543 | Side effect, when the text node is a list item: |
544 | The text node's representation in the list tree (<SwNodeNum> instance) |
545 | is updated. |
546 | |
547 | @param nLevel level to set |
548 | */ |
549 | void SetAttrListLevel(int nLevel); |
550 | |
551 | bool HasAttrListLevel() const; |
552 | |
553 | int GetAttrListLevel() const; |
554 | |
555 | /** Returns the actual list level of this text node, when it is a list item |
556 | |
557 | @return the actual list level of this text node, if it is a list item, |
558 | -1 otherwise |
559 | */ |
560 | int GetActualListLevel() const; |
561 | |
562 | /** |
563 | Returns outline level of this text node. |
564 | |
565 | If a text node has an outline number (i.e. it has an SwNodeNum |
566 | and an outline numbering rule) the outline level is the level of |
567 | this SwNodeNum. |
568 | |
569 | If a text node has no outline number and has a paragraph style |
570 | attached the outline level is the outline level of the |
571 | paragraph style. |
572 | |
573 | Otherwise the text node has no outline level (NO_NUMBERING). |
574 | |
575 | NOTE: The outline level of text nodes is subject to change. The |
576 | plan is to have an SwTextNode::nOutlineLevel member that is |
577 | updated from a paragraph style upon appliance of that paragraph |
578 | style. |
579 | |
580 | @return outline level or NO_NUMBERING if there is no outline level |
581 | */ |
582 | int GetAttrOutlineLevel() const; |
583 | |
584 | /** |
585 | Sets the out line level *at* a text node. |
586 | |
587 | @param nLevel the level to be set |
588 | |
589 | If the text node has an outline number the level is set at the |
590 | outline number. |
591 | |
592 | If the text node has no outline number but has a paragraph |
593 | style applied the outline level is set at the paragraph style. |
594 | |
595 | NOTE: This is subject to change, see GetOutlineLevel. |
596 | */ |
597 | void SetAttrOutlineLevel(int nLevel); |
598 | |
599 | /** |
600 | * @brief GetAttrOutlineContentVisible |
601 | * @param bOutlineContentVisibleAttr the value stored in RES_PARATR_GRABBAG for 'OutlineContentVisibleAttr' |
602 | * @return true if 'OutlineContentVisibleAttr' is found in RES_PARATR_GRABBAG |
603 | */ |
604 | bool GetAttrOutlineContentVisible(bool& bOutlineContentVisibleAttr); |
605 | void SetAttrOutlineContentVisible(bool bVisible); |
606 | |
607 | bool IsEmptyListStyleDueToSetOutlineLevelAttr() const { return mbEmptyListStyleSetDueToSetOutlineLevelAttr;} |
608 | void SetEmptyListStyleDueToSetOutlineLevelAttr(); |
609 | void ResetEmptyListStyleDueToResetOutlineLevelAttr(); |
610 | |
611 | /** |
612 | Returns the width of leading tabs/blanks in this paragraph. |
613 | This space will be converted into numbering indent if the paragraph |
614 | is set to be numbered. |
615 | |
616 | @return the width of the leading whitespace |
617 | */ |
618 | SwTwips GetWidthOfLeadingTabs() const; |
619 | |
620 | /** |
621 | Returns if the paragraph has a visible numbering or bullet. |
622 | This includes all kinds of numbering/bullet/outlines. |
623 | Note: This function returns false, if the numbering format is |
624 | SVX_NUM_NUMBER_NONE or if the numbering/bullet has been deleted. |
625 | |
626 | @return true if the paragraph has a visible numbering/bullet/outline |
627 | */ |
628 | bool HasVisibleNumberingOrBullet() const; |
629 | |
630 | void SetListId(OUString const& rListId); |
631 | OUString GetListId() const; |
632 | |
633 | /** Determines, if the list level indent attributes can be applied to the |
634 | paragraph. |
635 | |
636 | The list level indents can be applied to the paragraph under the one |
637 | of following conditions: |
638 | - the list style is directly applied to the paragraph and the paragraph |
639 | has no own indent attributes. |
640 | - the list style is applied to the paragraph through one of its paragraph |
641 | styles, the paragraph has no own indent attributes and on the paragraph |
642 | style hierarchy from the paragraph to the paragraph style with the |
643 | list style no indent attributes are found. |
644 | |
645 | @return boolean |
646 | */ |
647 | bool AreListLevelIndentsApplicable() const; |
648 | |
649 | /** Retrieves the list tab stop position, if the paragraph's list level defines |
650 | one and this list tab stop has to merged into the tap stops of the paragraph |
651 | |
652 | @param nListTabStopPosition |
653 | output parameter - containing the list tab stop position |
654 | |
655 | @return boolean - indicating, if a list tab stop position is provided |
656 | */ |
657 | bool GetListTabStopPosition( long& nListTabStopPosition ) const; |
658 | |
659 | /** Retrieves the character following the list label, if the paragraph's |
660 | list level defines one. |
661 | |
662 | @return the list tab stop position as string |
663 | */ |
664 | OUString GetLabelFollowedBy() const; |
665 | |
666 | // END OF BULLET/NUMBERING/OUTLINE STUFF: |
667 | |
668 | void fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const; |
669 | |
670 | LanguageType GetLang( const sal_Int32 nBegin, const sal_Int32 nLen = 0, |
671 | sal_uInt16 nScript = 0 ) const; |
672 | |
673 | /// in ndcopy.cxx |
674 | bool IsSymbolAt(sal_Int32 nBegin) const; // In itratr.cxx. |
675 | virtual SwContentNode* MakeCopy(SwDoc&, const SwNodeIndex&, bool bNewFrames) const override; |
676 | |
677 | /// Interactive hyphenation: we find TextFrame and call its CalcHyph. |
678 | bool Hyphenate( SwInterHyphInfo &rHyphInf ); |
679 | void DelSoftHyph( const sal_Int32 nStart, const sal_Int32 nEnd ); |
680 | |
681 | /** add 4th optional parameter <bAddSpaceAfterListLabelStr> indicating, |
682 | when <bWithNum = true> that a space is inserted after the string for |
683 | the list label. |
684 | add 5th optional parameter <bWithSpacesForLevel> indicating, if additional |
685 | spaces are inserted in front of the expanded text string depending on |
686 | the list level. */ |
687 | OUString GetExpandText( SwRootFrame const* pLayout, |
688 | const sal_Int32 nIdx = 0, |
689 | const sal_Int32 nLen = -1, |
690 | const bool bWithNum = false, |
691 | const bool bAddSpaceAfterListLabelStr = false, |
692 | const bool bWithSpacesForLevel = false, |
693 | const ExpandMode eAdditionalMode = ExpandMode::ExpandFootnote) const; |
694 | bool CopyExpandText( SwTextNode& rDestNd, const SwIndex* pDestIdx, |
695 | sal_Int32 nIdx, sal_Int32 nLen, |
696 | SwRootFrame const* pLayout, |
697 | bool bWithNum = false, bool bWithFootnote = true, |
698 | bool bReplaceTabsWithSpaces = false ) const; |
699 | |
700 | OUString GetRedlineText() const; |
701 | |
702 | /** @return actual count of initial chars for initial-function. |
703 | If nWishLen == 0 that of first word. */ |
704 | sal_Int32 GetDropLen(sal_Int32 nWishLen) const; |
705 | |
706 | /// Passes back info needed on the dropcap dimensions |
707 | bool GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const; |
708 | |
709 | /// Hidden Paragraph Field: |
710 | bool CalcHiddenParaField() |
711 | { return m_pSwpHints && m_pSwpHints->CalcHiddenParaField(); } |
712 | /// set CalcVisible flags |
713 | void SetCalcHiddenParaField() |
714 | { if (m_pSwpHints) m_pSwpHints->SetCalcHiddenParaField(); } |
715 | |
716 | /// is the paragraph visible? |
717 | bool IsHiddenByParaField() const |
718 | { return m_pSwpHints && m_pSwpHints->IsHiddenByParaField(); } |
719 | |
720 | /// Hidden Paragraph Field: |
721 | |
722 | bool HasHiddenCharAttribute( bool bWholePara ) const |
723 | { |
724 | if ( m_bRecalcHiddenCharFlags ) |
725 | CalcHiddenCharFlags(); |
726 | return bWholePara ? m_bHiddenCharsHidePara : m_bContainsHiddenChars; |
727 | } |
728 | |
729 | void SetCalcHiddenCharFlags() const |
730 | { m_bRecalcHiddenCharFlags = true; } |
731 | |
732 | /** @return if the node is hidden due to |
733 | 1. HiddenParaField |
734 | 2. HiddenCharAttribute |
735 | 3. HiddenSection */ |
736 | |
737 | bool IsHidden() const; |
738 | |
739 | |
740 | /// override SwIndexReg |
741 | virtual void Update( |
742 | SwIndex const & rPos, |
743 | const sal_Int32 nChangeLen, |
744 | const bool bNegative = false, |
745 | const bool bDelete = false ) override; |
746 | |
747 | /// change text to Upper/Lower/Hiragana/Katakana/... |
748 | void TransliterateText( utl::TransliterationWrapper& rTrans, |
749 | sal_Int32 nStart, sal_Int32 nEnd, |
750 | SwUndoTransliterate* pUndo ); |
751 | |
752 | /// count words in given range - returns true if we refreshed out count |
753 | bool CountWords( SwDocStat& rStat, sal_Int32 nStart, sal_Int32 nEnd ) const; |
754 | |
755 | /** Checks some global conditions like loading or destruction of document |
756 | to economize notifications */ |
757 | bool IsNotificationEnabled() const; |
758 | |
759 | /// Checks a temporary notification blocker and the global conditions of IsNotificationEnabled() |
760 | bool IsNotifiable() const; |
761 | |
762 | void SetListRestart( bool bRestart ); |
763 | bool IsListRestart() const; |
764 | |
765 | void SetAttrListRestartValue( SwNumberTree::tSwNumTreeNumber nNum ); |
766 | bool HasAttrListRestartValue() const; |
767 | SwNumberTree::tSwNumTreeNumber GetAttrListRestartValue() const; |
768 | SwNumberTree::tSwNumTreeNumber GetActualListStartValue() const; |
769 | |
770 | void SetCountedInList( bool bCounted ); |
771 | bool IsCountedInList() const; |
772 | |
773 | void AddToList(); |
774 | void AddToListRLHidden(); |
775 | void RemoveFromList(); |
776 | void RemoveFromListRLHidden(); |
777 | bool IsInList() const; |
778 | |
779 | bool IsFirstOfNumRule(SwRootFrame const& rLayout) const; |
780 | |
781 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) css::uno::WeakReference<css::text::XTextContent> const& GetXParagraph() const |
782 | { return m_wXParagraph; } |
783 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void SetXParagraph(css::uno::Reference<css::text::XTextContent> const& xParagraph) |
784 | { m_wXParagraph = xParagraph; } |
785 | |
786 | /// sfx2::Metadatable |
787 | virtual ::sfx2::IXmlIdRegistry& GetRegistry() override; |
788 | virtual bool IsInClipboard() const override; |
789 | virtual bool IsInUndo() const override; |
790 | virtual bool IsInContent() const override; |
791 | virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override; |
792 | |
793 | bool IsCollapse() const; |
794 | |
795 | virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override; |
796 | |
797 | sal_uInt32 GetRsid( sal_Int32 nStt, sal_Int32 nEnd ) const; |
798 | sal_uInt32 GetParRsid() const; |
799 | |
800 | bool CompareRsid( const SwTextNode &rTextNode, sal_Int32 nStt1, sal_Int32 nStt2 ) const; |
801 | bool CompareParRsid( const SwTextNode &rTextNode ) const; |
802 | |
803 | // Access to DrawingLayer FillAttributes in a preprocessed form for primitive usage |
804 | virtual drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const override; |
805 | |
806 | /// In MS Word, the font underline setting of the paragraph end position won't affect the formatting of numbering, so we ignore it |
807 | static bool IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich); |
808 | }; |
809 | |
810 | inline SwpHints & SwTextNode::GetSwpHints() |
811 | { |
812 | assert( m_pSwpHints )(static_cast <bool> (m_pSwpHints) ? void (0) : __assert_fail ("m_pSwpHints", "/home/maarten/src/libreoffice/core/sw/inc/ndtxt.hxx" , 812, __extension__ __PRETTY_FUNCTION__)); |
813 | return *m_pSwpHints; |
814 | } |
815 | inline const SwpHints &SwTextNode::GetSwpHints() const |
816 | { |
817 | assert( m_pSwpHints )(static_cast <bool> (m_pSwpHints) ? void (0) : __assert_fail ("m_pSwpHints", "/home/maarten/src/libreoffice/core/sw/inc/ndtxt.hxx" , 817, __extension__ __PRETTY_FUNCTION__)); |
818 | return *m_pSwpHints; |
819 | } |
820 | |
821 | inline SwpHints& SwTextNode::GetOrCreateSwpHints() |
822 | { |
823 | if ( !m_pSwpHints ) |
824 | { |
825 | m_pSwpHints.reset(new SwpHints(*this)); |
826 | } |
827 | return *m_pSwpHints; |
828 | } |
829 | |
830 | inline void SwTextNode::TryDeleteSwpHints() |
831 | { |
832 | if ( m_pSwpHints && m_pSwpHints->CanBeDeleted() ) |
833 | { |
834 | m_pSwpHints.reset(); |
835 | } |
836 | } |
837 | |
838 | inline SwTextFormatColl* SwTextNode::GetTextColl() const |
839 | { |
840 | return static_cast<SwTextFormatColl*>(const_cast<SwModify*>(GetRegisteredIn())); |
841 | } |
842 | |
843 | /// Inline methods from Node.hxx |
844 | inline SwTextNode *SwNode::GetTextNode() |
845 | { |
846 | return SwNodeType::Text == m_nNodeType ? static_cast<SwTextNode*>(this) : nullptr; |
847 | } |
848 | |
849 | inline const SwTextNode *SwNode::GetTextNode() const |
850 | { |
851 | return SwNodeType::Text == m_nNodeType ? static_cast<const SwTextNode*>(this) : nullptr; |
852 | } |
853 | |
854 | inline void |
855 | SwTextNode::CutText(SwTextNode * const pDest, const SwIndex & rDestStart, |
856 | const SwIndex & rStart, const sal_Int32 nLen) |
857 | { |
858 | CutImpl( pDest, rDestStart, rStart, nLen ); |
859 | } |
860 | |
861 | inline sal_Int32 SwTextNode::GetSpaceLeft() const |
862 | { |
863 | // do not fill the String up to the max - need to be able to have a |
864 | // SwPosition "behind" the last character, i.e., at index TXTNODE_MAX + 1 |
865 | const sal_Int32 TXTNODE_MAX = SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF) - 2; |
866 | return TXTNODE_MAX-m_Text.getLength(); |
867 | } |
868 | |
869 | #endif |
870 | |
871 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_SW_INC_NDINDEX_HXX |
20 | #define INCLUDED_SW_INC_NDINDEX_HXX |
21 | |
22 | #include <iostream> |
23 | |
24 | #include <tools/solar.h> |
25 | |
26 | #include "node.hxx" |
27 | #include "ring.hxx" |
28 | #include "ndarr.hxx" |
29 | |
30 | /// Marks a node in the document model. |
31 | class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwNodeIndex final : public sw::Ring<SwNodeIndex> |
32 | { |
33 | SwNode * m_pNode; |
34 | |
35 | // These are not allowed! |
36 | SwNodeIndex( SwNodes& rNds, sal_uInt16 nIdx ) = delete; |
37 | SwNodeIndex( SwNodes& rNds, int nIdx ) = delete; |
38 | void RegisterIndex( SwNodes& rNodes ) |
39 | { |
40 | if(!rNodes.m_vIndices) |
41 | rNodes.m_vIndices = this; |
42 | MoveTo(rNodes.m_vIndices); |
43 | } |
44 | void DeRegisterIndex( SwNodes& rNodes ) |
45 | { |
46 | if(rNodes.m_vIndices == this) |
47 | rNodes.m_vIndices = GetNextInRing(); |
48 | MoveTo(nullptr); |
49 | if(rNodes.m_vIndices == this) |
50 | rNodes.m_vIndices = nullptr; |
51 | } |
52 | |
53 | public: |
54 | SwNodeIndex( SwNodes& rNds, sal_uLong nIdx = 0 ) |
55 | : m_pNode( rNds[ nIdx ] ) |
56 | { |
57 | RegisterIndex( rNds ); |
58 | }; |
59 | SwNodeIndex( const SwNodeIndex& rIdx, long nDiff = 0 ) |
60 | : sw::Ring<SwNodeIndex>() |
61 | { |
62 | if( nDiff ) |
63 | m_pNode = rIdx.GetNodes()[ rIdx.GetIndex() + nDiff ]; |
64 | else |
65 | m_pNode = rIdx.m_pNode; |
66 | RegisterIndex( m_pNode->GetNodes() ); |
67 | } |
68 | |
69 | SwNodeIndex( const SwNode& rNd, long nDiff = 0 ) |
70 | { |
71 | if( nDiff ) |
72 | m_pNode = rNd.GetNodes()[ rNd.GetIndex() + nDiff ]; |
73 | else |
74 | m_pNode = const_cast<SwNode*>(&rNd); |
75 | RegisterIndex( m_pNode->GetNodes() ); |
76 | } |
77 | |
78 | virtual ~SwNodeIndex() override |
79 | { DeRegisterIndex( m_pNode->GetNodes() ); } |
80 | |
81 | inline sal_uLong operator++(); |
82 | inline sal_uLong operator--(); |
83 | inline sal_uLong operator++(int); |
84 | inline sal_uLong operator--(int); |
85 | |
86 | inline sal_uLong operator+=( sal_uLong ); |
87 | inline sal_uLong operator-=( sal_uLong ); |
88 | |
89 | inline bool operator< ( const SwNodeIndex& ) const; |
90 | inline bool operator<=( const SwNodeIndex& ) const; |
91 | inline bool operator> ( const SwNodeIndex& ) const; |
92 | inline bool operator>=( const SwNodeIndex& ) const; |
93 | inline bool operator==( const SwNodeIndex& ) const; |
94 | inline bool operator!=( const SwNodeIndex& ) const; |
95 | |
96 | inline bool operator< ( sal_uLong ) const; |
97 | inline bool operator<=( sal_uLong ) const; |
98 | inline bool operator> ( sal_uLong ) const; |
99 | inline bool operator>=( sal_uLong ) const; |
100 | inline bool operator==( sal_uLong ) const; |
101 | inline bool operator!=( sal_uLong ) const; |
102 | |
103 | inline SwNodeIndex& operator=( sal_uLong ); |
104 | inline SwNodeIndex& operator=( const SwNodeIndex& ); |
105 | inline SwNodeIndex& operator=( const SwNode& ); |
106 | |
107 | // Return value of index as sal_uLong. |
108 | inline sal_uLong GetIndex() const; |
109 | |
110 | // Enables assignments without creation of a temporary object. |
111 | inline SwNodeIndex& Assign( SwNodes const & rNds, sal_uLong ); |
112 | inline SwNodeIndex& Assign( const SwNode& rNd, long nOffset = 0 ); |
113 | |
114 | // Gets pointer on NodesArray. |
115 | inline const SwNodes& GetNodes() const; |
116 | inline SwNodes& GetNodes(); |
117 | |
118 | SwNodeIndex* GetNext() { return GetNextInRing(); } |
119 | SwNode& GetNode() const { return *m_pNode; } |
120 | }; |
121 | |
122 | inline std::ostream &operator <<(std::ostream& s, const SwNodeIndex& index) |
123 | { |
124 | return s << "SwNodeIndex (node " << index.GetIndex() << ")"; |
125 | }; |
126 | |
127 | // SwRange |
128 | |
129 | class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwNodeRange |
130 | { |
131 | public: |
132 | SwNodeIndex aStart; |
133 | SwNodeIndex aEnd; |
134 | |
135 | SwNodeRange( const SwNodeIndex &rS, const SwNodeIndex &rE ) |
136 | : aStart( rS ), aEnd( rE ) {}; |
137 | SwNodeRange( const SwNodeRange &rRange ) |
138 | : aStart( rRange.aStart ), aEnd( rRange.aEnd ) {}; |
139 | |
140 | SwNodeRange( SwNodes& rNds, sal_uLong nSttIdx, sal_uLong nEndIdx = 0 ) |
141 | : aStart( rNds, nSttIdx ), aEnd( rNds, nEndIdx ) {}; |
142 | |
143 | SwNodeRange( const SwNodeIndex& rS, long nSttDiff, const SwNodeIndex& rE, long nEndDiff = 0 ) |
144 | : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) {}; |
145 | SwNodeRange( const SwNode& rS, long nSttDiff, const SwNode& rE, long nEndDiff = 0 ) |
146 | : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) {}; |
147 | }; |
148 | |
149 | // For inlines node.hxx is needed which in turn needs this one. |
150 | // Therefore all inlines accessing m_pNode are implemented here. |
151 | |
152 | inline sal_uLong SwNodeIndex::GetIndex() const |
153 | { |
154 | return m_pNode->GetIndex(); |
155 | } |
156 | inline const SwNodes& SwNodeIndex::GetNodes() const |
157 | { |
158 | return m_pNode->GetNodes(); |
159 | } |
160 | inline SwNodes& SwNodeIndex::GetNodes() |
161 | { |
162 | return m_pNode->GetNodes(); |
163 | } |
164 | inline bool SwNodeIndex::operator< ( sal_uLong const nOther ) const |
165 | { |
166 | return m_pNode->GetIndex() < nOther; |
167 | } |
168 | inline bool SwNodeIndex::operator<=( sal_uLong const nOther ) const |
169 | { |
170 | return m_pNode->GetIndex() <= nOther; |
171 | } |
172 | inline bool SwNodeIndex::operator> ( sal_uLong const nOther ) const |
173 | { |
174 | return m_pNode->GetIndex() > nOther; |
175 | } |
176 | inline bool SwNodeIndex::operator>=( sal_uLong const nOther ) const |
177 | { |
178 | return m_pNode->GetIndex() >= nOther; |
179 | } |
180 | inline bool SwNodeIndex::operator==( sal_uLong const nOther ) const |
181 | { |
182 | return m_pNode->GetIndex() == nOther; |
183 | } |
184 | inline bool SwNodeIndex::operator!=( sal_uLong const nOther ) const |
185 | { |
186 | return m_pNode->GetIndex() != nOther; |
187 | } |
188 | inline bool SwNodeIndex::operator<( const SwNodeIndex& rIndex ) const |
189 | { |
190 | return m_pNode->GetIndex() < rIndex.GetIndex(); |
191 | } |
192 | inline bool SwNodeIndex::operator<=( const SwNodeIndex& rIndex ) const |
193 | { |
194 | return m_pNode->GetIndex() <= rIndex.GetIndex(); |
195 | } |
196 | inline bool SwNodeIndex::operator>( const SwNodeIndex& rIndex ) const |
197 | { |
198 | return m_pNode->GetIndex() > rIndex.GetIndex(); |
199 | } |
200 | inline bool SwNodeIndex::operator>=( const SwNodeIndex& rIndex ) const |
201 | { |
202 | return m_pNode->GetIndex() >= rIndex.GetIndex(); |
203 | } |
204 | inline bool SwNodeIndex::operator==( const SwNodeIndex& rIdx ) const |
205 | { |
206 | return m_pNode == rIdx.m_pNode; |
207 | } |
208 | inline bool SwNodeIndex::operator!=( const SwNodeIndex& rIdx ) const |
209 | { |
210 | return m_pNode != rIdx.m_pNode; |
211 | } |
212 | |
213 | inline sal_uLong SwNodeIndex::operator++() |
214 | { |
215 | m_pNode = GetNodes()[ m_pNode->GetIndex()+1 ]; |
216 | return m_pNode->GetIndex(); |
217 | } |
218 | inline sal_uLong SwNodeIndex::operator--() |
219 | { |
220 | m_pNode = GetNodes()[ m_pNode->GetIndex()-1 ]; |
221 | return m_pNode->GetIndex(); |
222 | } |
223 | inline sal_uLong SwNodeIndex::operator++(int) |
224 | { |
225 | sal_uLong nOldIndex = m_pNode->GetIndex(); |
226 | m_pNode = GetNodes()[ nOldIndex + 1 ]; |
227 | return nOldIndex; |
228 | } |
229 | inline sal_uLong SwNodeIndex::operator--(int) |
230 | { |
231 | sal_uLong nOldIndex = m_pNode->GetIndex(); |
232 | m_pNode = GetNodes()[ nOldIndex - 1 ]; |
233 | return nOldIndex; |
234 | } |
235 | |
236 | inline sal_uLong SwNodeIndex::operator+=( sal_uLong const nOffset ) |
237 | { |
238 | m_pNode = GetNodes()[ m_pNode->GetIndex() + nOffset ]; |
239 | return m_pNode->GetIndex(); |
240 | } |
241 | inline sal_uLong SwNodeIndex::operator-=( sal_uLong const nOffset ) |
242 | { |
243 | m_pNode = GetNodes()[ m_pNode->GetIndex() - nOffset ]; |
244 | return m_pNode->GetIndex(); |
245 | } |
246 | |
247 | inline SwNodeIndex& SwNodeIndex::operator=( sal_uLong const nNew ) |
248 | { |
249 | m_pNode = GetNodes()[ nNew ]; |
250 | return *this; |
251 | } |
252 | |
253 | SwNodeIndex& SwNodeIndex::operator=( const SwNodeIndex& rIdx ) |
254 | { |
255 | *this = *(rIdx.m_pNode); |
256 | return *this; |
257 | } |
258 | |
259 | SwNodeIndex& SwNodeIndex::operator=( const SwNode& rNd ) |
260 | { |
261 | if (&m_pNode->GetNodes() != &rNd.GetNodes()) |
262 | { |
263 | DeRegisterIndex( m_pNode->GetNodes() ); |
264 | m_pNode = const_cast<SwNode*>(&rNd); |
265 | RegisterIndex( m_pNode->GetNodes() ); |
266 | } |
267 | else |
268 | m_pNode = const_cast<SwNode*>(&rNd); |
269 | return *this; |
270 | } |
271 | |
272 | SwNodeIndex& SwNodeIndex::Assign( SwNodes const & rNds, sal_uLong nIdx ) |
273 | { |
274 | *this = *rNds[ nIdx ]; |
275 | return *this; |
276 | } |
277 | |
278 | SwNodeIndex& SwNodeIndex::Assign( const SwNode& rNd, long nOffset ) |
279 | { |
280 | *this = rNd; |
281 | |
282 | if( nOffset ) |
283 | m_pNode = m_pNode->GetNodes()[ m_pNode->GetIndex() + nOffset ]; |
284 | |
285 | return *this; |
286 | } |
287 | |
288 | #endif |
289 | |
290 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_O3TL_TYPED_FLAGS_SET_HXX |
21 | #define INCLUDED_O3TL_TYPED_FLAGS_SET_HXX |
22 | |
23 | #include <sal/config.h> |
24 | |
25 | #include <cassert> |
26 | #include <type_traits> |
27 | |
28 | #include <o3tl/underlyingenumvalue.hxx> |
29 | #include <sal/types.h> |
30 | |
31 | namespace o3tl { |
32 | |
33 | namespace detail { |
34 | |
35 | template<typename T> constexpr |
36 | typename std::enable_if<std::is_signed<T>::value, bool>::type isNonNegative( |
37 | T value) |
38 | { |
39 | return value >= 0; |
40 | } |
41 | |
42 | template<typename T> constexpr |
43 | typename std::enable_if<std::is_unsigned<T>::value, bool>::type isNonNegative(T) |
44 | { |
45 | return true; |
46 | } |
47 | |
48 | } |
49 | |
50 | template<typename T> struct typed_flags {}; |
51 | |
52 | /// Mark a (scoped) enumeration as a set of bit flags, with accompanying |
53 | /// operations. |
54 | /// |
55 | /// template<> |
56 | /// struct o3tl::typed_flags<TheE>: o3tl::is_typed_flags<TheE, TheM> {}; |
57 | /// |
58 | /// All relevant values must be non-negative. (Typically, the enumeration's |
59 | /// underlying type will either be fixed and unsigned, or it will be unfixed--- |
60 | /// and can thus default to a signed type---and all enumerators will have non- |
61 | /// negative values.) |
62 | /// |
63 | /// \param E the enumeration type. |
64 | /// \param M the all-bits-set value for the bit flags. |
65 | template<typename E, typename std::underlying_type<E>::type M> |
66 | struct is_typed_flags { |
67 | static_assert( |
68 | M >= 0, "is_typed_flags expects only non-negative bit values"); |
69 | |
70 | typedef E Self; |
71 | |
72 | class Wrap { |
73 | public: |
74 | typedef is_typed_flags Unwrapped; |
75 | |
76 | explicit constexpr Wrap(typename std::underlying_type<E>::type value): |
77 | value_(value) |
78 | { |
79 | assert(detail::isNonNegative(value))(static_cast <bool> (detail::isNonNegative(value)) ? void (0) : __assert_fail ("detail::isNonNegative(value)", "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 79, __extension__ __PRETTY_FUNCTION__)); |
80 | assert((static_cast <bool> (static_cast<typename std::underlying_type <E>::type>(~0) == M || (value & ~M) == 0) ? void (0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 84, __extension__ __PRETTY_FUNCTION__)) |
81 | static_cast<typename std::underlying_type<E>::type>(~0) == M(static_cast <bool> (static_cast<typename std::underlying_type <E>::type>(~0) == M || (value & ~M) == 0) ? void (0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 84, __extension__ __PRETTY_FUNCTION__)) |
82 | // avoid "operands don't affect result" warnings when M(static_cast <bool> (static_cast<typename std::underlying_type <E>::type>(~0) == M || (value & ~M) == 0) ? void (0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 84, __extension__ __PRETTY_FUNCTION__)) |
83 | // covers all bits of the underlying type(static_cast <bool> (static_cast<typename std::underlying_type <E>::type>(~0) == M || (value & ~M) == 0) ? void (0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 84, __extension__ __PRETTY_FUNCTION__)) |
84 | || (value & ~M) == 0)(static_cast <bool> (static_cast<typename std::underlying_type <E>::type>(~0) == M || (value & ~M) == 0) ? void (0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 84, __extension__ __PRETTY_FUNCTION__)); |
85 | } |
86 | |
87 | constexpr operator E() const { return static_cast<E>(value_); } |
88 | |
89 | explicit constexpr operator typename std::underlying_type<E>::type() |
90 | const |
91 | { return value_; } |
92 | |
93 | explicit constexpr operator bool() const { return value_ != 0; } |
94 | |
95 | private: |
96 | typename std::underlying_type<E>::type value_; |
97 | }; |
98 | |
99 | static typename std::underlying_type<E>::type const mask = M; |
100 | }; |
101 | |
102 | } |
103 | |
104 | template<typename E> |
105 | constexpr typename o3tl::typed_flags<E>::Wrap operator ~(E rhs) { |
106 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 108, __extension__ __PRETTY_FUNCTION__)) |
107 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 108, __extension__ __PRETTY_FUNCTION__)) |
108 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 108, __extension__ __PRETTY_FUNCTION__)); |
109 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
110 | o3tl::typed_flags<E>::mask |
111 | & ~o3tl::underlyingEnumValue(rhs)); |
112 | } |
113 | |
114 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ~( |
115 | typename o3tl::typed_flags<E>::Wrap rhs) |
116 | { |
117 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
118 | o3tl::typed_flags<E>::mask |
119 | & ~o3tl::underlyingEnumValue<E>(rhs)); |
120 | } |
121 | |
122 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( |
123 | E lhs, E rhs) |
124 | { |
125 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 127, __extension__ __PRETTY_FUNCTION__)) |
126 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 127, __extension__ __PRETTY_FUNCTION__)) |
127 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 127, __extension__ __PRETTY_FUNCTION__)); |
128 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 130, __extension__ __PRETTY_FUNCTION__)) |
129 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 130, __extension__ __PRETTY_FUNCTION__)) |
130 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 130, __extension__ __PRETTY_FUNCTION__)); |
131 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
132 | o3tl::underlyingEnumValue(lhs) |
133 | ^ o3tl::underlyingEnumValue(rhs)); |
134 | } |
135 | |
136 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( |
137 | E lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
138 | { |
139 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 141, __extension__ __PRETTY_FUNCTION__)) |
140 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 141, __extension__ __PRETTY_FUNCTION__)) |
141 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 141, __extension__ __PRETTY_FUNCTION__)); |
142 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
143 | o3tl::underlyingEnumValue(lhs) |
144 | ^ o3tl::underlyingEnumValue<E>(rhs)); |
145 | } |
146 | |
147 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^( |
148 | typename o3tl::typed_flags<E>::Wrap lhs, E rhs) |
149 | { |
150 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 152, __extension__ __PRETTY_FUNCTION__)) |
151 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 152, __extension__ __PRETTY_FUNCTION__)) |
152 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 152, __extension__ __PRETTY_FUNCTION__)); |
153 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
154 | o3tl::underlyingEnumValue<E>(lhs) |
155 | ^ o3tl::underlyingEnumValue(rhs)); |
156 | } |
157 | |
158 | template<typename W> constexpr |
159 | typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator ^( |
160 | W lhs, W rhs) |
161 | { |
162 | return static_cast<W>( |
163 | o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs) |
164 | ^ o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs)); |
165 | } |
166 | |
167 | template<typename E> |
168 | constexpr typename o3tl::typed_flags<E>::Wrap operator &(E lhs, E rhs) { |
169 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 171, __extension__ __PRETTY_FUNCTION__)) |
170 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 171, __extension__ __PRETTY_FUNCTION__)) |
171 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 171, __extension__ __PRETTY_FUNCTION__)); |
172 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 174, __extension__ __PRETTY_FUNCTION__)) |
173 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 174, __extension__ __PRETTY_FUNCTION__)) |
174 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 174, __extension__ __PRETTY_FUNCTION__)); |
175 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
176 | o3tl::underlyingEnumValue(lhs) |
177 | & o3tl::underlyingEnumValue(rhs)); |
178 | } |
179 | |
180 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &( |
181 | E lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
182 | { |
183 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 185, __extension__ __PRETTY_FUNCTION__)) |
184 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 185, __extension__ __PRETTY_FUNCTION__)) |
185 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 185, __extension__ __PRETTY_FUNCTION__)); |
186 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
187 | o3tl::underlyingEnumValue(lhs) |
188 | & o3tl::underlyingEnumValue<E>(rhs)); |
189 | } |
190 | |
191 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &( |
192 | typename o3tl::typed_flags<E>::Wrap lhs, E rhs) |
193 | { |
194 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 196, __extension__ __PRETTY_FUNCTION__)) |
195 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 196, __extension__ __PRETTY_FUNCTION__)) |
196 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 196, __extension__ __PRETTY_FUNCTION__)); |
197 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
198 | o3tl::underlyingEnumValue<E>(lhs) |
199 | & o3tl::underlyingEnumValue(rhs)); |
200 | } |
201 | |
202 | template<typename W> constexpr |
203 | typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator &( |
204 | W lhs, W rhs) |
205 | { |
206 | return static_cast<W>( |
207 | o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs) |
208 | & o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs)); |
209 | } |
210 | |
211 | template<typename E> |
212 | constexpr typename o3tl::typed_flags<E>::Wrap operator |(E lhs, E rhs) { |
213 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 215, __extension__ __PRETTY_FUNCTION__)) |
214 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 215, __extension__ __PRETTY_FUNCTION__)) |
215 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 215, __extension__ __PRETTY_FUNCTION__)); |
216 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 218, __extension__ __PRETTY_FUNCTION__)) |
217 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 218, __extension__ __PRETTY_FUNCTION__)) |
218 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 218, __extension__ __PRETTY_FUNCTION__)); |
219 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
220 | o3tl::underlyingEnumValue(lhs) |
221 | | o3tl::underlyingEnumValue(rhs)); |
222 | } |
223 | |
224 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |( |
225 | E lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
226 | { |
227 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 229, __extension__ __PRETTY_FUNCTION__)) |
228 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 229, __extension__ __PRETTY_FUNCTION__)) |
229 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 229, __extension__ __PRETTY_FUNCTION__)); |
230 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
231 | o3tl::underlyingEnumValue(lhs) |
232 | | o3tl::underlyingEnumValue<E>(rhs)); |
233 | } |
234 | |
235 | template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |( |
236 | typename o3tl::typed_flags<E>::Wrap lhs, E rhs) |
237 | { |
238 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 240, __extension__ __PRETTY_FUNCTION__)) |
239 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 240, __extension__ __PRETTY_FUNCTION__)) |
240 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 240, __extension__ __PRETTY_FUNCTION__)); |
241 | return static_cast<typename o3tl::typed_flags<E>::Wrap>( |
242 | o3tl::underlyingEnumValue<E>(lhs) |
243 | | o3tl::underlyingEnumValue(rhs)); |
244 | } |
245 | |
246 | template<typename W> constexpr |
247 | typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator |( |
248 | W lhs, W rhs) |
249 | { |
250 | return static_cast<W>( |
251 | o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs) |
252 | | o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs)); |
253 | } |
254 | |
255 | template<typename E> |
256 | inline typename o3tl::typed_flags<E>::Self operator &=(E & lhs, E rhs) { |
257 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 259, __extension__ __PRETTY_FUNCTION__)) |
258 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 259, __extension__ __PRETTY_FUNCTION__)) |
259 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 259, __extension__ __PRETTY_FUNCTION__)); |
260 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 262, __extension__ __PRETTY_FUNCTION__)) |
261 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 262, __extension__ __PRETTY_FUNCTION__)) |
262 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 262, __extension__ __PRETTY_FUNCTION__)); |
263 | lhs = lhs & rhs; |
264 | return lhs; |
265 | } |
266 | |
267 | template<typename E> |
268 | inline typename o3tl::typed_flags<E>::Self operator &=( |
269 | E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
270 | { |
271 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 273, __extension__ __PRETTY_FUNCTION__)) |
272 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 273, __extension__ __PRETTY_FUNCTION__)) |
273 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 273, __extension__ __PRETTY_FUNCTION__)); |
274 | lhs = lhs & rhs; |
275 | return lhs; |
276 | } |
277 | |
278 | template<typename E> |
279 | inline typename o3tl::typed_flags<E>::Self operator |=(E & lhs, E rhs) { |
280 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 282, __extension__ __PRETTY_FUNCTION__)) |
281 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 282, __extension__ __PRETTY_FUNCTION__)) |
282 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 282, __extension__ __PRETTY_FUNCTION__)); |
283 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 285, __extension__ __PRETTY_FUNCTION__)) |
284 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 285, __extension__ __PRETTY_FUNCTION__)) |
285 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 285, __extension__ __PRETTY_FUNCTION__)); |
286 | lhs = lhs | rhs; |
287 | return lhs; |
288 | } |
289 | |
290 | template<typename E> |
291 | inline typename o3tl::typed_flags<E>::Self operator |=( |
292 | E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
293 | { |
294 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 296, __extension__ __PRETTY_FUNCTION__)) |
295 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 296, __extension__ __PRETTY_FUNCTION__)) |
296 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 296, __extension__ __PRETTY_FUNCTION__)); |
297 | lhs = lhs | rhs; |
298 | return lhs; |
299 | } |
300 | |
301 | template<typename E> |
302 | inline typename o3tl::typed_flags<E>::Self operator ^=(E & lhs, E rhs) { |
303 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 305, __extension__ __PRETTY_FUNCTION__)) |
304 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 305, __extension__ __PRETTY_FUNCTION__)) |
305 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 305, __extension__ __PRETTY_FUNCTION__)); |
306 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 308, __extension__ __PRETTY_FUNCTION__)) |
307 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 308, __extension__ __PRETTY_FUNCTION__)) |
308 | o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 308, __extension__ __PRETTY_FUNCTION__)); |
309 | lhs = lhs ^ rhs; |
310 | return lhs; |
311 | } |
312 | |
313 | template<typename E> |
314 | inline typename o3tl::typed_flags<E>::Self operator ^=( |
315 | E & lhs, typename o3tl::typed_flags<E>::Wrap rhs) |
316 | { |
317 | assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 319, __extension__ __PRETTY_FUNCTION__)) |
318 | o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 319, __extension__ __PRETTY_FUNCTION__)) |
319 | o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl:: underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))" , "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx" , 319, __extension__ __PRETTY_FUNCTION__)); |
320 | lhs = lhs ^ rhs; |
321 | return lhs; |
322 | } |
323 | |
324 | #endif /* INCLUDED_O3TL_TYPED_FLAGS_SET_HXX */ |
325 | |
326 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |