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 <MarkManager.hxx>
21 : #include <bookmrk.hxx>
22 : #include <boost/bind.hpp>
23 : #include <boost/foreach.hpp>
24 : #include <boost/function.hpp>
25 : #include <cntfrm.hxx>
26 : #include <crossrefbookmark.hxx>
27 : #include <annotationmark.hxx>
28 : #include <dcontact.hxx>
29 : #include <doc.hxx>
30 : #include <IDocumentRedlineAccess.hxx>
31 : #include <docary.hxx>
32 : #include <xmloff/odffields.hxx>
33 : #include <editsh.hxx>
34 : #include <fmtanchr.hxx>
35 : #include <frmfmt.hxx>
36 : #include <functional>
37 : #include <hintids.hxx>
38 : #include <mvsave.hxx>
39 : #include <ndtxt.hxx>
40 : #include <node.hxx>
41 : #include <pam.hxx>
42 : #include <redline.hxx>
43 : #include <rolbck.hxx>
44 : #include <rtl/ustrbuf.hxx>
45 : #include <rtl/ustring.hxx>
46 : #include <sal/types.h>
47 : #include <sortedobjs.hxx>
48 : #include <sfx2/linkmgr.hxx>
49 : #include <swserv.hxx>
50 : #include <swundo.hxx>
51 : #include <unocrsr.hxx>
52 : #include <viscrs.hxx>
53 : #include <edimp.hxx>
54 : #include <stdio.h>
55 :
56 : using namespace ::boost;
57 : using namespace ::sw::mark;
58 :
59 : namespace
60 : {
61 191212 : static bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
62 : {
63 : return pIdx != NULL
64 68496 : ? ( rPos.nNode > rNdIdx
65 76110 : || ( rPos.nNode == rNdIdx
66 2998 : && rPos.nContent >= pIdx->GetIndex() ) )
67 259708 : : rPos.nNode >= rNdIdx;
68 : }
69 :
70 135986 : static bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
71 : {
72 135986 : return rPos.nNode < rNdIdx
73 138390 : || ( pIdx != NULL
74 7184 : && rPos.nNode == rNdIdx
75 136874 : && rPos.nContent < pIdx->GetIndex() );
76 : }
77 :
78 709606 : static bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst,
79 : const IDocumentMarkAccess::pMark_t& rpSecond)
80 : {
81 709606 : return rpFirst->GetMarkStart() < rpSecond->GetMarkStart();
82 : }
83 :
84 0 : static bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst,
85 : const IDocumentMarkAccess::pMark_t& rpSecond)
86 : {
87 0 : return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd();
88 : }
89 :
90 205580 : static void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks,
91 : const IDocumentMarkAccess::pMark_t& pMark)
92 : {
93 : io_vMarks.insert(
94 : lower_bound(
95 : io_vMarks.begin(),
96 : io_vMarks.end(),
97 : pMark,
98 205580 : &lcl_MarkOrderingByStart),
99 205580 : pMark);
100 205580 : }
101 :
102 0 : static inline ::std::unique_ptr<SwPosition> lcl_PositionFromCntntNode(
103 : SwCntntNode * const pCntntNode,
104 : const bool bAtEnd=false)
105 : {
106 0 : ::std::unique_ptr<SwPosition> pResult(new SwPosition(*pCntntNode));
107 0 : pResult->nContent.Assign(pCntntNode, bAtEnd ? pCntntNode->Len() : 0);
108 0 : return pResult;
109 : }
110 :
111 : // return a position at the begin of rEnd, if it is a CntntNode
112 : // else set it to the begin of the Node after rEnd, if there is one
113 : // else set it to the end of the node before rStt
114 : // else set it to the CntntNode of the Pos outside the Range
115 0 : static inline ::std::unique_ptr<SwPosition> lcl_FindExpelPosition(
116 : const SwNodeIndex& rStt,
117 : const SwNodeIndex& rEnd,
118 : const SwPosition& rOtherPosition)
119 : {
120 0 : SwCntntNode * pNode = rEnd.GetNode().GetCntntNode();
121 0 : bool bPosAtEndOfNode = false;
122 0 : if ( pNode == NULL)
123 : {
124 0 : SwNodeIndex aEnd = SwNodeIndex(rEnd);
125 0 : pNode = rEnd.GetNodes().GoNext( &aEnd );
126 0 : bPosAtEndOfNode = false;
127 : }
128 0 : if ( pNode == NULL )
129 : {
130 0 : SwNodeIndex aStt = SwNodeIndex(rStt);
131 0 : pNode = rStt.GetNodes().GoPrevious(&aStt);
132 0 : bPosAtEndOfNode = true;
133 : }
134 0 : if ( pNode != NULL )
135 : {
136 0 : return lcl_PositionFromCntntNode( pNode, bPosAtEndOfNode );
137 : }
138 :
139 0 : return ::std::unique_ptr<SwPosition>(new SwPosition(rOtherPosition));
140 : }
141 :
142 2 : static IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
143 : {
144 : IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound(
145 : rMarks.begin(),
146 : rMarks.end(),
147 : rPos,
148 2 : sw::mark::CompareIMarkStartsAfter());
149 2 : if(pMarkAfter == rMarks.end()) return NULL;
150 2 : return pMarkAfter->get();
151 : };
152 :
153 0 : static IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
154 : {
155 : // candidates from which to choose the mark before
156 0 : IDocumentMarkAccess::container_t vCandidates;
157 : // no need to consider marks starting after rPos
158 : IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound(
159 : rMarks.begin(),
160 : rMarks.end(),
161 : rPos,
162 0 : sw::mark::CompareIMarkStartsAfter());
163 0 : vCandidates.reserve(pCandidatesEnd - rMarks.begin());
164 : // only marks ending before are candidates
165 : remove_copy_if(
166 : rMarks.begin(),
167 : pCandidatesEnd,
168 : back_inserter(vCandidates),
169 0 : boost::bind( ::std::logical_not<bool>(), boost::bind( &IMark::EndsBefore, _1, rPos ) ) );
170 : // no candidate left => we are in front of the first mark or there are none
171 0 : if(!vCandidates.size()) return NULL;
172 : // return the highest (last) candidate using mark end ordering
173 0 : return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get();
174 : }
175 :
176 72512 : static bool lcl_FixCorrectedMark(
177 : const bool bChangedPos,
178 : const bool bChangedOPos,
179 : MarkBase* io_pMark )
180 : {
181 72512 : if ( IDocumentMarkAccess::GetType(*io_pMark) == IDocumentMarkAccess::ANNOTATIONMARK )
182 : {
183 : // annotation marks are allowed to span a table cell range.
184 : // but trigger sorting to be save
185 42 : return true;
186 : }
187 :
188 143068 : if ( ( bChangedPos || bChangedOPos )
189 2418 : && io_pMark->IsExpanded()
190 76942 : && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() !=
191 2236 : io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() )
192 : {
193 0 : if ( !bChangedOPos )
194 : {
195 0 : io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() );
196 : }
197 0 : io_pMark->ClearOtherMarkPos();
198 0 : DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark);
199 0 : if ( pDdeBkmk != NULL
200 0 : && pDdeBkmk->IsServer() )
201 : {
202 0 : pDdeBkmk->SetRefObject(NULL);
203 : }
204 0 : return true;
205 : }
206 72470 : return false;
207 : }
208 :
209 842 : static IDocumentMarkAccess::iterator_t lcl_FindMark(
210 : IDocumentMarkAccess::container_t& rMarks,
211 : const IDocumentMarkAccess::pMark_t& rpMarkToFind)
212 : {
213 : IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
214 : rMarks.begin(), rMarks.end(),
215 842 : rpMarkToFind, &lcl_MarkOrderingByStart);
216 : // since there are usually not too many marks on the same start
217 : // position, we are not doing a bisect search for the upper bound
218 : // but instead start to iterate from pMarkLow directly
219 1794 : while(ppCurrentMark != rMarks.end() && **ppCurrentMark == *rpMarkToFind)
220 : {
221 952 : if(ppCurrentMark->get() == rpMarkToFind.get())
222 : {
223 : //OSL_TRACE("found mark named '%s'",
224 : // OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr());
225 842 : return ppCurrentMark;
226 : }
227 110 : ++ppCurrentMark;
228 : }
229 : // reached a mark starting on a later start pos or the end of the
230 : // vector => not found
231 0 : return rMarks.end();
232 : };
233 :
234 6 : static IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos(
235 : IDocumentMarkAccess::container_t& rMarks,
236 : const SwPosition& rPos,
237 : const IDocumentMarkAccess::MarkType eType)
238 : {
239 18 : for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
240 : rMarks.begin(), rMarks.end(),
241 : rPos,
242 6 : sw::mark::CompareIMarkStartsBefore());
243 12 : ppCurrentMark != rMarks.end();
244 : ++ppCurrentMark)
245 : {
246 : // Once we reach a mark starting after the target pos
247 : // we do not need to continue
248 2 : if(ppCurrentMark->get()->StartsAfter(rPos))
249 0 : break;
250 2 : if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType)
251 : {
252 : //OSL_TRACE("found mark named '%s'",
253 : // OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr());
254 2 : return ppCurrentMark;
255 : }
256 : }
257 : // reached a mark starting on a later start pos or the end of the
258 : // vector => not found
259 4 : return rMarks.end();
260 : };
261 :
262 21692 : static IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName(
263 : const OUString& rName,
264 : IDocumentMarkAccess::const_iterator_t ppMarksBegin,
265 : IDocumentMarkAccess::const_iterator_t ppMarksEnd)
266 : {
267 : return find_if(
268 : ppMarksBegin,
269 : ppMarksEnd,
270 21692 : boost::bind(&OUString::equals, boost::bind(&IMark::GetName, _1), rName));
271 : }
272 :
273 : #if 0
274 : static void lcl_DebugMarks(IDocumentMarkAccess::container_t vMarks)
275 : {
276 : OSL_TRACE("%d Marks", vMarks.size());
277 : for(IDocumentMarkAccess::iterator_t ppMark = vMarks.begin();
278 : ppMark != vMarks.end();
279 : ppMark++)
280 : {
281 : IMark* pMark = ppMark->get();
282 : OString sName = OUStringToOString(pMark->GetName(), RTL_TEXTENCODING_UTF8);
283 : const SwPosition* const pStPos = &pMark->GetMarkStart();
284 : const SwPosition* const pEndPos = &pMark->GetMarkEnd();
285 : OSL_TRACE("%s %s %d,%d %d,%d",
286 : typeid(*pMark).name(),
287 : sName.getStr(),
288 : pStPos->nNode.GetIndex(),
289 : pStPos->nContent.GetIndex(),
290 : pEndPos->nNode.GetIndex(),
291 : pEndPos->nContent.GetIndex());
292 : }
293 : };
294 : #endif
295 : }
296 :
297 5051572 : IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk)
298 : {
299 5051572 : const std::type_info* const pMarkTypeInfo = &typeid(rBkmk);
300 : // not using dynamic_cast<> here for performance
301 5051572 : if(*pMarkTypeInfo == typeid(UnoMark))
302 2339100 : return UNO_BOOKMARK;
303 2712472 : else if(*pMarkTypeInfo == typeid(DdeBookmark))
304 2 : return DDE_BOOKMARK;
305 2712470 : else if(*pMarkTypeInfo == typeid(Bookmark))
306 2701972 : return BOOKMARK;
307 10498 : else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark))
308 14 : return CROSSREF_HEADING_BOOKMARK;
309 10484 : else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark))
310 34 : return CROSSREF_NUMITEM_BOOKMARK;
311 10450 : else if(*pMarkTypeInfo == typeid(AnnotationMark))
312 438 : return ANNOTATIONMARK;
313 10012 : else if(*pMarkTypeInfo == typeid(TextFieldmark))
314 9828 : return TEXT_FIELDMARK;
315 184 : else if(*pMarkTypeInfo == typeid(CheckboxFieldmark))
316 184 : return CHECKBOX_FIELDMARK;
317 0 : else if(*pMarkTypeInfo == typeid(NavigatorReminder))
318 0 : return NAVIGATOR_REMINDER;
319 : else
320 : {
321 : OSL_FAIL("IDocumentMarkAccess::GetType(..)"
322 : " - unknown MarkType. This needs to be fixed!");
323 0 : return UNO_BOOKMARK;
324 : }
325 : }
326 :
327 8162 : OUString IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix()
328 : {
329 8162 : return OUString("__RefHeading__");
330 : }
331 :
332 0 : bool IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( const SwPaM& rPaM )
333 : {
334 0 : return rPaM.Start()->nNode.GetNode().IsTxtNode() &&
335 0 : rPaM.Start()->nContent.GetIndex() == 0 &&
336 0 : ( !rPaM.HasMark() ||
337 0 : ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode &&
338 0 : rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTxtNode()->Len() ) );
339 : }
340 :
341 : namespace sw { namespace mark
342 : {
343 5052 : MarkManager::MarkManager(SwDoc& rDoc)
344 : : m_vAllMarks()
345 : , m_vBookmarks()
346 : , m_vFieldmarks()
347 : , m_vAnnotationMarks()
348 5052 : , m_pDoc(&rDoc)
349 5052 : { }
350 :
351 196998 : ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM,
352 : const OUString& rName,
353 : const IDocumentMarkAccess::MarkType eType)
354 : {
355 : #if 0
356 : {
357 : OString sName = OUStringToOString(rName, RTL_TEXTENCODING_UTF8);
358 : const SwPosition* const pPos1 = rPaM.GetPoint();
359 : const SwPosition* pPos2 = pPos1;
360 : if(rPaM.HasMark())
361 : pPos2 = rPaM.GetMark();
362 : OSL_TRACE("%s %d,%d %d,%d",
363 : sName.getStr(),
364 : pPos1->nNode.GetIndex(),
365 : pPos1->nContent.GetIndex(),
366 : pPos2->nNode.GetIndex(),
367 : pPos2->nContent.GetIndex());
368 : }
369 : #endif
370 : // see for example _SaveCntntIdx, Shells
371 : OSL_PRECOND(m_vAllMarks.size() < USHRT_MAX,
372 : "MarkManager::makeMark(..)"
373 : " - more than USHRT_MAX marks are not supported correctly");
374 : // There should only be one CrossRefBookmark per Textnode per Type
375 : OSL_PRECOND(
376 : (eType != CROSSREF_NUMITEM_BOOKMARK && eType != CROSSREF_HEADING_BOOKMARK)
377 : || (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.GetPoint(), eType) == m_vBookmarks.end()),
378 : "MarkManager::makeMark(..)"
379 : " - creating duplicate CrossRefBookmark");
380 :
381 : // create mark
382 196998 : pMark_t pMark;
383 196998 : switch(eType)
384 : {
385 : case IDocumentMarkAccess::TEXT_FIELDMARK:
386 192 : pMark = boost::shared_ptr<IMark>(new TextFieldmark(rPaM));
387 192 : break;
388 : case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
389 26 : pMark = boost::shared_ptr<IMark>(new CheckboxFieldmark(rPaM));
390 26 : break;
391 : case IDocumentMarkAccess::NAVIGATOR_REMINDER:
392 0 : pMark = boost::shared_ptr<IMark>(new NavigatorReminder(rPaM));
393 0 : break;
394 : case IDocumentMarkAccess::BOOKMARK:
395 8256 : pMark = boost::shared_ptr<IMark>(new Bookmark(rPaM, vcl::KeyCode(), rName, OUString()));
396 8256 : break;
397 : case IDocumentMarkAccess::DDE_BOOKMARK:
398 2 : pMark = boost::shared_ptr<IMark>(new DdeBookmark(rPaM));
399 2 : break;
400 : case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
401 4 : pMark = boost::shared_ptr<IMark>(new CrossRefHeadingBookmark(rPaM, vcl::KeyCode(), rName, OUString()));
402 4 : break;
403 : case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
404 18 : pMark = boost::shared_ptr<IMark>(new CrossRefNumItemBookmark(rPaM, vcl::KeyCode(), rName, OUString()));
405 18 : break;
406 : case IDocumentMarkAccess::UNO_BOOKMARK:
407 188414 : pMark = boost::shared_ptr<IMark>(new UnoMark(rPaM));
408 188414 : break;
409 : case IDocumentMarkAccess::ANNOTATIONMARK:
410 86 : pMark = boost::shared_ptr<IMark>(new AnnotationMark( rPaM, rName ));
411 86 : break;
412 : }
413 : OSL_ENSURE(pMark.get(),
414 : "MarkManager::makeMark(..)"
415 : " - Mark was not created.");
416 196998 : MarkBase* pMarkBase = dynamic_cast<MarkBase*>(pMark.get());
417 :
418 196998 : if (!pMarkBase)
419 0 : return 0;
420 :
421 196998 : if(pMark->GetMarkPos() != pMark->GetMarkStart())
422 3774 : pMarkBase->Swap();
423 :
424 : // for performance reasons, we trust UnoMarks to have a (generated) unique name
425 196998 : if ( eType != IDocumentMarkAccess::UNO_BOOKMARK )
426 8584 : pMarkBase->SetName( getUniqueMarkName( pMarkBase->GetName() ) );
427 :
428 : // register mark
429 196998 : m_aMarkNamesSet.insert(pMarkBase->GetName());
430 196998 : lcl_InsertMarkSorted(m_vAllMarks, pMark);
431 196998 : switch(eType)
432 : {
433 : case IDocumentMarkAccess::BOOKMARK:
434 : case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
435 : case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
436 8278 : lcl_InsertMarkSorted(m_vBookmarks, pMark);
437 8278 : break;
438 : case IDocumentMarkAccess::TEXT_FIELDMARK:
439 : case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
440 218 : lcl_InsertMarkSorted(m_vFieldmarks, pMark);
441 218 : break;
442 : case IDocumentMarkAccess::ANNOTATIONMARK:
443 86 : lcl_InsertMarkSorted( m_vAnnotationMarks, pMark );
444 86 : break;
445 : case IDocumentMarkAccess::NAVIGATOR_REMINDER:
446 : case IDocumentMarkAccess::DDE_BOOKMARK:
447 : case IDocumentMarkAccess::UNO_BOOKMARK:
448 : // no special array for these
449 188416 : break;
450 : }
451 196998 : pMarkBase->InitDoc(m_pDoc);
452 : #if 0
453 : OSL_TRACE("--- makeType ---");
454 : OSL_TRACE("Marks");
455 : lcl_DebugMarks(m_vAllMarks);
456 : OSL_TRACE("Bookmarks");
457 : lcl_DebugMarks(m_vBookmarks);
458 : OSL_TRACE("Fieldmarks");
459 : lcl_DebugMarks(m_vFieldmarks);
460 : #endif
461 :
462 196998 : return pMark.get();
463 : }
464 :
465 2 : ::sw::mark::IFieldmark* MarkManager::makeFieldBookmark(
466 : const SwPaM& rPaM,
467 : const OUString& rName,
468 : const OUString& rType )
469 : {
470 : sw::mark::IMark* pMark = makeMark( rPaM, rName,
471 2 : IDocumentMarkAccess::TEXT_FIELDMARK );
472 2 : sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
473 2 : if (pFieldMark)
474 2 : pFieldMark->SetFieldname( rType );
475 :
476 2 : return pFieldMark;
477 : }
478 :
479 8 : ::sw::mark::IFieldmark* MarkManager::makeNoTextFieldBookmark(
480 : const SwPaM& rPaM,
481 : const OUString& rName,
482 : const OUString& rType)
483 : {
484 : sw::mark::IMark* pMark = makeMark( rPaM, rName,
485 8 : IDocumentMarkAccess::CHECKBOX_FIELDMARK );
486 8 : sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
487 8 : if (pFieldMark)
488 8 : pFieldMark->SetFieldname( rType );
489 :
490 8 : return pFieldMark;
491 : }
492 :
493 6 : ::sw::mark::IMark* MarkManager::getMarkForTxtNode(
494 : const SwTxtNode& rTxtNode,
495 : const IDocumentMarkAccess::MarkType eType )
496 : {
497 6 : SwPosition aPos(rTxtNode);
498 6 : aPos.nContent.Assign(&(const_cast<SwTxtNode&>(rTxtNode)), 0);
499 6 : const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType);
500 6 : if(ppExistingMark != m_vBookmarks.end())
501 2 : return ppExistingMark->get();
502 8 : const SwPaM aPaM(aPos);
503 10 : return makeMark(aPaM, OUString(), eType);
504 : }
505 :
506 86 : sw::mark::IMark* MarkManager::makeAnnotationMark(
507 : const SwPaM& rPaM,
508 : const ::rtl::OUString& rName )
509 : {
510 86 : return makeMark( rPaM, rName, IDocumentMarkAccess::ANNOTATIONMARK );
511 : }
512 :
513 0 : void MarkManager::repositionMark(
514 : ::sw::mark::IMark* const io_pMark,
515 : const SwPaM& rPaM)
516 : {
517 : OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc,
518 : "<MarkManager::repositionMark(..)>"
519 : " - Mark is not in my doc.");
520 0 : MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark);
521 0 : if (!pMarkBase)
522 0 : return;
523 :
524 0 : pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
525 0 : if(rPaM.HasMark())
526 0 : pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
527 : else
528 0 : pMarkBase->ClearOtherMarkPos();
529 :
530 0 : if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
531 0 : pMarkBase->Swap();
532 :
533 0 : sortMarks();
534 : }
535 :
536 764 : bool MarkManager::renameMark(
537 : ::sw::mark::IMark* io_pMark,
538 : const OUString& rNewName )
539 : {
540 : OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc,
541 : "<MarkManager::renameMark(..)>"
542 : " - Mark is not in my doc.");
543 764 : if ( io_pMark->GetName() == rNewName )
544 48 : return true;
545 716 : if ( findMark(rNewName) != m_vAllMarks.end() )
546 710 : return false;
547 6 : if (::sw::mark::MarkBase* pMarkBase = dynamic_cast< ::sw::mark::MarkBase* >(io_pMark))
548 : {
549 6 : m_aMarkNamesSet.erase(pMarkBase->GetName());
550 6 : m_aMarkNamesSet.insert(rNewName);
551 6 : pMarkBase->SetName(rNewName);
552 : }
553 6 : return true;
554 : }
555 :
556 4626 : void MarkManager::correctMarksAbsolute(
557 : const SwNodeIndex& rOldNode,
558 : const SwPosition& rNewPos,
559 : const sal_Int32 nOffset)
560 : {
561 4626 : const SwNode* const pOldNode = &rOldNode.GetNode();
562 4626 : SwPosition aNewPos(rNewPos);
563 4626 : aNewPos.nContent += nOffset;
564 4626 : bool isSortingNeeded = false;
565 :
566 90636 : for(iterator_t ppMark = m_vAllMarks.begin();
567 60424 : ppMark != m_vAllMarks.end();
568 : ++ppMark)
569 : {
570 25586 : ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
571 25586 : if (!pMark)
572 0 : continue;
573 : // is on position ??
574 25586 : bool bChangedPos = false;
575 25586 : if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
576 : {
577 2 : pMark->SetMarkPos(aNewPos);
578 2 : bChangedPos = true;
579 : }
580 25586 : bool bChangedOPos = false;
581 29026 : if (pMark->IsExpanded() &&
582 3440 : &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
583 : {
584 : // shift the OtherMark to aNewPos
585 8 : pMark->SetOtherMarkPos(aNewPos);
586 8 : bChangedOPos= true;
587 : }
588 : // illegal selection? collapse the mark and restore sorting later
589 25586 : isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
590 : }
591 :
592 : // restore sorting if needed
593 4626 : if(isSortingNeeded)
594 0 : sortMarks();
595 : #if 0
596 : OSL_TRACE("correctMarksAbsolute");
597 : lcl_DebugMarks(m_vAllMarks);
598 : #endif
599 4626 : }
600 :
601 5018 : void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const sal_Int32 nOffset)
602 : {
603 5018 : const SwNode* const pOldNode = &rOldNode.GetNode();
604 5018 : SwPosition aNewPos(rNewPos);
605 5018 : aNewPos.nContent += nOffset;
606 5018 : bool isSortingNeeded = false;
607 :
608 154746 : for(iterator_t ppMark = m_vAllMarks.begin();
609 103164 : ppMark != m_vAllMarks.end();
610 : ++ppMark)
611 : {
612 : // is on position ??
613 46564 : bool bChangedPos = false, bChangedOPos = false;
614 46564 : ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
615 46564 : if (!pMark)
616 0 : continue;
617 46564 : if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
618 : {
619 1868 : SwPosition aNewPosRel(aNewPos);
620 1868 : aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex();
621 1868 : pMark->SetMarkPos(aNewPosRel);
622 1868 : bChangedPos = true;
623 : }
624 69004 : if(pMark->IsExpanded() &&
625 22440 : &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
626 : {
627 1878 : SwPosition aNewPosRel(aNewPos);
628 1878 : aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex();
629 1878 : pMark->SetOtherMarkPos(aNewPosRel);
630 1878 : bChangedOPos = true;
631 : }
632 : // illegal selection? collapse the mark and restore sorting later
633 46564 : isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
634 : }
635 :
636 : // restore sorting if needed
637 5018 : if(isSortingNeeded)
638 30 : sortMarks();
639 : #if 0
640 : OSL_TRACE("correctMarksRelative");
641 : lcl_DebugMarks(m_vAllMarks);
642 : #endif
643 5018 : }
644 :
645 21344 : void MarkManager::deleteMarks(
646 : const SwNodeIndex& rStt,
647 : const SwNodeIndex& rEnd,
648 : ::std::vector<SaveBookmark>* pSaveBkmk,
649 : const SwIndex* pSttIdx,
650 : const SwIndex* pEndIdx )
651 : {
652 21344 : ::std::vector<const_iterator_t> vMarksToDelete;
653 21344 : bool bIsSortingNeeded = false;
654 :
655 : // boolean indicating, if at least one mark has been moved while collecting marks for deletion
656 21344 : bool bMarksMoved = false;
657 :
658 : // copy all bookmarks in the move area to a vector storing all position data as offset
659 : // reassignment is performed after the move
660 518094 : for(iterator_t ppMark = m_vAllMarks.begin();
661 345396 : ppMark != m_vAllMarks.end();
662 : ++ppMark)
663 : {
664 : // navigator marks should not be moved
665 : // TODO: Check if this might make them invalid
666 151354 : if(IDocumentMarkAccess::GetType(**ppMark) == NAVIGATOR_REMINDER)
667 0 : continue;
668 :
669 151354 : ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
670 :
671 151354 : if (!pMark)
672 0 : continue;
673 :
674 : // on position ??
675 151354 : bool bIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
676 151354 : && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
677 151354 : bool bIsOtherPosInRange = pMark->IsExpanded()
678 39858 : && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
679 175746 : && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
680 : // special case: completely in range, touching the end?
681 151354 : if ( pEndIdx != NULL
682 151556 : && ( ( bIsOtherPosInRange
683 360 : && pMark->GetMarkPos().nNode == rEnd
684 168 : && pMark->GetMarkPos().nContent == *pEndIdx )
685 51168 : || ( bIsPosInRange
686 2026 : && pMark->IsExpanded()
687 204 : && pMark->GetOtherMarkPos().nNode == rEnd
688 204 : && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
689 : {
690 202 : bIsPosInRange = true, bIsOtherPosInRange = true;
691 : }
692 :
693 151354 : if ( bIsPosInRange
694 153388 : && ( bIsOtherPosInRange
695 1834 : || !pMark->IsExpanded() ) )
696 : {
697 : // completely in range
698 :
699 2034 : bool bDeleteMark = true;
700 : {
701 2034 : switch ( IDocumentMarkAccess::GetType( *pMark ) )
702 : {
703 : case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
704 : case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
705 : // no delete of cross-reference bookmarks, if range is inside one paragraph
706 0 : bDeleteMark = rStt != rEnd;
707 0 : break;
708 : case IDocumentMarkAccess::UNO_BOOKMARK:
709 : // no delete of UNO mark, if it is not expanded and only touches the start of the range
710 : bDeleteMark = bIsOtherPosInRange
711 1106 : || pMark->IsExpanded()
712 1106 : || pSttIdx == NULL
713 3312 : || !( pMark->GetMarkPos().nNode == rStt
714 1708 : && pMark->GetMarkPos().nContent == *pSttIdx );
715 1308 : break;
716 : default:
717 726 : bDeleteMark = true;
718 726 : break;
719 : }
720 : }
721 :
722 2034 : if ( bDeleteMark )
723 : {
724 1634 : if ( pSaveBkmk )
725 : {
726 0 : pSaveBkmk->push_back( SaveBookmark( true, true, *pMark, rStt, pSttIdx ) );
727 : }
728 1634 : vMarksToDelete.push_back(ppMark);
729 : }
730 : }
731 149320 : else if ( bIsPosInRange != bIsOtherPosInRange )
732 : {
733 : // the bookmark is partially in the range
734 : // move position of that is in the range out of it
735 :
736 362 : ::std::unique_ptr< SwPosition > pNewPos;
737 : {
738 362 : if ( pEndIdx != NULL )
739 : {
740 362 : pNewPos = ::std::unique_ptr< SwPosition >( new SwPosition( rEnd, *pEndIdx ) );
741 : }
742 : else
743 : {
744 0 : pNewPos =
745 0 : lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() );
746 : }
747 : }
748 :
749 362 : bool bMoveMark = true;
750 : {
751 362 : switch ( IDocumentMarkAccess::GetType( *pMark ) )
752 : {
753 : case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
754 : case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
755 : // no move of cross-reference bookmarks, if move occurs inside a certain node
756 0 : bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode;
757 0 : break;
758 : case IDocumentMarkAccess::ANNOTATIONMARK:
759 : // no move of annotation marks, if method is called to collect deleted marks
760 6 : bMoveMark = pSaveBkmk == NULL;
761 6 : break;
762 : default:
763 356 : bMoveMark = true;
764 356 : break;
765 : }
766 : }
767 362 : if ( bMoveMark )
768 : {
769 362 : if ( bIsPosInRange )
770 2 : pMark->SetMarkPos(*pNewPos);
771 : else
772 360 : pMark->SetOtherMarkPos(*pNewPos);
773 362 : bMarksMoved = true;
774 :
775 : // illegal selection? collapse the mark and restore sorting later
776 362 : bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark );
777 362 : }
778 : }
779 : }
780 :
781 : {
782 : // fdo#61016 delay the deletion of the fieldmark characters
783 : // to prevent that from deleting the marks on that position
784 : // which would invalidate the iterators in vMarksToDelete
785 21344 : std::vector< ::boost::shared_ptr<ILazyDeleter> > vDelay;
786 21344 : vDelay.reserve(vMarksToDelete.size());
787 :
788 : // If needed, sort mark containers containing subsets of the marks
789 : // in order to assure sorting. The sorting is critical for the
790 : // deletion of a mark as it is searched in these container for
791 : // deletion.
792 21344 : if ( vMarksToDelete.size() > 0 && bMarksMoved )
793 : {
794 20 : sortSubsetMarks();
795 : }
796 : // we just remembered the iterators to delete, so we do not need to search
797 : // for the shared_ptr<> (the entry in m_vAllMarks) again
798 : // reverse iteration, since erasing an entry invalidates iterators
799 : // behind it (the iterators in vMarksToDelete are sorted)
800 68934 : for ( ::std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin();
801 45956 : pppMark != vMarksToDelete.rend();
802 : ++pppMark )
803 : {
804 1634 : vDelay.push_back(deleteMark(*pppMark));
805 21344 : }
806 : } // scope to kill vDelay
807 :
808 21344 : if ( bIsSortingNeeded )
809 : {
810 6 : sortMarks();
811 21344 : }
812 :
813 : #if 0
814 : OSL_TRACE("deleteMarks");
815 : lcl_DebugMarks(m_vAllMarks);
816 : #endif
817 21344 : }
818 :
819 : struct LazyFieldmarkDeleter : public IDocumentMarkAccess::ILazyDeleter
820 : {
821 : ::boost::shared_ptr<IMark> const m_pFieldmark;
822 : SwDoc *const m_pDoc;
823 0 : LazyFieldmarkDeleter(
824 : ::boost::shared_ptr<IMark> const& pMark, SwDoc *const pDoc)
825 0 : : m_pFieldmark(pMark), m_pDoc(pDoc)
826 0 : { }
827 0 : virtual ~LazyFieldmarkDeleter()
828 0 : {
829 0 : dynamic_cast<Fieldmark&>(*m_pFieldmark.get()).ReleaseDoc(m_pDoc);
830 0 : }
831 : };
832 :
833 : ::boost::shared_ptr<IDocumentMarkAccess::ILazyDeleter>
834 183149 : MarkManager::deleteMark(const const_iterator_t ppMark)
835 : {
836 183149 : ::boost::shared_ptr<ILazyDeleter> ret;
837 183149 : if (ppMark == m_vAllMarks.end()) return ret;
838 :
839 183149 : switch(IDocumentMarkAccess::GetType(**ppMark))
840 : {
841 : case IDocumentMarkAccess::BOOKMARK:
842 : case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
843 : case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
844 : {
845 842 : IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark);
846 842 : if ( ppBookmark != m_vBookmarks.end() )
847 : {
848 842 : m_vBookmarks.erase(ppBookmark);
849 : }
850 : else
851 : {
852 : OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Bookmark not found in Bookmark container.");
853 : }
854 : }
855 842 : break;
856 :
857 : case IDocumentMarkAccess::TEXT_FIELDMARK:
858 : case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
859 : {
860 0 : IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark);
861 0 : if ( ppFieldmark != m_vFieldmarks.end() )
862 : {
863 0 : m_vFieldmarks.erase(ppFieldmark);
864 0 : ret.reset(new LazyFieldmarkDeleter(*ppMark, m_pDoc));
865 : }
866 : else
867 : {
868 : OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Fieldmark not found in Fieldmark container.");
869 : }
870 : }
871 0 : break;
872 :
873 : case IDocumentMarkAccess::ANNOTATIONMARK:
874 : {
875 0 : IDocumentMarkAccess::iterator_t ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark);
876 0 : if ( ppAnnotationMark != m_vAnnotationMarks.end() )
877 : {
878 0 : m_vAnnotationMarks.erase(ppAnnotationMark);
879 : }
880 : else
881 : {
882 : OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Annotation Mark not found in Annotation Mark container.");
883 : }
884 : }
885 0 : break;
886 :
887 : case IDocumentMarkAccess::NAVIGATOR_REMINDER:
888 : case IDocumentMarkAccess::DDE_BOOKMARK:
889 : case IDocumentMarkAccess::UNO_BOOKMARK:
890 : // no special marks container
891 182307 : break;
892 : }
893 183149 : DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get());
894 183149 : if(pDdeBookmark)
895 842 : pDdeBookmark->DeregisterFromDoc(m_pDoc);
896 : //Effective STL Item 27, get a non-const iterator aI at the same
897 : //position as const iterator ppMark was
898 183149 : iterator_t aI = m_vAllMarks.begin();
899 183149 : std::advance(aI, std::distance<const_iterator_t>(aI, ppMark));
900 :
901 : //fdo#37974
902 : //a) a mark destructor may callback into this method.
903 : //b) vector::erase first calls the destructor of the object, then
904 : //removes it from the vector.
905 : //So if the only reference to the object is the one
906 : //in the vector then we may reenter this method when the mark
907 : //is destructed but before it is removed, i.e. findMark still
908 : //finds the object whose destructor is being run. Take a temp
909 : //extra reference on the shared_ptr, remove the entry from the
910 : //vector, and on xHoldPastErase release findMark won't find
911 : //it anymore.
912 183149 : pMark_t xHoldPastErase = *aI;
913 183149 : m_aMarkNamesSet.erase(ppMark->get()->GetName());
914 183149 : m_vAllMarks.erase(aI);
915 183149 : return ret;
916 : }
917 :
918 181204 : void MarkManager::deleteMark(const IMark* const pMark)
919 : {
920 : OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc,
921 : "<MarkManager::deleteMark(..)>"
922 : " - Mark is not in my doc.");
923 : // finds the last Mark that is starting before pMark
924 : // (pMarkLow < pMark)
925 : iterator_t pMarkLow =
926 : lower_bound(
927 : m_vAllMarks.begin(),
928 : m_vAllMarks.end(),
929 181204 : pMark->GetMarkStart(),
930 181204 : sw::mark::CompareIMarkStartsBefore());
931 181204 : iterator_t pMarkHigh = m_vAllMarks.end();
932 : iterator_t pMarkFound =
933 : find_if(
934 : pMarkLow,
935 : pMarkHigh,
936 181204 : boost::bind( ::std::equal_to<const IMark*>(), boost::bind(&boost::shared_ptr<IMark>::get, _1), pMark ) );
937 181204 : if(pMarkFound != pMarkHigh)
938 181204 : deleteMark(pMarkFound);
939 181204 : }
940 :
941 5083 : void MarkManager::clearAllMarks()
942 : {
943 5083 : m_vFieldmarks.clear();
944 5083 : m_vBookmarks.clear();
945 5083 : m_aMarkNamesSet.clear();
946 :
947 5083 : m_vAnnotationMarks.clear();
948 :
949 : #if OSL_DEBUG_LEVEL > 0
950 : for(iterator_t pBkmk = m_vAllMarks.begin();
951 : pBkmk != m_vAllMarks.end();
952 : ++pBkmk)
953 : OSL_ENSURE( pBkmk->unique(),
954 : "<MarkManager::clearAllMarks(..)> - a Bookmark is still in use.");
955 : #endif
956 5083 : m_vAllMarks.clear();
957 5083 : }
958 :
959 10328 : IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const OUString& rName) const
960 : {
961 10328 : return lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end());
962 : }
963 :
964 9876 : IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const OUString& rName) const
965 : {
966 9876 : return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end());
967 : }
968 :
969 2335167 : IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksBegin() const
970 2335167 : { return m_vAllMarks.begin(); }
971 :
972 9876521 : IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksEnd() const
973 9876521 : { return m_vAllMarks.end(); }
974 :
975 1337227 : sal_Int32 MarkManager::getAllMarksCount() const
976 1337227 : { return m_vAllMarks.size(); }
977 :
978 222 : IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const
979 222 : { return m_vBookmarks.begin(); }
980 :
981 19786 : IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const
982 19786 : { return m_vBookmarks.end(); }
983 :
984 1592 : sal_Int32 MarkManager::getBookmarksCount() const
985 1592 : { return m_vBookmarks.size(); }
986 :
987 158457 : IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const
988 : {
989 : const_iterator_t pFieldmark = find_if(
990 : m_vFieldmarks.begin(),
991 : m_vFieldmarks.end( ),
992 158457 : boost::bind(&IMark::IsCoveringPosition, _1, rPos));
993 158457 : if(pFieldmark == m_vFieldmarks.end()) return NULL;
994 258 : return dynamic_cast<IFieldmark*>(pFieldmark->get());
995 : }
996 :
997 0 : IFieldmark* MarkManager::getDropDownFor(const SwPosition& rPos) const
998 : {
999 0 : IFieldmark *pMark = getFieldmarkFor(rPos);
1000 0 : if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1001 0 : return NULL;
1002 0 : return pMark;
1003 : }
1004 :
1005 6525 : std::vector<IFieldmark*> MarkManager::getDropDownsFor(const SwPaM &rPaM) const
1006 : {
1007 6525 : std::vector<IFieldmark*> aRet;
1008 :
1009 13078 : for (IDocumentMarkAccess::const_iterator_t aI = m_vFieldmarks.begin(),
1010 6525 : aEnd = m_vFieldmarks.end(); aI != aEnd; ++aI)
1011 : {
1012 28 : boost::shared_ptr<IMark> xI = *aI;
1013 28 : const SwPosition &rStart = xI->GetMarkPos();
1014 28 : if (!rPaM.ContainsPosition(rStart))
1015 20 : continue;
1016 :
1017 8 : IFieldmark *pMark = dynamic_cast<IFieldmark*>(xI.get());
1018 8 : if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1019 4 : continue;
1020 :
1021 4 : aRet.push_back(pMark);
1022 4 : }
1023 :
1024 6525 : return aRet;
1025 : }
1026 :
1027 2 : IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const
1028 2 : { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
1029 :
1030 0 : IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const
1031 0 : { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
1032 :
1033 552 : IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksBegin() const
1034 : {
1035 552 : return m_vAnnotationMarks.begin();
1036 : }
1037 :
1038 1548 : IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksEnd() const
1039 : {
1040 1548 : return m_vAnnotationMarks.end();
1041 : }
1042 :
1043 50768 : sal_Int32 MarkManager::getAnnotationMarksCount() const
1044 : {
1045 50768 : return m_vAnnotationMarks.size();
1046 : }
1047 :
1048 1488 : IDocumentMarkAccess::const_iterator_t MarkManager::findAnnotationMark( const ::rtl::OUString& rName ) const
1049 : {
1050 1488 : return lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1051 : }
1052 :
1053 2 : IMark* MarkManager::getAnnotationMarkFor(const SwPosition& rPos) const
1054 : {
1055 : const_iterator_t pAnnotationMark = find_if(
1056 : m_vAnnotationMarks.begin(),
1057 : m_vAnnotationMarks.end( ),
1058 2 : boost::bind(&IMark::IsCoveringPosition, _1, rPos));
1059 2 : if (pAnnotationMark == m_vAnnotationMarks.end())
1060 0 : return NULL;
1061 2 : return pAnnotationMark->get();
1062 : }
1063 :
1064 :
1065 8584 : OUString MarkManager::getUniqueMarkName(const OUString& rName) const
1066 : {
1067 : OSL_ENSURE(rName.getLength(),
1068 : "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1069 8584 : if ( findMark(rName) == getAllMarksEnd() )
1070 : {
1071 8524 : return rName;
1072 : }
1073 60 : OUStringBuffer sBuf;
1074 120 : OUString sTmp;
1075 :
1076 : // try the name "<rName>XXX" (where XXX is a number starting from 1) unless there is
1077 : // a unused name. Due to performance-reasons (especially in mailmerge-Szenarios) there
1078 : // is a map m_aMarkBasenameMapUniqueOffset which holds the next possible offset (XXX) for
1079 : // rName (so there is no need to test for nCnt-values smaller than the offset).
1080 60 : sal_Int32 nCnt = 1;
1081 60 : MarkBasenameMapUniqueOffset_t::const_iterator aIter = m_aMarkBasenameMapUniqueOffset.find(rName);
1082 60 : if(aIter != m_aMarkBasenameMapUniqueOffset.end()) nCnt = aIter->second;
1083 120 : while(nCnt < SAL_MAX_INT32)
1084 : {
1085 60 : sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear();
1086 60 : nCnt++;
1087 60 : if ( findMark(sTmp) == getAllMarksEnd() )
1088 : {
1089 60 : break;
1090 : }
1091 : }
1092 60 : m_aMarkBasenameMapUniqueOffset[rName] = nCnt;
1093 :
1094 120 : return sTmp;
1095 : }
1096 :
1097 10 : void MarkManager::assureSortedMarkContainers() const
1098 : {
1099 10 : const_cast< MarkManager* >(this)->sortMarks();
1100 10 : }
1101 :
1102 66 : void MarkManager::sortSubsetMarks()
1103 : {
1104 66 : sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1105 66 : sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1106 66 : sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1107 66 : }
1108 :
1109 46 : void MarkManager::sortMarks()
1110 : {
1111 46 : sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1112 46 : sortSubsetMarks();
1113 46 : }
1114 :
1115 0 : bool MarkManager::hasMark(const OUString& rName) const
1116 : {
1117 0 : return (m_aMarkNamesSet.find(rName) != m_aMarkNamesSet.end());
1118 : }
1119 :
1120 : }} // namespace ::sw::mark
1121 :
1122 : namespace
1123 : {
1124 20660 : static inline bool lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1125 : {
1126 20660 : return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1127 : }
1128 : }
1129 :
1130 : // IDocumentMarkAccess for SwDoc
1131 549220 : IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess()
1132 549220 : { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1133 :
1134 324495 : const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const
1135 324495 : { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1136 :
1137 0 : SaveBookmark::SaveBookmark(
1138 : bool bSavePos,
1139 : bool bSaveOtherPos,
1140 : const IMark& rBkmk,
1141 : const SwNodeIndex & rMvPos,
1142 : const SwIndex* pIdx)
1143 0 : : m_aName(rBkmk.GetName())
1144 : , m_aShortName()
1145 : , m_aCode()
1146 : , m_bSavePos(bSavePos)
1147 : , m_bSaveOtherPos(bSaveOtherPos)
1148 0 : , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1149 : {
1150 0 : const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1151 0 : if(pBookmark)
1152 : {
1153 0 : m_aShortName = pBookmark->GetShortName();
1154 0 : m_aCode = pBookmark->GetKeyCode();
1155 :
1156 : ::sfx2::Metadatable const*const pMetadatable(
1157 0 : dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1158 0 : if (pMetadatable)
1159 : {
1160 0 : m_pMetadataUndo = pMetadatable->CreateUndo();
1161 : }
1162 : }
1163 0 : m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1164 0 : m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex();
1165 :
1166 0 : if(m_bSavePos)
1167 : {
1168 0 : m_nNode1 -= rMvPos.GetIndex();
1169 0 : if(pIdx && !m_nNode1)
1170 0 : m_nCntnt1 -= pIdx->GetIndex();
1171 : }
1172 :
1173 0 : if(rBkmk.IsExpanded())
1174 : {
1175 0 : m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1176 0 : m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex();
1177 :
1178 0 : if(m_bSaveOtherPos)
1179 : {
1180 0 : m_nNode2 -= rMvPos.GetIndex();
1181 0 : if(pIdx && !m_nNode2)
1182 0 : m_nCntnt2 -= pIdx->GetIndex();
1183 : }
1184 : }
1185 : else
1186 : {
1187 0 : m_nNode2 = ULONG_MAX;
1188 0 : m_nCntnt2 = -1;
1189 : }
1190 0 : }
1191 :
1192 0 : void SaveBookmark::SetInDoc(
1193 : SwDoc* pDoc,
1194 : const SwNodeIndex& rNewPos,
1195 : const SwIndex* pIdx)
1196 : {
1197 0 : SwPaM aPam(rNewPos.GetNode());
1198 0 : if(pIdx)
1199 0 : aPam.GetPoint()->nContent = *pIdx;
1200 :
1201 0 : if(ULONG_MAX != m_nNode2)
1202 : {
1203 0 : aPam.SetMark();
1204 :
1205 0 : if(m_bSaveOtherPos)
1206 : {
1207 0 : aPam.GetMark()->nNode += m_nNode2;
1208 0 : if(pIdx && !m_nNode2)
1209 0 : aPam.GetMark()->nContent += m_nCntnt2;
1210 : else
1211 0 : aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(false), m_nCntnt2);
1212 : }
1213 : else
1214 : {
1215 0 : aPam.GetMark()->nNode = m_nNode2;
1216 0 : aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(false), m_nCntnt2);
1217 : }
1218 : }
1219 :
1220 0 : if(m_bSavePos)
1221 : {
1222 0 : aPam.GetPoint()->nNode += m_nNode1;
1223 :
1224 0 : if(pIdx && !m_nNode1)
1225 0 : aPam.GetPoint()->nContent += m_nCntnt1;
1226 : else
1227 0 : aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1228 : }
1229 : else
1230 : {
1231 0 : aPam.GetPoint()->nNode = m_nNode1;
1232 0 : aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1233 : }
1234 :
1235 0 : if(!aPam.HasMark()
1236 0 : || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, true))
1237 : {
1238 0 : ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType));
1239 0 : if(pBookmark)
1240 : {
1241 0 : pBookmark->SetKeyCode(m_aCode);
1242 0 : pBookmark->SetShortName(m_aShortName);
1243 0 : if (m_pMetadataUndo)
1244 : {
1245 : ::sfx2::Metadatable * const pMeta(
1246 0 : dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1247 : OSL_ENSURE(pMeta, "metadata undo, but not metadatable?");
1248 0 : if (pMeta)
1249 : {
1250 0 : pMeta->RestoreMetadata(m_pMetadataUndo);
1251 : }
1252 : }
1253 : }
1254 0 : }
1255 0 : }
1256 :
1257 : // _DelBookmarks
1258 :
1259 21344 : void _DelBookmarks(
1260 : const SwNodeIndex& rStt,
1261 : const SwNodeIndex& rEnd,
1262 : ::std::vector<SaveBookmark> * pSaveBkmk,
1263 : const SwIndex* pSttIdx,
1264 : const SwIndex* pEndIdx)
1265 : {
1266 : // illegal range ??
1267 42688 : if(rStt.GetIndex() > rEnd.GetIndex()
1268 21344 : || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1269 21344 : return;
1270 21344 : SwDoc* const pDoc = rStt.GetNode().GetDoc();
1271 :
1272 21344 : pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1273 :
1274 : // Copy all Redlines which are in the move area into an array
1275 : // which holds all position information as offset.
1276 : // Assignement happens after moving.
1277 21344 : SwRedlineTbl& rTbl = pDoc->getIDocumentRedlineAccess().GetRedlineTbl();
1278 31674 : for(sal_uInt16 nCnt = 0; nCnt < rTbl.size(); ++nCnt )
1279 : {
1280 : // Is at position?
1281 10330 : SwRangeRedline* pRedl = rTbl[ nCnt ];
1282 :
1283 10330 : SwPosition *pRStt = &pRedl->GetBound(true),
1284 10330 : *pREnd = &pRedl->GetBound(false);
1285 10330 : if( *pRStt > *pREnd )
1286 : {
1287 10320 : SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp;
1288 : }
1289 :
1290 10330 : if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1291 : {
1292 4 : pRStt->nNode = rEnd;
1293 4 : if( pEndIdx )
1294 0 : pRStt->nContent = *pEndIdx;
1295 : else
1296 : {
1297 4 : bool bStt = true;
1298 4 : SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode();
1299 4 : if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) )
1300 : {
1301 4 : bStt = false;
1302 4 : pRStt->nNode = rStt;
1303 4 : if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) )
1304 : {
1305 4 : pRStt->nNode = pREnd->nNode;
1306 4 : pCNd = pRStt->nNode.GetNode().GetCntntNode();
1307 : }
1308 : }
1309 4 : pRStt->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1310 : }
1311 : }
1312 10330 : if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1313 : {
1314 4 : pREnd->nNode = rStt;
1315 4 : if( pSttIdx )
1316 0 : pREnd->nContent = *pSttIdx;
1317 : else
1318 : {
1319 4 : bool bStt = false;
1320 4 : SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
1321 4 : if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) )
1322 : {
1323 4 : bStt = true;
1324 4 : pREnd->nNode = rEnd;
1325 4 : if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) )
1326 : {
1327 4 : pREnd->nNode = pRStt->nNode;
1328 4 : pCNd = pREnd->nNode.GetNode().GetCntntNode();
1329 : }
1330 : }
1331 4 : pREnd->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1332 : }
1333 : }
1334 : }
1335 270 : }
1336 :
1337 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|