LibreOffice Module sw (master)  1
docbm.cxx
Go to the documentation of this file.
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 <memory>
21 #include <MarkManager.hxx>
22 #include <bookmrk.hxx>
23 #include <cntfrm.hxx>
24 #include <crossrefbookmark.hxx>
25 #include <annotationmark.hxx>
26 #include <dcontact.hxx>
27 #include <doc.hxx>
29 #include <IDocumentState.hxx>
30 #include <IDocumentUndoRedo.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 <sal/log.hxx>
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 #include <view.hxx>
58 
59 using namespace ::sw::mark;
60 
61 namespace
62 {
63  bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
64  {
65  return pIdx != nullptr
66  ? ( rPos.nNode > rNdIdx
67  || ( rPos.nNode == rNdIdx
68  && rPos.nContent >= pIdx->GetIndex() ) )
69  : rPos.nNode >= rNdIdx;
70  }
71 
72  bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
73  {
74  return rPos.nNode < rNdIdx
75  || ( pIdx != nullptr
76  && rPos.nNode == rNdIdx
77  && rPos.nContent < pIdx->GetIndex() );
78  }
79 
80  bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst,
81  const IDocumentMarkAccess::pMark_t& rpSecond)
82  {
83  auto const& rFirstStart(rpFirst->GetMarkStart());
84  auto const& rSecondStart(rpSecond->GetMarkStart());
85  if (rFirstStart.nNode != rSecondStart.nNode)
86  {
87  return rFirstStart.nNode < rSecondStart.nNode;
88  }
89  const sal_Int32 nFirstContent = rFirstStart.nContent.GetIndex();
90  const sal_Int32 nSecondContent = rSecondStart.nContent.GetIndex();
91  if (nFirstContent != 0 || nSecondContent != 0)
92  {
93  return nFirstContent < nSecondContent;
94  }
95  auto *const pCRFirst (dynamic_cast<::sw::mark::CrossRefBookmark const*>(rpFirst.get()));
96  auto *const pCRSecond(dynamic_cast<::sw::mark::CrossRefBookmark const*>(rpSecond.get()));
97  if ((pCRFirst == nullptr) == (pCRSecond == nullptr))
98  {
99  return false; // equal
100  }
101  return pCRFirst != nullptr; // cross-ref sorts *before*
102  }
103 
104  bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst,
105  const IDocumentMarkAccess::pMark_t& rpSecond)
106  {
107  return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd();
108  }
109 
110  void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks,
111  const IDocumentMarkAccess::pMark_t& pMark)
112  {
113  io_vMarks.insert(
114  lower_bound(
115  io_vMarks.begin(),
116  io_vMarks.end(),
117  pMark,
118  &lcl_MarkOrderingByStart),
119  pMark);
120  }
121 
122  std::unique_ptr<SwPosition> lcl_PositionFromContentNode(
123  SwContentNode * const pContentNode,
124  const bool bAtEnd)
125  {
126  std::unique_ptr<SwPosition> pResult(new SwPosition(*pContentNode));
127  pResult->nContent.Assign(pContentNode, bAtEnd ? pContentNode->Len() : 0);
128  return pResult;
129  }
130 
131  // return a position at the begin of rEnd, if it is a ContentNode
132  // else set it to the begin of the Node after rEnd, if there is one
133  // else set it to the end of the node before rStt
134  // else set it to the ContentNode of the Pos outside the Range
135  std::unique_ptr<SwPosition> lcl_FindExpelPosition(
136  const SwNodeIndex& rStt,
137  const SwNodeIndex& rEnd,
138  const SwPosition& rOtherPosition)
139  {
140  SwContentNode * pNode = rEnd.GetNode().GetContentNode();
141  bool bPosAtEndOfNode = false;
142  if ( pNode == nullptr)
143  {
144  SwNodeIndex aEnd = rEnd;
145  pNode = rEnd.GetNodes().GoNext( &aEnd );
146  bPosAtEndOfNode = false;
147  }
148  if ( pNode == nullptr )
149  {
150  SwNodeIndex aStt = rStt;
151  pNode = SwNodes::GoPrevious(&aStt);
152  bPosAtEndOfNode = true;
153  }
154  if ( pNode != nullptr )
155  {
156  return lcl_PositionFromContentNode( pNode, bPosAtEndOfNode );
157  }
158 
159  return std::make_unique<SwPosition>(rOtherPosition);
160  }
161 
162  IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
163  {
164  IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound(
165  rMarks.begin(),
166  rMarks.end(),
167  rPos,
169  if(pMarkAfter == rMarks.end()) return nullptr;
170  return pMarkAfter->get();
171  };
172 
173  IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
174  {
175  // candidates from which to choose the mark before
177  // no need to consider marks starting after rPos
178  IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound(
179  rMarks.begin(),
180  rMarks.end(),
181  rPos,
183  vCandidates.reserve(pCandidatesEnd - rMarks.begin());
184  // only marks ending before are candidates
185  remove_copy_if(
186  rMarks.begin(),
187  pCandidatesEnd,
188  back_inserter(vCandidates),
189  [&rPos] (IDocumentMarkAccess::pMark_t const& rpMark) { return !rpMark->EndsBefore(rPos); } );
190  // no candidate left => we are in front of the first mark or there are none
191  if(vCandidates.empty()) return nullptr;
192  // return the highest (last) candidate using mark end ordering
193  return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get();
194  }
195 
196  bool lcl_FixCorrectedMark(
197  const bool bChangedPos,
198  const bool bChangedOPos,
199  MarkBase* io_pMark )
200  {
202  {
203  // annotation marks are allowed to span a table cell range.
204  // but trigger sorting to be save
205  return true;
206  }
207 
208  if ( ( bChangedPos || bChangedOPos )
209  && io_pMark->IsExpanded()
210  && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() !=
211  io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() )
212  {
213  if ( !bChangedOPos )
214  {
215  io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() );
216  }
217  io_pMark->ClearOtherMarkPos();
218  DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark);
219  if ( pDdeBkmk != nullptr
220  && pDdeBkmk->IsServer() )
221  {
222  pDdeBkmk->SetRefObject(nullptr);
223  }
224  return true;
225  }
226  return false;
227  }
228 
229  bool lcl_MarkEqualByStart(const IDocumentMarkAccess::pMark_t& rpFirst,
230  const IDocumentMarkAccess::pMark_t& rpSecond)
231  {
232  return !lcl_MarkOrderingByStart(rpFirst, rpSecond) &&
233  !lcl_MarkOrderingByStart(rpSecond, rpFirst);
234  }
235 
236  IDocumentMarkAccess::iterator_t lcl_FindMark(
238  const IDocumentMarkAccess::pMark_t& rpMarkToFind)
239  {
240  IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
241  rMarks.begin(), rMarks.end(),
242  rpMarkToFind, &lcl_MarkOrderingByStart);
243  // since there are usually not too many marks on the same start
244  // position, we are not doing a bisect search for the upper bound
245  // but instead start to iterate from pMarkLow directly
246  while (ppCurrentMark != rMarks.end() && lcl_MarkEqualByStart(*ppCurrentMark, rpMarkToFind))
247  {
248  if(ppCurrentMark->get() == rpMarkToFind.get())
249  {
250  return ppCurrentMark;
251  }
252  ++ppCurrentMark;
253  }
254  // reached a mark starting on a later start pos or the end of the
255  // vector => not found
256  return rMarks.end();
257  };
258 
259  IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos(
261  const SwPosition& rPos,
262  const IDocumentMarkAccess::MarkType eType)
263  {
264  for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
265  rMarks.begin(), rMarks.end(),
266  rPos,
268  ppCurrentMark != rMarks.end();
269  ++ppCurrentMark)
270  {
271  // Once we reach a mark starting after the target pos
272  // we do not need to continue
273  if(ppCurrentMark->get()->StartsAfter(rPos))
274  break;
275  if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType)
276  {
277  return ppCurrentMark;
278  }
279  }
280  // reached a mark starting on a later start pos or the end of the
281  // vector => not found
282  return rMarks.end();
283  };
284 
285  IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName(
286  const OUString& rName,
287  const IDocumentMarkAccess::const_iterator_t& ppMarksBegin,
288  const IDocumentMarkAccess::const_iterator_t& ppMarksEnd)
289  {
290  return find_if(
291  ppMarksBegin,
292  ppMarksEnd,
293  [&rName] (IDocumentMarkAccess::pMark_t const& rpMark) { return rpMark->GetName() == rName; } );
294  }
295 
296  void lcl_DebugMarks(IDocumentMarkAccess::container_t const& rMarks)
297  {
298 #if OSL_DEBUG_LEVEL > 0
299  SAL_INFO("sw.core", rMarks.size() << " Marks");
300  for (IDocumentMarkAccess::const_iterator_t ppMark = rMarks.begin();
301  ppMark != rMarks.end();
302  ++ppMark)
303  {
304  IMark* pMark = ppMark->get();
305  const SwPosition* const pStPos = &pMark->GetMarkStart();
306  const SwPosition* const pEndPos = &pMark->GetMarkEnd();
307  SAL_INFO("sw.core",
308  pStPos->nNode.GetIndex() << "," <<
309  pStPos->nContent.GetIndex() << " " <<
310  pEndPos->nNode.GetIndex() << "," <<
311  pEndPos->nContent.GetIndex() << " " <<
312  typeid(*pMark).name() << " " <<
313  pMark->GetName());
314  }
315 #else
316  (void) rMarks;
317 #endif
318  assert(std::is_sorted(rMarks.begin(), rMarks.end(), lcl_MarkOrderingByStart));
319  };
320 }
321 
323 {
324  const std::type_info* const pMarkTypeInfo = &typeid(rBkmk);
325  // not using dynamic_cast<> here for performance
326  if(*pMarkTypeInfo == typeid(UnoMark))
327  return MarkType::UNO_BOOKMARK;
328  else if(*pMarkTypeInfo == typeid(DdeBookmark))
329  return MarkType::DDE_BOOKMARK;
330  else if(*pMarkTypeInfo == typeid(Bookmark))
331  return MarkType::BOOKMARK;
332  else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark))
334  else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark))
336  else if(*pMarkTypeInfo == typeid(AnnotationMark))
338  else if(*pMarkTypeInfo == typeid(TextFieldmark))
340  else if(*pMarkTypeInfo == typeid(CheckboxFieldmark))
342  else if(*pMarkTypeInfo == typeid(DropDownFieldmark))
344  else if(*pMarkTypeInfo == typeid(NavigatorReminder))
346  else
347  {
348  assert(false && "IDocumentMarkAccess::GetType(..)"
349  " - unknown MarkType. This needs to be fixed!");
350  return MarkType::UNO_BOOKMARK;
351  }
352 }
353 
355 {
356  return OUString("__RefHeading__");
357 }
358 
360 {
361  return rPaM.Start()->nNode.GetNode().IsTextNode() &&
362  rPaM.Start()->nContent.GetIndex() == 0 &&
363  ( !rPaM.HasMark() ||
364  ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode &&
365  rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTextNode()->Len() ) );
366 }
367 
368 namespace sw { namespace mark
369 {
371  : m_vAllMarks()
372  , m_vBookmarks()
373  , m_vFieldmarks()
374  , m_vAnnotationMarks()
375  , m_pDoc(&rDoc)
376  , m_pLastActiveFieldmark(nullptr)
377  { }
378 
380  const OUString& rName,
381  const IDocumentMarkAccess::MarkType eType,
382  sw::mark::InsertMode const eMode)
383  {
384 #if OSL_DEBUG_LEVEL > 0
385  {
386  const SwPosition* const pPos1 = rPaM.GetPoint();
387  const SwPosition* pPos2 = pPos1;
388  if(rPaM.HasMark())
389  pPos2 = rPaM.GetMark();
390  SAL_INFO("sw.core",
391  rName << " " <<
392  pPos1->nNode.GetIndex() << "," <<
393  pPos1->nContent.GetIndex() << " " <<
394  pPos2->nNode.GetIndex() << "," <<
395  pPos2->nContent.GetIndex());
396  }
397 #endif
398  // see for example _SaveContentIdx, Shells
399  OSL_PRECOND(m_vAllMarks.size() < USHRT_MAX,
400  "MarkManager::makeMark(..)"
401  " - more than USHRT_MAX marks are not supported correctly");
402  // There should only be one CrossRefBookmark per Textnode per Type
404  && (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end()))
405  { // this can happen via UNO API
406  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
407  " - refusing to create duplicate CrossRefBookmark");
408  return nullptr;
409  }
410 
411  // create mark
412  pMark_t pMark;
413  switch(eType)
414  {
416  pMark = std::shared_ptr<IMark>(new TextFieldmark(rPaM, rName));
417  break;
419  pMark = std::shared_ptr<IMark>(new CheckboxFieldmark(rPaM));
420  break;
422  pMark = std::shared_ptr<IMark>(new DropDownFieldmark(rPaM));
423  break;
425  pMark = std::shared_ptr<IMark>(new NavigatorReminder(rPaM));
426  break;
428  pMark = std::shared_ptr<IMark>(new Bookmark(rPaM, vcl::KeyCode(), rName));
429  break;
431  pMark = std::shared_ptr<IMark>(new DdeBookmark(rPaM));
432  break;
434  pMark = std::shared_ptr<IMark>(new CrossRefHeadingBookmark(rPaM, vcl::KeyCode(), rName));
435  break;
437  pMark = std::shared_ptr<IMark>(new CrossRefNumItemBookmark(rPaM, vcl::KeyCode(), rName));
438  break;
440  pMark = std::shared_ptr<IMark>(new UnoMark(rPaM));
441  break;
443  pMark = std::shared_ptr<IMark>(new AnnotationMark( rPaM, rName ));
444  break;
445  }
446  assert(pMark.get() &&
447  "MarkManager::makeMark(..)"
448  " - Mark was not created.");
449  MarkBase* pMarkBase = dynamic_cast<MarkBase*>(pMark.get());
450 
451  if (!pMarkBase)
452  return nullptr;
453 
454  if(pMark->GetMarkPos() != pMark->GetMarkStart())
455  pMarkBase->Swap();
456 
457  // for performance reasons, we trust UnoMarks to have a (generated) unique name
459  pMarkBase->SetName( getUniqueMarkName( pMarkBase->GetName() ) );
460 
461  // register mark
462  lcl_InsertMarkSorted(m_vAllMarks, pMark);
463  switch(eType)
464  {
468  lcl_InsertMarkSorted(m_vBookmarks, pMark);
469  break;
473  lcl_InsertMarkSorted(m_vFieldmarks, pMark);
474  break;
476  lcl_InsertMarkSorted( m_vAnnotationMarks, pMark );
477  break;
481  // no special array for these
482  break;
483  }
484  pMarkBase->InitDoc(m_pDoc, eMode);
485  SAL_INFO("sw.core", "--- makeType ---");
486  SAL_INFO("sw.core", "Marks");
487  lcl_DebugMarks(m_vAllMarks);
488  SAL_INFO("sw.core", "Bookmarks");
489  lcl_DebugMarks(m_vBookmarks);
490  SAL_INFO("sw.core", "Fieldmarks");
491  lcl_DebugMarks(m_vFieldmarks);
492 
493  return pMark.get();
494  }
495 
497  const SwPaM& rPaM,
498  const OUString& rName,
499  const OUString& rType )
500  {
501  // Disable undo, because we handle it using SwUndoInsTextFieldmark
502  bool bUndoIsEnabled = m_pDoc->GetIDocumentUndoRedo().DoesUndo();
504 
505  sw::mark::IMark* pMark = makeMark( rPaM, rName,
508  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
509  if (pFieldMark)
510  pFieldMark->SetFieldname( rType );
511 
512  if (bUndoIsEnabled)
513  {
514  m_pDoc->GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
515  m_pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsTextFieldmark>(*pFieldMark));
516  }
517 
518  return pFieldMark;
519  }
520 
522  const SwPaM& rPaM,
523  const OUString& rName,
524  const OUString& rType)
525  {
526  // Disable undo, because we handle it using SwUndoInsNoTextFieldmark
527  bool bUndoIsEnabled = m_pDoc->GetIDocumentUndoRedo().DoesUndo();
529 
530  bool bEnableSetModified = m_pDoc->getIDocumentState().IsEnableSetModified();
532 
533  sw::mark::IMark* pMark = nullptr;
534  if(rType == ODF_FORMCHECKBOX)
535  {
536  pMark = makeMark( rPaM, rName,
539  }
540  else if(rType == ODF_FORMDROPDOWN)
541  {
542  pMark = makeMark( rPaM, rName,
545  }
546 
547  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
548  if (pFieldMark)
549  pFieldMark->SetFieldname( rType );
550 
551  if (bUndoIsEnabled)
552  {
553  m_pDoc->GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
554  m_pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsNoTextFieldmark>(*pFieldMark));
555  }
556 
557  m_pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
559 
560  return pFieldMark;
561  }
562 
564  const SwTextNode& rTextNode,
565  const IDocumentMarkAccess::MarkType eType )
566  {
567  SwPosition aPos(rTextNode);
568  aPos.nContent.Assign(&const_cast<SwTextNode&>(rTextNode), 0);
569  const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType);
570  if(ppExistingMark != m_vBookmarks.end())
571  return ppExistingMark->get();
572  const SwPaM aPaM(aPos);
573  return makeMark(aPaM, OUString(), eType, sw::mark::InsertMode::New);
574  }
575 
577  const SwPaM& rPaM,
578  const OUString& rName )
579  {
582  }
583 
585  ::sw::mark::IMark* const io_pMark,
586  const SwPaM& rPaM)
587  {
588  assert(io_pMark->GetMarkPos().GetDoc() == m_pDoc &&
589  "<MarkManager::repositionMark(..)>"
590  " - Mark is not in my doc.");
591  MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark);
592  if (!pMarkBase)
593  return;
594 
595  pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
596  if(rPaM.HasMark())
597  pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
598  else
599  pMarkBase->ClearOtherMarkPos();
600 
601  if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
602  pMarkBase->Swap();
603 
604  sortMarks();
605  }
606 
608  ::sw::mark::IMark* io_pMark,
609  const OUString& rNewName )
610  {
611  assert(io_pMark->GetMarkPos().GetDoc() == m_pDoc &&
612  "<MarkManager::renameMark(..)>"
613  " - Mark is not in my doc.");
614  if ( io_pMark->GetName() == rNewName )
615  return true;
616  if ( findMark(rNewName) != m_vAllMarks.end() )
617  return false;
618  if (::sw::mark::MarkBase* pMarkBase = dynamic_cast< ::sw::mark::MarkBase* >(io_pMark))
619  {
620  const OUString sOldName(pMarkBase->GetName());
621  pMarkBase->SetName(rNewName);
622 
623  if (dynamic_cast< ::sw::mark::Bookmark* >(io_pMark))
624  {
626  {
628  std::make_unique<SwUndoRenameBookmark>(sOldName, rNewName, m_pDoc));
629  }
631  }
632  }
633  return true;
634  }
635 
637  const SwNodeIndex& rOldNode,
638  const SwPosition& rNewPos,
639  const sal_Int32 nOffset)
640  {
641  const SwNode* const pOldNode = &rOldNode.GetNode();
642  SwPosition aNewPos(rNewPos);
643  aNewPos.nContent += nOffset;
644  bool isSortingNeeded = false;
645 
646  for(iterator_t ppMark = m_vAllMarks.begin();
647  ppMark != m_vAllMarks.end();
648  ++ppMark)
649  {
650  ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
651  // correction of non-existent non-MarkBase instances cannot be done
652  assert(pMark);
653  // is on position ??
654  bool bChangedPos = false;
655  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
656  {
657  pMark->SetMarkPos(aNewPos);
658  bChangedPos = true;
659  isSortingNeeded = true;
660  }
661  bool bChangedOPos = false;
662  if (pMark->IsExpanded() &&
663  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
664  {
665  // shift the OtherMark to aNewPos
666  pMark->SetOtherMarkPos(aNewPos);
667  bChangedOPos= true;
668  isSortingNeeded = true;
669  }
670  // illegal selection? collapse the mark and restore sorting later
671  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
672  }
673 
674  // restore sorting if needed
675  if(isSortingNeeded)
676  sortMarks();
677 
678  SAL_INFO("sw.core", "correctMarksAbsolute");
679  lcl_DebugMarks(m_vAllMarks);
680  }
681 
682  void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const sal_Int32 nOffset)
683  {
684  const SwNode* const pOldNode = &rOldNode.GetNode();
685  SwPosition aNewPos(rNewPos);
686  aNewPos.nContent += nOffset;
687  bool isSortingNeeded = false;
688 
689  for(iterator_t ppMark = m_vAllMarks.begin();
690  ppMark != m_vAllMarks.end();
691  ++ppMark)
692  {
693  // is on position ??
694  bool bChangedPos = false, bChangedOPos = false;
695  ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
696  // correction of non-existent non-MarkBase instances cannot be done
697  assert(pMark);
698  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
699  {
700  SwPosition aNewPosRel(aNewPos);
701  if (dynamic_cast< ::sw::mark::CrossRefBookmark *>(pMark))
702  {
703  // ensure that cross ref bookmark always starts at 0
704  aNewPosRel.nContent = 0; // HACK for WW8 import
705  isSortingNeeded = true; // and sort them to be safe...
706  }
707  aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex();
708  pMark->SetMarkPos(aNewPosRel);
709  bChangedPos = true;
710  }
711  if(pMark->IsExpanded() &&
712  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
713  {
714  SwPosition aNewPosRel(aNewPos);
715  aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex();
716  pMark->SetOtherMarkPos(aNewPosRel);
717  bChangedOPos = true;
718  }
719  // illegal selection? collapse the mark and restore sorting later
720  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
721  }
722 
723  // restore sorting if needed
724  if(isSortingNeeded)
725  sortMarks();
726 
727  SAL_INFO("sw.core", "correctMarksRelative");
728  lcl_DebugMarks(m_vAllMarks);
729  }
730 
732  const SwNodeIndex& rStt,
733  const SwNodeIndex& rEnd,
734  std::vector<SaveBookmark>* pSaveBkmk,
735  const SwIndex* pSttIdx,
736  const SwIndex* pEndIdx )
737  {
738  std::vector<const_iterator_t> vMarksToDelete;
739  bool bIsSortingNeeded = false;
740 
741  // boolean indicating, if at least one mark has been moved while collecting marks for deletion
742  bool bMarksMoved = false;
743  // have marks in the range been skipped instead of deleted
744  bool bMarksSkipDeletion = false;
745 
746  // copy all bookmarks in the move area to a vector storing all position data as offset
747  // reassignment is performed after the move
748  for(iterator_t ppMark = m_vAllMarks.begin();
749  ppMark != m_vAllMarks.end();
750  ++ppMark)
751  {
752  // navigator marks should not be moved
753  // TODO: Check if this might make them invalid
755  continue;
756 
757  ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
758 
759  if (!pMark)
760  continue;
761 
762  // on position ??
763  bool bIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
764  && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
765  bool bIsOtherPosInRange = pMark->IsExpanded()
766  && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
767  && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
768  // special case: completely in range, touching the end?
769  if ( pEndIdx != nullptr
770  && ( ( bIsOtherPosInRange
771  && pMark->GetMarkPos().nNode == rEnd
772  && pMark->GetMarkPos().nContent == *pEndIdx )
773  || ( bIsPosInRange
774  && pMark->IsExpanded()
775  && pMark->GetOtherMarkPos().nNode == rEnd
776  && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
777  {
778  bIsPosInRange = true;
779  bIsOtherPosInRange = true;
780  }
781 
782  if ( bIsPosInRange
783  && ( bIsOtherPosInRange
784  || !pMark->IsExpanded() ) )
785  {
786  // completely in range
787 
788  bool bDeleteMark = true;
789  {
790  switch ( IDocumentMarkAccess::GetType( *pMark ) )
791  {
794  // no delete of cross-reference bookmarks, if range is inside one paragraph
795  bDeleteMark = rStt != rEnd;
796  break;
798  // no delete of UNO mark, if it is not expanded and only touches the start of the range
799  bDeleteMark = bIsOtherPosInRange
800  || pMark->IsExpanded()
801  || pSttIdx == nullptr
802  || !( pMark->GetMarkPos().nNode == rStt
803  && pMark->GetMarkPos().nContent == *pSttIdx );
804  break;
805  default:
806  bDeleteMark = true;
807  break;
808  }
809  }
810 
811  if ( bDeleteMark )
812  {
813  if ( pSaveBkmk )
814  {
815  pSaveBkmk->push_back( SaveBookmark( *pMark, rStt, pSttIdx ) );
816  }
817  vMarksToDelete.emplace_back(ppMark);
818  }
819  else
820  {
821  bMarksSkipDeletion = true;
822  }
823  }
824  else if ( bIsPosInRange != bIsOtherPosInRange )
825  {
826  // the bookmark is partially in the range
827  // move position of that is in the range out of it
828 
829  std::unique_ptr< SwPosition > pNewPos;
830  {
831  if ( pEndIdx != nullptr )
832  {
833  pNewPos = std::make_unique< SwPosition >( rEnd, *pEndIdx );
834  }
835  else
836  {
837  pNewPos =
838  lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() );
839  }
840  }
841 
842  bool bMoveMark = true;
843  {
844  switch ( IDocumentMarkAccess::GetType( *pMark ) )
845  {
848  // no move of cross-reference bookmarks, if move occurs inside a certain node
849  bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode;
850  break;
852  // no move of annotation marks, if method is called to collect deleted marks
853  bMoveMark = pSaveBkmk == nullptr;
854  break;
855  default:
856  bMoveMark = true;
857  break;
858  }
859  }
860  if ( bMoveMark )
861  {
862  if ( bIsPosInRange )
863  pMark->SetMarkPos(*pNewPos);
864  else
865  pMark->SetOtherMarkPos(*pNewPos);
866  bMarksMoved = true;
867 
868  // illegal selection? collapse the mark and restore sorting later
869  bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark );
870  }
871  }
872  }
873 
874  {
875  // fdo#61016 delay the deletion of the fieldmark characters
876  // to prevent that from deleting the marks on that position
877  // which would invalidate the iterators in vMarksToDelete
878  std::vector< std::shared_ptr<ILazyDeleter> > vDelay;
879  vDelay.reserve(vMarksToDelete.size());
880 
881  // If needed, sort mark containers containing subsets of the marks
882  // in order to assure sorting. The sorting is critical for the
883  // deletion of a mark as it is searched in these container for
884  // deletion.
885  if ( !vMarksToDelete.empty() && bMarksMoved )
886  {
887  sortSubsetMarks();
888  }
889  // we just remembered the iterators to delete, so we do not need to search
890  // for the shared_ptr<> (the entry in m_vAllMarks) again
891  // reverse iteration, since erasing an entry invalidates iterators
892  // behind it (the iterators in vMarksToDelete are sorted)
893  for ( std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin();
894  pppMark != vMarksToDelete.rend();
895  ++pppMark )
896  {
897  vDelay.push_back(deleteMark(*pppMark));
898  }
899  } // scope to kill vDelay
900 
901  // also need to sort if both marks were moved and not-deleted because
902  // the not-deleted marks could be in wrong order vs. the moved ones
903  if (bIsSortingNeeded || (bMarksMoved && bMarksSkipDeletion))
904  {
905  sortMarks();
906  }
907 
908  SAL_INFO("sw.core", "deleteMarks");
909  lcl_DebugMarks(m_vAllMarks);
910  }
911 
913  {
914  std::shared_ptr<IMark> const m_pFieldmark;
915  SwDoc *const m_pDoc;
917  std::shared_ptr<IMark> const& pMark, SwDoc *const pDoc)
918  : m_pFieldmark(pMark), m_pDoc(pDoc)
919  { }
920  virtual ~LazyFieldmarkDeleter() override
921  {
922  Fieldmark *const pFieldMark(
923  dynamic_cast<Fieldmark*>(m_pFieldmark.get()));
924  assert(pFieldMark);
925  pFieldMark->ReleaseDoc(m_pDoc);
926  }
927  };
928 
929  std::shared_ptr<IDocumentMarkAccess::ILazyDeleter>
931  {
932  std::shared_ptr<ILazyDeleter> ret;
933  if (ppMark == m_vAllMarks.end()) return ret;
934 
935  switch(IDocumentMarkAccess::GetType(**ppMark))
936  {
940  {
941  IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark);
942  if ( ppBookmark != m_vBookmarks.end() )
943  {
944  m_vBookmarks.erase(ppBookmark);
945  }
946  else
947  {
948  assert(false &&
949  "<MarkManager::deleteMark(..)> - Bookmark not found in Bookmark container.");
950  }
951  }
952  break;
953 
957  {
958  IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark);
959  if ( ppFieldmark != m_vFieldmarks.end() )
960  {
961  if(m_pLastActiveFieldmark == ppFieldmark->get())
963 
964  m_vFieldmarks.erase(ppFieldmark);
965  ret.reset(new LazyFieldmarkDeleter(*ppMark, m_pDoc));
966  }
967  else
968  {
969  assert(false &&
970  "<MarkManager::deleteMark(..)> - Fieldmark not found in Fieldmark container.");
971  }
972  }
973  break;
974 
976  {
977  IDocumentMarkAccess::iterator_t ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark);
978  assert(ppAnnotationMark != m_vAnnotationMarks.end() &&
979  "<MarkManager::deleteMark(..)> - Annotation Mark not found in Annotation Mark container.");
980  m_vAnnotationMarks.erase(ppAnnotationMark);
981  }
982  break;
983 
987  // no special marks container
988  break;
989  }
990  DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get());
991  if(pDdeBookmark)
992  pDdeBookmark->DeregisterFromDoc(m_pDoc);
993  //Effective STL Item 27, get a non-const iterator aI at the same
994  //position as const iterator ppMark was
995  iterator_t aI = m_vAllMarks.begin();
996  std::advance(aI, std::distance<const_iterator_t>(aI, ppMark));
997 
998  //fdo#37974
999  //a) a mark destructor may callback into this method.
1000  //b) vector::erase first calls the destructor of the object, then
1001  //removes it from the vector.
1002  //So if the only reference to the object is the one
1003  //in the vector then we may reenter this method when the mark
1004  //is destructed but before it is removed, i.e. findMark still
1005  //finds the object whose destructor is being run. Take a temp
1006  //extra reference on the shared_ptr, remove the entry from the
1007  //vector, and on xHoldPastErase release findMark won't find
1008  //it anymore.
1009  pMark_t xHoldPastErase = *aI;
1010  m_vAllMarks.erase(aI);
1011  return ret;
1012  }
1013 
1014  void MarkManager::deleteMark(const IMark* const pMark)
1015  {
1016  assert(pMark->GetMarkPos().GetDoc() == m_pDoc &&
1017  "<MarkManager::deleteMark(..)>"
1018  " - Mark is not in my doc.");
1019  // finds the last Mark that is starting before pMark
1020  // (pMarkLow < pMark)
1021  iterator_t pMarkLow =
1022  lower_bound(
1023  m_vAllMarks.begin(),
1024  m_vAllMarks.end(),
1025  pMark->GetMarkStart(),
1027  iterator_t pMarkHigh = m_vAllMarks.end();
1028  iterator_t pMarkFound =
1029  find_if(
1030  pMarkLow,
1031  pMarkHigh,
1032  [pMark] (pMark_t const& rpMark) { return rpMark.get() == pMark; } );
1033  if(pMarkFound != pMarkHigh)
1034  deleteMark(pMarkFound);
1035  }
1036 
1038  {
1040  m_vFieldmarks.clear();
1041  m_vBookmarks.clear();
1042 
1043  m_vAnnotationMarks.clear();
1044 
1045 #if OSL_DEBUG_LEVEL > 0
1046  for(iterator_t pBkmk = m_vAllMarks.begin();
1047  pBkmk != m_vAllMarks.end();
1048  ++pBkmk)
1049  OSL_ENSURE( pBkmk->use_count() == 1,
1050  "<MarkManager::clearAllMarks(..)> - a Bookmark is still in use.");
1051 #endif
1052  m_vAllMarks.clear();
1053  }
1054 
1056  {
1057  return lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end());
1058  }
1059 
1061  {
1062  return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end());
1063  }
1064 
1066  { return m_vAllMarks.begin(); }
1067 
1069  { return m_vAllMarks.end(); }
1070 
1072  { return m_vAllMarks.size(); }
1073 
1075  { return m_vBookmarks.begin(); }
1076 
1078  { return m_vBookmarks.end(); }
1079 
1081  { return m_vBookmarks.size(); }
1082 
1084  {
1085  const_iterator_t pFieldmark = find_if(
1086  m_vFieldmarks.begin(),
1087  m_vFieldmarks.end(),
1088  [&rPos] (pMark_t const& rpMark) { return rpMark->IsCoveringPosition(rPos); } );
1089  if(pFieldmark == m_vFieldmarks.end()) return nullptr;
1090  return dynamic_cast<IFieldmark*>(pFieldmark->get());
1091  }
1092 
1094  {
1095  const_iterator_t pFieldmark = find_if(
1096  m_vFieldmarks.begin(),
1097  m_vFieldmarks.end(),
1098  [&rPos] (pMark_t const& rpMark) { return rpMark->IsCoveringPosition(rPos); } );
1099  if(pFieldmark == m_vFieldmarks.end()) return;
1100 
1101  deleteMark(lcl_FindMark(m_vAllMarks, *pFieldmark));
1102  }
1103 
1105  {
1106  bool bActualChange = false;
1107  if(rNewType == ODF_FORMDROPDOWN)
1108  {
1109  if (dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark))
1110  bActualChange = true;
1111  }
1112  else if(rNewType == ODF_FORMCHECKBOX)
1113  {
1114  if (dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark))
1115  bActualChange = true;
1116  }
1117 
1118  if (!bActualChange)
1119  return nullptr;
1120 
1121  // Store attributes needed to create the new fieldmark
1122  OUString sName = pFieldmark->GetName();
1123  SwPaM aPaM(pFieldmark->GetMarkPos());
1124 
1125  // Remove the old fieldmark and create a new one with the new type
1126  if(aPaM.GetPoint()->nContent > 0)
1127  {
1128  --aPaM.GetPoint()->nContent;
1129  SwPosition aNewPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
1130  deleteFieldmarkAt(aNewPos);
1131  return makeNoTextFieldBookmark(aPaM, sName, rNewType);
1132  }
1133  return nullptr;
1134  }
1135 
1137  {
1138  SwView* pSwView = dynamic_cast<SwView *>(rCursorShell.GetSfxViewShell());
1139  if(!pSwView)
1140  return;
1141 
1142  SwEditWin& rEditWin = pSwView->GetEditWin();
1143  SwPosition aPos(*rCursorShell.GetCursor()->GetPoint());
1144  IFieldmark* pFieldBM = getFieldmarkFor(aPos);
1145  DropDownFieldmark* pNewActiveFieldmark = nullptr;
1146  if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMDROPDOWN)
1147  && aPos.nContent.GetIndex() > 0 )
1148  {
1149  --aPos.nContent;
1150  pFieldBM = getFieldmarkFor(aPos);
1151  }
1152 
1153  if ( pFieldBM && pFieldBM->GetFieldname() == ODF_FORMDROPDOWN )
1154  {
1155  if (m_pLastActiveFieldmark != pFieldBM)
1156  {
1157  DropDownFieldmark* pDropDownFm = dynamic_cast<DropDownFieldmark*>(pFieldBM);
1158  pDropDownFm->ShowButton(&rEditWin);
1159  pNewActiveFieldmark = pDropDownFm;
1160  }
1161  else
1162  {
1163  pNewActiveFieldmark = m_pLastActiveFieldmark;
1164  }
1165  }
1166 
1167  if(pNewActiveFieldmark != m_pLastActiveFieldmark)
1168  {
1170  m_pLastActiveFieldmark = pNewActiveFieldmark;
1171  }
1172  }
1173 
1175  {
1178 
1179  m_pLastActiveFieldmark = nullptr;
1180  }
1181 
1183  {
1184  IFieldmark *pMark = getFieldmarkFor(rPos);
1185  if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1186  return nullptr;
1187  return pMark;
1188  }
1189 
1190  std::vector<IFieldmark*> MarkManager::getDropDownsFor(const SwPaM &rPaM) const
1191  {
1192  std::vector<IFieldmark*> aRet;
1193 
1195  aEnd = m_vFieldmarks.end(); aI != aEnd; ++aI)
1196  {
1197  std::shared_ptr<IMark> xI = *aI;
1198  const SwPosition &rStart = xI->GetMarkPos();
1199  if (!rPaM.ContainsPosition(rStart))
1200  continue;
1201 
1202  IFieldmark *pMark = dynamic_cast<IFieldmark*>(xI.get());
1203  if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1204  continue;
1205 
1206  aRet.push_back(pMark);
1207  }
1208 
1209  return aRet;
1210  }
1211 
1213  { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
1214 
1216  { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
1217 
1219  {
1220  return m_vAnnotationMarks.begin();
1221  }
1222 
1224  {
1225  return m_vAnnotationMarks.end();
1226  }
1227 
1229  {
1230  return m_vAnnotationMarks.size();
1231  }
1232 
1234  {
1235  return lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1236  }
1237 
1239  {
1240  const_iterator_t pAnnotationMark = find_if(
1241  m_vAnnotationMarks.begin(),
1242  m_vAnnotationMarks.end(),
1243  [&rPos] (pMark_t const& rpMark) { return rpMark->IsCoveringPosition(rPos); } );
1244  if (pAnnotationMark == m_vAnnotationMarks.end())
1245  return nullptr;
1246  return pAnnotationMark->get();
1247  }
1248 
1249 
1250  OUString MarkManager::getUniqueMarkName(const OUString& rName) const
1251  {
1252  OSL_ENSURE(rName.getLength(),
1253  "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1254  if( m_pDoc->IsInMailMerge())
1255  {
1256  OUString newName = rName + "MailMergeMark"
1257  + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
1258  + OUString::number( m_vAllMarks.size() + 1 );
1259  return newName;
1260  }
1261 
1262  if ( findMark(rName) == getAllMarksEnd() )
1263  {
1264  return rName;
1265  }
1266  OUStringBuffer sBuf;
1267  OUString sTmp;
1268 
1269  // try the name "<rName>XXX" (where XXX is a number starting from 1) unless there is
1270  // a unused name. Due to performance-reasons (especially in mailmerge-scenarios) there
1271  // is a map m_aMarkBasenameMapUniqueOffset which holds the next possible offset (XXX) for
1272  // rName (so there is no need to test for nCnt-values smaller than the offset).
1273  sal_Int32 nCnt = 1;
1274  MarkBasenameMapUniqueOffset_t::const_iterator aIter = m_aMarkBasenameMapUniqueOffset.find(rName);
1275  if(aIter != m_aMarkBasenameMapUniqueOffset.end()) nCnt = aIter->second;
1276  while(nCnt < SAL_MAX_INT32)
1277  {
1278  sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear();
1279  nCnt++;
1280  if ( findMark(sTmp) == getAllMarksEnd() )
1281  {
1282  break;
1283  }
1284  }
1285  m_aMarkBasenameMapUniqueOffset[rName] = nCnt;
1286 
1287  return sTmp;
1288  }
1289 
1291  {
1292  const_cast< MarkManager* >(this)->sortMarks();
1293  }
1294 
1296  {
1297  sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1298  sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1299  sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1300  }
1301 
1303  {
1304  sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1305  sortSubsetMarks();
1306  }
1307 
1309 {
1310  struct
1311  {
1312  const char* pName;
1313  const container_t* pContainer;
1314  } aContainers[] =
1315  {
1316  // UNO marks are only part of all marks.
1317  {"allmarks", &m_vAllMarks},
1318  {"bookmarks", &m_vBookmarks},
1319  {"fieldmarks", &m_vFieldmarks},
1320  {"annotationmarks", &m_vAnnotationMarks}
1321  };
1322 
1323  xmlTextWriterStartElement(pWriter, BAD_CAST("MarkManager"));
1324  for (const auto & rContainer : aContainers)
1325  {
1326  if (!rContainer.pContainer->empty())
1327  {
1328  xmlTextWriterStartElement(pWriter, BAD_CAST(rContainer.pName));
1329  for (const_iterator_t it = rContainer.pContainer->begin(); it != rContainer.pContainer->end(); ++it)
1330  (*it)->dumpAsXml(pWriter);
1331  xmlTextWriterEndElement(pWriter);
1332  }
1333  }
1334  xmlTextWriterEndElement(pWriter);
1335 }
1336 
1337 }} // namespace ::sw::mark
1338 
1339 namespace
1340 {
1341  bool lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1342  {
1343  return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1344  }
1345 }
1346 
1347 // IDocumentMarkAccess for SwDoc
1349  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1350 
1352  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1353 
1354 SaveBookmark::SaveBookmark(
1355  const IMark& rBkmk,
1356  const SwNodeIndex & rMvPos,
1357  const SwIndex* pIdx)
1358  : m_aName(rBkmk.GetName())
1359  , m_aShortName()
1360  , m_aCode()
1361  , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1362 {
1363  const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1364  if(pBookmark)
1365  {
1366  m_aShortName = pBookmark->GetShortName();
1367  m_aCode = pBookmark->GetKeyCode();
1368 
1369  ::sfx2::Metadatable const*const pMetadatable(
1370  dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1371  if (pMetadatable)
1372  {
1373  m_pMetadataUndo = pMetadatable->CreateUndo();
1374  }
1375  }
1376  m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1378 
1379  m_nNode1 -= rMvPos.GetIndex();
1380  if(pIdx && !m_nNode1)
1381  m_nContent1 -= pIdx->GetIndex();
1382 
1383  if(rBkmk.IsExpanded())
1384  {
1385  m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1387 
1388  m_nNode2 -= rMvPos.GetIndex();
1389  if(pIdx && !m_nNode2)
1390  m_nContent2 -= pIdx->GetIndex();
1391  }
1392  else
1393  {
1394  m_nNode2 = ULONG_MAX;
1395  m_nContent2 = -1;
1396  }
1397 }
1398 
1400  SwDoc* pDoc,
1401  const SwNodeIndex& rNewPos,
1402  const SwIndex* pIdx)
1403 {
1404  SwPaM aPam(rNewPos.GetNode());
1405  if(pIdx)
1406  aPam.GetPoint()->nContent = *pIdx;
1407 
1408  if(ULONG_MAX != m_nNode2)
1409  {
1410  aPam.SetMark();
1411 
1412  aPam.GetMark()->nNode += m_nNode2;
1413  if(pIdx && !m_nNode2)
1414  aPam.GetMark()->nContent += m_nContent2;
1415  else
1416  aPam.GetMark()->nContent.Assign(aPam.GetContentNode(false), m_nContent2);
1417  }
1418 
1419  aPam.GetPoint()->nNode += m_nNode1;
1420 
1421  if(pIdx && !m_nNode1)
1422  aPam.GetPoint()->nContent += m_nContent1;
1423  else
1424  aPam.GetPoint()->nContent.Assign(aPam.GetContentNode(), m_nContent1);
1425 
1426  if(!aPam.HasMark()
1427  || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, true))
1428  {
1429  ::sw::mark::IBookmark* const pBookmark = dynamic_cast<::sw::mark::IBookmark*>(
1430  pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName,
1432  if(pBookmark)
1433  {
1434  pBookmark->SetKeyCode(m_aCode);
1435  pBookmark->SetShortName(m_aShortName);
1436  if (m_pMetadataUndo)
1437  {
1438  ::sfx2::Metadatable * const pMeta(
1439  dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1440  assert(pMeta && "metadata undo, but not metadatable?");
1441  if (pMeta)
1442  {
1444  }
1445  }
1446  }
1447  }
1448 }
1449 
1450 // DelBookmarks
1451 
1453  const SwNodeIndex& rStt,
1454  const SwNodeIndex& rEnd,
1455  std::vector<SaveBookmark> * pSaveBkmk,
1456  const SwIndex* pSttIdx,
1457  const SwIndex* pEndIdx)
1458 {
1459  // illegal range ??
1460  if(rStt.GetIndex() > rEnd.GetIndex()
1461  || (rStt == rEnd && (!pSttIdx || !pEndIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1462  return;
1463  SwDoc* const pDoc = rStt.GetNode().GetDoc();
1464 
1465  pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1466 
1467  // Copy all Redlines which are in the move area into an array
1468  // which holds all position information as offset.
1469  // Assignment happens after moving.
1471  for(SwRangeRedline* pRedl : rTable)
1472  {
1473  // Is at position?
1474  SwPosition *const pRStt = pRedl->Start();
1475  SwPosition *const pREnd = pRedl->End();
1476 
1477  if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1478  {
1479  pRStt->nNode = rEnd;
1480  if( pEndIdx )
1481  pRStt->nContent = *pEndIdx;
1482  else
1483  {
1484  bool bStt = true;
1485  SwContentNode* pCNd = pRStt->nNode.GetNode().GetContentNode();
1486  if( !pCNd && nullptr == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) )
1487  {
1488  bStt = false;
1489  pRStt->nNode = rStt;
1490  if( nullptr == ( pCNd = SwNodes::GoPrevious( &pRStt->nNode )) )
1491  {
1492  pRStt->nNode = pREnd->nNode;
1493  pCNd = pRStt->nNode.GetNode().GetContentNode();
1494  }
1495  }
1496  pRStt->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1497  }
1498  }
1499  if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1500  {
1501  pREnd->nNode = rStt;
1502  if( pSttIdx )
1503  pREnd->nContent = *pSttIdx;
1504  else
1505  {
1506  bool bStt = false;
1507  SwContentNode* pCNd = pREnd->nNode.GetNode().GetContentNode();
1508  if( !pCNd && nullptr == ( pCNd = SwNodes::GoPrevious( &pREnd->nNode )) )
1509  {
1510  bStt = true;
1511  pREnd->nNode = rEnd;
1512  if( nullptr == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) )
1513  {
1514  pREnd->nNode = pRStt->nNode;
1515  pCNd = pREnd->nNode.GetNode().GetContentNode();
1516  }
1517  }
1518  pREnd->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1519  }
1520  }
1521  }
1522 }
1523 
1524 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual sw::mark::IMark * getAnnotationMarkFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1238
container_t::iterator iterator_t
virtual sal_Int32 Len() const
Definition: node.cxx:1183
bool IsInMailMerge() const
Definition: doc.hxx:951
virtual ::sw::mark::IFieldmark * changeNonTextFieldmarkType(::sw::mark::IFieldmark *pFieldmark, const OUString &rNewType) override
Definition: docbm.cxx:1104
virtual sal_Int32 getAllMarksCount() const override
returns the number of marks.
Definition: docbm.cxx:1071
virtual const OUString & GetName() const =0
Marks a position in the document model.
Definition: pam.hxx:35
LazyFieldmarkDeleter(std::shared_ptr< IMark > const &pMark, SwDoc *const pDoc)
Definition: docbm.cxx:916
void DelBookmarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx)
Definition: docbm.cxx:1452
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:185
sal_uLong m_nNode2
Definition: mvsave.hxx:64
virtual void SetFieldname(const OUString &rFieldname)=0
To avoid recursive calls of deleteMark, the removal of dummy characters of fieldmarks has to be delay...
SwNodeIndex nNode
Definition: pam.hxx:37
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
virtual void SetModified()=0
Must be called manually at changes of format.
std::shared_ptr< IMark > const m_pFieldmark
Definition: docbm.cxx:914
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:322
container_t m_vFieldmarks
const SwPosition * GetMark() const
Definition: pam.hxx:209
OUString getUniqueMarkName(const OUString &rName) const
Definition: docbm.cxx:1250
Provides access to the marks of a document.
Definition: doc.hxx:185
#define ODF_FORMCHECKBOX
void SetInDoc(SwDoc *pDoc, const SwNodeIndex &, const SwIndex *pIdx=nullptr)
Definition: docbm.cxx:1399
virtual const SwPosition & GetMarkPos() const =0
virtual ::sw::mark::IFieldmark * getFieldmarkAfter(const SwPosition &rPos) const override
Definition: docbm.cxx:1212
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1290
SwNode & GetNode() const
Definition: ndindex.hxx:118
Fieldmark representing a checkbox form field.
Definition: bookmrk.hxx:251
virtual ::sw::mark::IMark * makeMark(const SwPaM &rPaM, const OUString &rProposedName, MarkType eMark,::sw::mark::InsertMode eMode)=0
Generates a new mark in the document for a certain selection.
SwEditWin & GetEditWin()
Definition: view.hxx:403
virtual const_iterator_t getAllMarksBegin() const override
returns a STL-like random access iterator to the begin of the sequence of marks.
Definition: docbm.cxx:1065
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1348
Dialog to specify the properties of drop-down form field.
Definition: accframe.hxx:34
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
virtual const_iterator_t getAnnotationMarksBegin() const override
Definition: docbm.cxx:1218
IDocumentMarkAccess::MarkType const m_eOrigBkmType
Definition: mvsave.hxx:62
SfxViewShell * GetSfxViewShell() const
Definition: viewsh.hxx:444
virtual ~LazyFieldmarkDeleter() override
Definition: docbm.cxx:920
virtual ::sw::mark::IFieldmark * getFieldmarkFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1083
virtual sw::mark::IFieldmark * makeNoTextFieldBookmark(const SwPaM &rPaM, const OUString &rName, const OUString &rType) override
Definition: docbm.cxx:521
virtual bool IsExpanded() const override
Definition: bookmrk.hxx:82
virtual const_iterator_t getBookmarksEnd() const override
returns a STL-like random access iterator to the end of the sequence of IBookmarks.
Definition: docbm.cxx:1077
virtual void clearAllMarks() override
Clear (deletes) all marks.
Definition: docbm.cxx:1037
static SW_DLLPUBLIC OUString GetCrossRefHeadingBookmarkNamePrefix()
Definition: docbm.cxx:354
static SW_DLLPUBLIC bool IsLegalPaMForCrossRefHeadingBookmark(const SwPaM &rPaM)
Definition: docbm.cxx:359
SwIndex nContent
Definition: pam.hxx:38
container_t m_vBookmarks
SwDoc * GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:178
sal_Int32 m_nContent1
Definition: mvsave.hxx:65
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: docbm.cxx:1308
sal_uLong m_nNode1
Definition: mvsave.hxx:63
bool CheckNodesRange(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, bool bChkSection)
Definition: pam.cxx:238
virtual bool IsEnableSetModified() const =0
virtual ::sw::mark::IMark * getMarkForTextNode(const SwTextNode &rTextNode, IDocumentMarkAccess::MarkType eMark) override
Returns a mark in the document for a paragraph.
Definition: docbm.cxx:563
virtual void deleteMarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< ::sw::mark::SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx) override
Deletes marks in a range.
Definition: docbm.cxx:731
virtual bool DoesUndo() const =0
Is Undo enabled?
virtual void SetKeyCode(const vcl::KeyCode &)=0
virtual void SetShortName(const OUString &)=0
bool ContainsPosition(const SwPosition &rPos) const
Definition: pam.hxx:257
container_t::const_iterator const_iterator_t
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
struct _xmlTextWriter * xmlTextWriterPtr
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
virtual sal_Int32 getAnnotationMarksCount() const override
Definition: docbm.cxx:1228
container_t m_vAnnotationMarks
#define SAL_MAX_INT32
OUString m_aShortName
Definition: mvsave.hxx:60
virtual void deleteMarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< ::sw::mark::SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx)=0
Deletes marks in a range.
OUString const m_aName
Definition: mvsave.hxx:59
virtual const_iterator_t getAnnotationMarksEnd() const override
Definition: docbm.cxx:1223
const SwPosition * GetPoint() const
Definition: pam.hxx:207
void ShowButton(SwEditWin *pEditWin)
Definition: bookmrk.cxx:533
Window class for the Writer edit area, this is the one handling mouse and keyboard events and doing t...
Definition: edtwin.hxx:59
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:198
const std::unique_ptr< ::sw::mark::MarkManager > mpMarkManager
Definition: doc.hxx:208
virtual void ReleaseDoc(SwDoc *const)=0
OUString sName
virtual void assureSortedMarkContainers() const override
Definition: docbm.cxx:1290
MarkBasenameMapUniqueOffset_t m_aMarkBasenameMapUniqueOffset
SwContentNode * GetContentNode()
Definition: node.hxx:615
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
virtual const_iterator_t findMark(const OUString &rName) const override
Finds a mark by name.
Definition: docbm.cxx:1055
std::shared_ptr< ::sw::mark::IMark > pMark_t
SwDoc * GetDoc()
Definition: node.hxx:702
virtual const OUString & GetShortName() const =0
virtual bool renameMark(::sw::mark::IMark *io_pMark, const OUString &rNewName) override
Renames an existing Mark, if possible.
Definition: docbm.cxx:607
Marks a character position inside a document model node.
Definition: index.hxx:37
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:426
std::shared_ptr< MetadatableUndo > CreateUndo() const
std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndo
Definition: mvsave.hxx:67
Marks a node in the document model.
Definition: ndindex.hxx:31
sal_uInt16 sal_Char * pName
virtual const vcl::KeyCode & GetKeyCode() const =0
OUString newName(const OUString &aNewPrefix, const OUString &aOldPrefix, const OUString &old_Name)
virtual const_iterator_t getAllMarksEnd() const override
returns a STL-like random access iterator to the end of the sequence of marks.
Definition: docbm.cxx:1068
virtual const_iterator_t findAnnotationMark(const OUString &rName) const override
Definition: docbm.cxx:1233
sw::mark::DropDownFieldmark * m_pLastActiveFieldmark
const SwPosition * Start() const
Definition: pam.hxx:212
void SetMark(const sw::mark::IMark *pMark)
Definition: index.cxx:214
virtual sw::mark::IMark * makeAnnotationMark(const SwPaM &rPaM, const OUString &rName) override
Definition: docbm.cxx:576
virtual SwPosition & GetOtherMarkPos() const override
Definition: bookmrk.hxx:59
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:367
virtual sal_Int32 getBookmarksCount() const override
returns the number of IBookmarks.
Definition: docbm.cxx:1080
virtual void correctMarksAbsolute(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset) override
Corrects marks (absolute) This method ignores the previous position of the mark in the paragraph...
Definition: docbm.cxx:636
virtual void NotifyCursorUpdate(const SwCursorShell &rCursorShell) override
Definition: docbm.cxx:1136
const SwNodes & GetNodes() const
Definition: ndindex.hxx:155
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:259
virtual std::shared_ptr< ILazyDeleter > deleteMark(const const_iterator_t &ppMark) override
Deletes a mark.
Definition: docbm.cxx:930
#define SAL_INFO(area, stream)
sal_Int32 GetIndex() const
Definition: index.hxx:95
OString DateTimeToOString(const DateTime &rDateTime)
virtual sw::mark::IFieldmark * makeFieldBookmark(const SwPaM &rPaM, const OUString &rName, const OUString &rType) override
Definition: docbm.cxx:496
virtual SwPosition & GetMarkPos() const override
Definition: bookmrk.hxx:55
SwNodes & GetNodes()
Definition: doc.hxx:403
virtual const_iterator_t findBookmark(const OUString &rName) const override
Finds a bookmark by name.
Definition: docbm.cxx:1060
const SwPosition * End() const
Definition: pam.hxx:217
virtual void correctMarksRelative(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset) override
Corrects marks (relative) This method uses the previous position of the mark in the paragraph as offs...
Definition: docbm.cxx:682
virtual void SetMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:174
virtual ::sw::mark::IFieldmark * getFieldmarkBefore(const SwPosition &rPos) const override
Definition: docbm.cxx:1215
virtual ::sw::mark::IFieldmark * getDropDownFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1182
virtual void deleteFieldmarkAt(const SwPosition &rPos) override
Definition: docbm.cxx:1093
virtual std::vector< ::sw::mark::IFieldmark * > getDropDownsFor(const SwPaM &rPaM) const override
Definition: docbm.cxx:1190
virtual void SetEnableSetModified(bool bEnableSetModified)=0
virtual OUString GetFieldname() const =0
#define SAL_WARN(area, stream)
virtual void ClearFieldActivation() override
Definition: docbm.cxx:1174
vcl::KeyCode m_aCode
Definition: mvsave.hxx:61
virtual void DeregisterFromDoc(SwDoc *const pDoc)
Definition: bookmrk.cxx:265
virtual const SwPosition & GetMarkStart() const =0
sal_Int32 m_nContent2
Definition: mvsave.hxx:66
InsertMode
Definition: IMark.hxx:32
virtual void SetOtherMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:180
MarkManager(SwDoc &rDoc)
Definition: docbm.cxx:370
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual const_iterator_t getBookmarksBegin() const override
returns a STL-like random access iterator to the begin of the sequence the IBookmarks.
Definition: docbm.cxx:1074
virtual bool IsExpanded() const =0
std::vector< pMark_t > container_t
bool IsTextNode() const
Definition: node.hxx:636
virtual void repositionMark(::sw::mark::IMark *io_pMark, const SwPaM &rPaM) override
Moves an existing mark to a new selection and performs needed updates.
Definition: docbm.cxx:584
void RestoreMetadata(std::shared_ptr< MetadatableUndo > const &i_pUndo)
Fieldmark representing a drop-down form field.
Definition: bookmrk.hxx:264
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1273
Definition: view.hxx:146
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
#define ODF_FORMDROPDOWN
virtual const SwPosition & GetOtherMarkPos() const =0
virtual ::sw::mark::IMark * makeMark(const SwPaM &rPaM, const OUString &rName, IDocumentMarkAccess::MarkType eMark, sw::mark::InsertMode eMode) override
Definition: docbm.cxx:379
Base class of the Writer document model elements.
Definition: node.hxx:79
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo