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