Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <bookmrk.hxx>
21 : #include <boost/function.hpp>
22 : #include <cntfrm.hxx>
23 : #include <doc.hxx>
24 : #include <IDocumentRedlineAccess.hxx>
25 : #include <IDocumentLayoutAccess.hxx>
26 : #include <docary.hxx>
27 : #include <editsh.hxx>
28 : #include <fmtanchr.hxx>
29 : #include <frmfmt.hxx>
30 : #include <functional>
31 : #include <mvsave.hxx>
32 : #include <ndtxt.hxx>
33 : #include <node.hxx>
34 : #include <pam.hxx>
35 : #include <redline.hxx>
36 : #include <rtl/ustrbuf.hxx>
37 : #include <rtl/ustring.hxx>
38 : #include <sal/types.h>
39 : #include <unocrsr.hxx>
40 : #include <edimp.hxx>
41 : #include <memory>
42 :
43 : using namespace ::boost;
44 : using namespace ::sw::mark;
45 :
46 : namespace
47 : {
48 : // #i59534: If a paragraph will be splitted we have to restore some redline positions
49 : // This help function checks a position compared with a node and an content index
50 :
51 : static const int BEFORE_NODE = 0; // Position before the given node index
52 : static const int BEFORE_SAME_NODE = 1; // Same node index but content index before given content index
53 : static const int SAME_POSITION = 2; // Same node index and samecontent index
54 : static const int BEHIND_SAME_NODE = 3; // Same node index but content index behind given content index
55 : static const int BEHIND_NODE = 4; // Position behind the given node index
56 :
57 3110 : static int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, sal_Int32 nContent )
58 : {
59 3110 : sal_uLong nIndex = rPos.nNode.GetIndex();
60 3110 : int nReturn = BEFORE_NODE;
61 3110 : if( nIndex == nNode )
62 : {
63 14 : const sal_Int32 nCntIdx = rPos.nContent.GetIndex();
64 14 : if( nCntIdx < nContent )
65 3 : nReturn = BEFORE_SAME_NODE;
66 11 : else if( nCntIdx == nContent )
67 11 : nReturn = SAME_POSITION;
68 : else
69 0 : nReturn = BEHIND_SAME_NODE;
70 : }
71 3096 : else if( nIndex > nNode )
72 713 : nReturn = BEHIND_NODE;
73 3110 : return nReturn;
74 : }
75 : struct MarkEntry
76 : {
77 : long int m_nIdx;
78 : bool m_bOther;
79 : sal_Int32 m_nContent;
80 : #if 0
81 : void Dump()
82 : {
83 : SAL_INFO("sw.core", "Index: " << m_nIdx << "\tOther: " << m_bOther << "\tContent: " << m_nContent);
84 : }
85 : #endif
86 : };
87 : struct PaMEntry
88 : {
89 : SwPaM* m_pPaM;
90 : bool m_isMark;
91 : sal_Int32 m_nContent;
92 : };
93 : struct OffsetUpdater
94 : {
95 : const SwContentNode* m_pNewContentNode;
96 : const sal_Int32 m_nOffset;
97 38 : OffsetUpdater(SwContentNode* pNewContentNode, sal_Int32 nOffset)
98 38 : : m_pNewContentNode(pNewContentNode), m_nOffset(nOffset) {};
99 3635 : void operator()(SwPosition& rPos, sal_Int32 nContent) const
100 : {
101 3635 : rPos.nNode = *m_pNewContentNode;
102 3635 : rPos.nContent.Assign(const_cast<SwContentNode*>(m_pNewContentNode), nContent + m_nOffset);
103 3635 : };
104 : };
105 : struct LimitUpdater
106 : {
107 : const SwContentNode* m_pNewContentNode;
108 : const sal_uLong m_nLen;
109 : const sal_Int32 m_nCorrLen;
110 0 : LimitUpdater(SwContentNode* pNewContentNode, sal_uLong nLen, sal_Int32 nCorrLen)
111 0 : : m_pNewContentNode(pNewContentNode), m_nLen(nLen), m_nCorrLen(nCorrLen) {};
112 0 : void operator()(SwPosition& rPos, sal_Int32 nContent) const
113 : {
114 0 : rPos.nNode = *m_pNewContentNode;
115 0 : if( nContent < m_nCorrLen )
116 : {
117 0 : rPos.nContent.Assign(const_cast<SwContentNode*>(m_pNewContentNode), std::min( nContent, static_cast<sal_Int32>(m_nLen) ) );
118 : }
119 : else
120 : {
121 0 : rPos.nContent -= m_nCorrLen;
122 : }
123 0 : };
124 : };
125 4656 : struct ContentIdxStoreImpl : sw::mark::ContentIdxStore
126 : {
127 : std::vector<MarkEntry> m_aBkmkEntries;
128 : std::vector<MarkEntry> m_aRedlineEntries;
129 : std::vector<MarkEntry> m_aFlyEntries;
130 : std::vector<PaMEntry> m_aUnoCrsrEntries;
131 : std::vector<PaMEntry> m_aShellCrsrEntries;
132 : typedef boost::function<void (SwPosition& rPos, sal_Int32 nContent)> updater_t;
133 0 : virtual void Clear() SAL_OVERRIDE
134 : {
135 0 : m_aBkmkEntries.clear();
136 0 : m_aRedlineEntries.clear();
137 0 : m_aFlyEntries.clear();
138 0 : m_aUnoCrsrEntries.clear();
139 0 : m_aShellCrsrEntries.clear();
140 0 : }
141 4656 : virtual bool Empty() SAL_OVERRIDE
142 : {
143 4656 : return m_aBkmkEntries.empty() && m_aRedlineEntries.empty() && m_aFlyEntries.empty() && m_aUnoCrsrEntries.empty() && m_aShellCrsrEntries.empty();
144 : }
145 4656 : virtual void Save(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit=false) SAL_OVERRIDE
146 : {
147 4656 : SaveBkmks(pDoc, nNode, nContent);
148 4656 : SaveRedlines(pDoc, nNode, nContent);
149 4656 : SaveFlys(pDoc, nNode, nContent, bSaveFlySplit);
150 4656 : SaveUnoCrsrs(pDoc, nNode, nContent);
151 4656 : SaveShellCrsrs(pDoc, nNode, nContent);
152 4656 : }
153 38 : virtual void Restore(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false) SAL_OVERRIDE
154 : {
155 38 : SwContentNode* pCNd = pDoc->GetNodes()[ nNode ]->GetContentNode();
156 38 : updater_t aUpdater = OffsetUpdater(pCNd, nOffset);
157 38 : RestoreBkmks(pDoc, aUpdater);
158 38 : RestoreRedlines(pDoc, aUpdater);
159 38 : RestoreFlys(pDoc, aUpdater, bAuto);
160 38 : RestoreUnoCrsrs(aUpdater);
161 38 : RestoreShellCrsrs(aUpdater);
162 38 : }
163 0 : virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen) SAL_OVERRIDE
164 : {
165 0 : SwContentNode* pCNd = rNd.GetContentNode();
166 0 : SwDoc* pDoc = rNd.GetDoc();
167 0 : updater_t aUpdater = LimitUpdater(pCNd, nLen, nCorrLen);
168 0 : RestoreBkmks(pDoc, aUpdater);
169 0 : RestoreRedlines(pDoc, aUpdater);
170 0 : RestoreFlys(pDoc, aUpdater, false);
171 0 : RestoreUnoCrsrs(aUpdater);
172 0 : RestoreShellCrsrs(aUpdater);
173 0 : }
174 4656 : virtual ~ContentIdxStoreImpl(){};
175 : private:
176 : inline void SaveBkmks(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent);
177 : inline void RestoreBkmks(SwDoc* pDoc, updater_t& rUpdater);
178 : inline void SaveRedlines(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent);
179 : inline void RestoreRedlines(SwDoc* pDoc, updater_t& rUpdater);
180 : inline void SaveFlys(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit);
181 : inline void RestoreFlys(SwDoc* pDoc, updater_t& rUpdater, bool bAuto);
182 : inline void SaveUnoCrsrs(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent);
183 : inline void RestoreUnoCrsrs(updater_t& rUpdater);
184 : inline void SaveShellCrsrs(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent);
185 : inline void RestoreShellCrsrs(updater_t& rUpdater);
186 2512 : static inline const SwPosition& GetRightMarkPos(::sw::mark::IMark* pMark, bool bOther)
187 2512 : { return bOther ? pMark->GetOtherMarkPos() : pMark->GetMarkPos(); };
188 2512 : static inline void SetRightMarkPos(MarkBase* pMark, bool bOther, const SwPosition* const pPos)
189 2512 : { bOther ? pMark->SetOtherMarkPos(*pPos) : pMark->SetMarkPos(*pPos); };
190 : };
191 138996 : static inline void lcl_ChkPaM( std::vector<PaMEntry>& rPaMEntries, const sal_uLong nNode, const sal_Int32 nContent, SwPaM& rPaM, const bool bPoint)
192 : {
193 138996 : const SwPosition* pPos = &rPaM.GetBound( bPoint );
194 138996 : if( pPos->nNode.GetIndex() == nNode && pPos->nContent.GetIndex() < nContent )
195 : {
196 1117 : const PaMEntry aEntry = { &rPaM, bPoint, pPos->nContent.GetIndex() };
197 1117 : rPaMEntries.push_back(aEntry);
198 : }
199 138996 : }
200 69498 : static inline void lcl_ChkPaMBoth( std::vector<PaMEntry>& rPaMEntries, const sal_uLong nNode, const sal_Int32 nContent, SwPaM& rPaM)
201 : {
202 69498 : lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, true);
203 69498 : lcl_ChkPaM(rPaMEntries, nNode, nContent, rPaM, false);
204 69498 : }
205 :
206 : #if 0
207 : static void DumpEntries(std::vector<MarkEntry>* pEntries)
208 : {
209 : for (MarkEntry& aEntry : *pEntries)
210 : aEntry.Dump();
211 : }
212 : #endif
213 : }
214 :
215 4656 : void ContentIdxStoreImpl::SaveBkmks(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent)
216 : {
217 4656 : IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
218 4656 : const IDocumentMarkAccess::const_iterator_t ppBkmkEnd = pMarkAccess->getAllMarksEnd();
219 129057 : for(
220 4656 : IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getAllMarksBegin();
221 : ppBkmk != ppBkmkEnd;
222 : ++ppBkmk)
223 : {
224 124401 : const ::sw::mark::IMark* pBkmk = ppBkmk->get();
225 124401 : bool bMarkPosEqual = false;
226 248802 : if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode
227 124401 : && pBkmk->GetMarkPos().nContent.GetIndex() <= nContent)
228 : {
229 1283 : if(pBkmk->GetMarkPos().nContent.GetIndex() < nContent)
230 : {
231 1261 : const MarkEntry aEntry = { ppBkmk - pMarkAccess->getAllMarksBegin(), false, pBkmk->GetMarkPos().nContent.GetIndex() };
232 1261 : m_aBkmkEntries.push_back(aEntry);
233 : }
234 : else // if a bookmark position is equal nContent, the other position
235 22 : bMarkPosEqual = true; // has to decide if it is added to the array
236 : }
237 248802 : if(pBkmk->IsExpanded()
238 109845 : && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode
239 138532 : && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nContent)
240 : {
241 1251 : if(bMarkPosEqual)
242 : { // the other position is before, the (main) position is equal
243 0 : const MarkEntry aEntry = { ppBkmk - pMarkAccess->getAllMarksBegin(), false, pBkmk->GetMarkPos().nContent.GetIndex() };
244 0 : m_aBkmkEntries.push_back(aEntry);
245 : }
246 1251 : const MarkEntry aEntry = { ppBkmk - pMarkAccess->getAllMarksBegin(), true, pBkmk->GetOtherMarkPos().nContent.GetIndex() };
247 1251 : m_aBkmkEntries.push_back(aEntry);
248 : }
249 : }
250 4656 : }
251 :
252 38 : void ContentIdxStoreImpl::RestoreBkmks(SwDoc* pDoc, updater_t& rUpdater)
253 : {
254 38 : IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
255 2550 : for (const MarkEntry& aEntry : m_aBkmkEntries)
256 : {
257 2512 : if (MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aEntry.m_nIdx].get()))
258 : {
259 2512 : SwPosition aNewPos(GetRightMarkPos(pMark, aEntry.m_bOther));
260 2512 : rUpdater(aNewPos, aEntry.m_nContent);
261 2512 : SetRightMarkPos(pMark, aEntry.m_bOther, &aNewPos);
262 : }
263 : }
264 38 : }
265 :
266 4656 : void ContentIdxStoreImpl::SaveRedlines(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent)
267 : {
268 4656 : SwRedlineTable const & pRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
269 4656 : long int nIdx = 0;
270 6223 : for (const SwRangeRedline* pRdl : pRedlineTable)
271 : {
272 1567 : int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nContent );
273 3110 : int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nContent ) :
274 3110 : nPointPos;
275 : // #i59534: We have to store the positions inside the same node before the insert position
276 : // and the one at the insert position if the corresponding Point/Mark position is before
277 : // the insert position.
278 1567 : if( nPointPos == BEFORE_SAME_NODE ||
279 10 : ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) )
280 : {
281 3 : const MarkEntry aEntry = { nIdx, false, pRdl->GetPoint()->nContent.GetIndex() };
282 3 : m_aRedlineEntries.push_back(aEntry);
283 : }
284 1570 : if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE ||
285 1 : ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) )
286 : {
287 3 : const MarkEntry aEntry = { nIdx, true, pRdl->GetMark()->nContent.GetIndex() };
288 3 : m_aRedlineEntries.push_back(aEntry);
289 : }
290 1567 : ++nIdx;
291 : }
292 4656 : }
293 :
294 38 : void ContentIdxStoreImpl::RestoreRedlines(SwDoc* pDoc, updater_t& rUpdater)
295 : {
296 38 : const SwRedlineTable& rRedlTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
297 44 : for (const MarkEntry& aEntry : m_aRedlineEntries)
298 : {
299 : SwPosition* const pPos = aEntry.m_bOther
300 3 : ? rRedlTable[ aEntry.m_nIdx ]->GetMark()
301 9 : : rRedlTable[ aEntry.m_nIdx ]->GetPoint();
302 6 : rUpdater(*pPos, aEntry.m_nContent);
303 : }
304 38 : }
305 :
306 4656 : void ContentIdxStoreImpl::SaveFlys(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit)
307 : {
308 4656 : SwContentNode *pNode = pDoc->GetNodes()[nNode]->GetContentNode();
309 4656 : if( !pNode )
310 506 : return;
311 4656 : SwFrm* pFrm = pNode->getLayoutFrm( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() );
312 4656 : if( pFrm )
313 : {
314 509 : if( !pFrm->GetDrawObjs() )
315 506 : return; // if we have a layout and no DrawObjs, we can skip this
316 : }
317 4150 : MarkEntry aSave = { 0, false, 0 };
318 21231 : for (const SwFrameFormat* pFrameFormat : *pDoc->GetSpzFrameFormats())
319 : {
320 17081 : if ( RES_FLYFRMFMT == pFrameFormat->Which() || RES_DRAWFRMFMT == pFrameFormat->Which() )
321 : {
322 17081 : const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
323 17081 : SwPosition const*const pAPos = rAnchor.GetContentAnchor();
324 17084 : if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) &&
325 6 : ( FLY_AT_PARA == rAnchor.GetAnchorId() ||
326 3 : FLY_AT_CHAR == rAnchor.GetAnchorId() ) )
327 : {
328 0 : bool bSkip = false;
329 0 : aSave.m_bOther = false;
330 0 : aSave.m_nContent = pAPos->nContent.GetIndex();
331 0 : if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
332 : {
333 0 : if( nContent <= aSave.m_nContent )
334 : {
335 0 : if( bSaveFlySplit )
336 0 : aSave.m_bOther = true;
337 : else
338 0 : bSkip = true;
339 : }
340 : }
341 0 : if(!bSkip)
342 0 : m_aFlyEntries.push_back(aSave);
343 : }
344 : }
345 17081 : ++aSave.m_nIdx;
346 : }
347 : }
348 :
349 38 : void ContentIdxStoreImpl::RestoreFlys(SwDoc* pDoc, updater_t& rUpdater, bool bAuto)
350 : {
351 38 : SwFrameFormats* pSpz = pDoc->GetSpzFrameFormats();
352 38 : for (const MarkEntry& aEntry : m_aFlyEntries)
353 : {
354 0 : if(!aEntry.m_bOther)
355 : {
356 0 : SwFrameFormat *pFrameFormat = (*pSpz)[ aEntry.m_nIdx ];
357 0 : const SwFormatAnchor& rFlyAnchor = pFrameFormat->GetAnchor();
358 0 : if( rFlyAnchor.GetContentAnchor() )
359 : {
360 0 : SwFormatAnchor aNew( rFlyAnchor );
361 0 : SwPosition aNewPos( *rFlyAnchor.GetContentAnchor() );
362 0 : rUpdater(aNewPos, aEntry.m_nContent);
363 0 : if ( FLY_AT_CHAR != rFlyAnchor.GetAnchorId() )
364 : {
365 0 : aNewPos.nContent.Assign( 0, 0 );
366 : }
367 0 : aNew.SetAnchor( &aNewPos );
368 0 : pFrameFormat->SetFormatAttr( aNew );
369 : }
370 : }
371 0 : else if( bAuto )
372 : {
373 0 : SwFrameFormat *pFrameFormat = (*pSpz)[ aEntry.m_nIdx ];
374 0 : SfxPoolItem const *pAnchor = static_cast<SfxPoolItem const *>(&pFrameFormat->GetAnchor());
375 0 : pFrameFormat->NotifyClients( pAnchor, pAnchor );
376 : }
377 : }
378 38 : }
379 :
380 4656 : void ContentIdxStoreImpl::SaveUnoCrsrs(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent)
381 : {
382 737744 : for (auto pWeakUnoCrsr : pDoc->mvUnoCrsrTbl)
383 : {
384 802077 : auto pUnoCrsr(pWeakUnoCrsr.lock());
385 733088 : if(!pUnoCrsr)
386 664099 : continue;
387 137978 : for(SwPaM& rPaM : pUnoCrsr.get()->GetRingContainer())
388 : {
389 68989 : lcl_ChkPaMBoth( m_aUnoCrsrEntries, nNode, nContent, rPaM);
390 : }
391 68989 : const SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<const SwUnoTableCrsr*>(pUnoCrsr.get());
392 68989 : if( pUnoTblCrsr )
393 : {
394 0 : for(SwPaM& rPaM : (&(const_cast<SwUnoTableCrsr*>(pUnoTblCrsr))->GetSelRing())->GetRingContainer())
395 : {
396 0 : lcl_ChkPaMBoth( m_aUnoCrsrEntries, nNode, nContent, rPaM);
397 : }
398 : }
399 68989 : }
400 4656 : }
401 :
402 38 : void ContentIdxStoreImpl::RestoreUnoCrsrs(updater_t& rUpdater)
403 : {
404 1154 : for (const PaMEntry& aEntry : m_aUnoCrsrEntries)
405 : {
406 1116 : rUpdater(aEntry.m_pPaM->GetBound(!aEntry.m_isMark), aEntry.m_nContent);
407 : }
408 38 : }
409 :
410 4656 : void ContentIdxStoreImpl::SaveShellCrsrs(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent)
411 : {
412 4656 : SwCrsrShell* pShell = pDoc->GetEditShell();
413 4656 : if( !pShell )
414 8803 : return;
415 1018 : for(SwViewShell& rCurShell : pShell->GetRingContainer())
416 : {
417 509 : if( rCurShell.IsA( TYPE( SwCrsrShell )) )
418 : {
419 509 : SwPaM *_pStkCrsr = static_cast<SwCrsrShell*>(&rCurShell)->GetStkCrsr();
420 509 : if( _pStkCrsr )
421 0 : do {
422 0 : lcl_ChkPaMBoth( m_aShellCrsrEntries, nNode, nContent, *_pStkCrsr);
423 0 : } while ( (_pStkCrsr != 0 ) &&
424 0 : ((_pStkCrsr = _pStkCrsr->GetNext()) != static_cast<SwCrsrShell*>(&rCurShell)->GetStkCrsr()) );
425 :
426 1018 : for(SwPaM& rPaM : (static_cast<SwCrsrShell*>(&rCurShell)->_GetCrsr())->GetRingContainer())
427 : {
428 509 : lcl_ChkPaMBoth( m_aShellCrsrEntries, nNode, nContent, rPaM);
429 : }
430 : }
431 : }
432 : }
433 :
434 38 : void ContentIdxStoreImpl::RestoreShellCrsrs(updater_t& rUpdater)
435 : {
436 39 : for (const PaMEntry& aEntry : m_aShellCrsrEntries)
437 : {
438 1 : rUpdater(aEntry.m_pPaM->GetBound(aEntry.m_isMark), aEntry.m_nContent);
439 : }
440 38 : }
441 :
442 : namespace sw { namespace mark {
443 4656 : std::shared_ptr<ContentIdxStore> ContentIdxStore::Create()
444 : {
445 4656 : return std::make_shared<ContentIdxStoreImpl>();
446 : }
447 177 : }}
448 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|