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 <utility>
22 
23 #include <MarkManager.hxx>
24 #include <bookmark.hxx>
25 #include <crossrefbookmark.hxx>
26 #include <crsrsh.hxx>
27 #include <annotationmark.hxx>
28 #include <doc.hxx>
30 #include <IDocumentState.hxx>
31 #include <IDocumentUndoRedo.hxx>
32 #include <docary.hxx>
33 #include <xmloff/odffields.hxx>
34 #include <mvsave.hxx>
35 #include <ndtxt.hxx>
36 #include <node.hxx>
37 #include <pam.hxx>
38 #include <redline.hxx>
39 #include <rolbck.hxx>
40 #include <rtl/ustring.hxx>
41 #include <sal/types.h>
42 #include <sal/log.hxx>
43 #include <UndoBookmark.hxx>
44 #include <tools/datetimeutils.hxx>
45 #include <txtfrm.hxx>
46 #include <view.hxx>
47 
48 #include <libxml/xmlstring.h>
49 #include <libxml/xmlwriter.h>
50 #include <comphelper/lok.hxx>
51 
52 constexpr OUStringLiteral S_ANNOTATION_BOOKMARK = u"____";
53 
54 using namespace ::sw::mark;
55 
56 std::vector<::sw::mark::MarkBase*>::const_iterator const&
58 {
59  return *m_pIter;
60 }
61 
62 IDocumentMarkAccess::iterator::iterator(std::vector<::sw::mark::MarkBase*>::const_iterator const& rIter)
63  : m_pIter(rIter)
64 {
65 }
66 
68  : m_pIter(rOther.m_pIter)
69 {
70 }
71 
73 {
74  m_pIter = rOther.m_pIter;
75  return *this;
76 }
77 
79  : m_pIter(std::move(rOther.m_pIter))
80 {
81 }
82 
84 {
85  m_pIter = std::move(rOther.m_pIter);
86  return *this;
87 }
88 
89 // ARGH why does it *need* to return const& ?
90 ::sw::mark::IMark* /*const&*/
92 {
93  return static_cast<sw::mark::IMark*>(**m_pIter);
94 }
95 
97 {
98  ++(*m_pIter);
99  return *this;
100 }
102 {
103  iterator tmp(*this);
104  ++(*m_pIter);
105  return tmp;
106 }
107 
109 {
110  return *m_pIter == *rOther.m_pIter;
111 }
112 
114 {
115  return *m_pIter != *rOther.m_pIter;
116 }
117 
119  : m_pIter(std::in_place)
120 {
121 }
122 
124 {
125  --(*m_pIter);
126  return *this;
127 }
128 
130 {
131  iterator tmp(*this);
132  --(*m_pIter);
133  return tmp;
134 }
135 
137 {
138  (*m_pIter) += n;
139  return *this;
140 }
141 
143 {
144  return iterator(*m_pIter + n);
145 }
146 
148 {
149  (*m_pIter) -= n;
150  return *this;
151 }
152 
154 {
155  return iterator(*m_pIter - n);
156 }
157 
159 {
160  return *m_pIter - *rOther.m_pIter;
161 }
162 
164 {
165  return static_cast<sw::mark::IMark*>((*m_pIter)[n]);
166 }
167 
169 {
170  return *m_pIter < *rOther.m_pIter;
171 }
173 {
174  return *m_pIter > *rOther.m_pIter;
175 }
177 {
178  return *m_pIter <= *rOther.m_pIter;
179 }
181 {
182  return *m_pIter >= *rOther.m_pIter;
183 }
184 
185 
186 namespace
187 {
188  bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
189  {
190  return pIdx != nullptr
191  ? ( rPos.nNode > rNdIdx
192  || ( rPos.nNode == rNdIdx
193  && rPos.nContent >= pIdx->GetIndex() ) )
194  : rPos.nNode >= rNdIdx;
195  }
196 
197  bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
198  {
199  return rPos.nNode < rNdIdx
200  || ( pIdx != nullptr
201  && rPos.nNode == rNdIdx
202  && rPos.nContent < pIdx->GetIndex() );
203  }
204 
205  bool lcl_MarkOrderingByStart(const ::sw::mark::MarkBase *const pFirst,
206  const ::sw::mark::MarkBase *const pSecond)
207  {
208  auto const& rFirstStart(pFirst->GetMarkStart());
209  auto const& rSecondStart(pSecond->GetMarkStart());
210  if (rFirstStart.nNode != rSecondStart.nNode)
211  {
212  return rFirstStart.nNode < rSecondStart.nNode;
213  }
214  const sal_Int32 nFirstContent = rFirstStart.nContent.GetIndex();
215  const sal_Int32 nSecondContent = rSecondStart.nContent.GetIndex();
216  if (nFirstContent != 0 || nSecondContent != 0)
217  {
218  return nFirstContent < nSecondContent;
219  }
220  auto *const pCRFirst (dynamic_cast<::sw::mark::CrossRefBookmark const*>(pFirst));
221  auto *const pCRSecond(dynamic_cast<::sw::mark::CrossRefBookmark const*>(pSecond));
222  if ((pCRFirst == nullptr) == (pCRSecond == nullptr))
223  {
224  return false; // equal
225  }
226  return pCRFirst != nullptr; // cross-ref sorts *before*
227  }
228 
229  bool lcl_MarkOrderingByEnd(const ::sw::mark::MarkBase *const pFirst,
230  const ::sw::mark::MarkBase *const pSecond)
231  {
232  return pFirst->GetMarkEnd() < pSecond->GetMarkEnd();
233  }
234 
235  void lcl_InsertMarkSorted(MarkManager::container_t& io_vMarks,
236  ::sw::mark::MarkBase *const pMark)
237  {
238  io_vMarks.insert(
239  lower_bound(
240  io_vMarks.begin(),
241  io_vMarks.end(),
242  pMark,
243  &lcl_MarkOrderingByStart),
244  pMark);
245  }
246 
247  std::unique_ptr<SwPosition> lcl_PositionFromContentNode(
248  SwContentNode * const pContentNode,
249  const bool bAtEnd)
250  {
251  std::unique_ptr<SwPosition> pResult(new SwPosition(*pContentNode));
252  pResult->nContent.Assign(pContentNode, bAtEnd ? pContentNode->Len() : 0);
253  return pResult;
254  }
255 
256  // return a position at the begin of rEnd, if it is a ContentNode
257  // else set it to the begin of the Node after rEnd, if there is one
258  // else set it to the end of the node before rStt
259  // else set it to the ContentNode of the Pos outside the Range
260  std::unique_ptr<SwPosition> lcl_FindExpelPosition(
261  const SwNodeIndex& rStt,
262  const SwNodeIndex& rEnd,
263  const SwPosition& rOtherPosition)
264  {
265  SwContentNode * pNode = rEnd.GetNode().GetContentNode();
266  bool bPosAtEndOfNode = false;
267  if ( pNode == nullptr)
268  {
269  SwNodeIndex aEnd = rEnd;
270  pNode = rEnd.GetNodes().GoNext( &aEnd );
271  bPosAtEndOfNode = false;
272  }
273  if ( pNode == nullptr )
274  {
275  SwNodeIndex aStt = rStt;
276  pNode = SwNodes::GoPrevious(&aStt);
277  bPosAtEndOfNode = true;
278  }
279  if ( pNode != nullptr )
280  {
281  return lcl_PositionFromContentNode( pNode, bPosAtEndOfNode );
282  }
283 
284  return std::make_unique<SwPosition>(rOtherPosition);
285  }
286 
287  struct CompareIMarkStartsBefore
288  {
289  bool operator()(SwPosition const& rPos,
290  const sw::mark::IMark* pMark)
291  {
292  return rPos < pMark->GetMarkStart();
293  }
294  bool operator()(const sw::mark::IMark* pMark,
295  SwPosition const& rPos)
296  {
297  return pMark->GetMarkStart() < rPos;
298  }
299  };
300 
301  // Apple llvm-g++ 4.2.1 with _GLIBCXX_DEBUG won't eat boost::bind for this
302  // Neither will MSVC 2008 with _DEBUG
303  struct CompareIMarkStartsAfter
304  {
305  bool operator()(SwPosition const& rPos,
306  const sw::mark::IMark* pMark)
307  {
308  return pMark->GetMarkStart() > rPos;
309  }
310  };
311 
312 
313  IMark* lcl_getMarkAfter(const MarkManager::container_t& rMarks, const SwPosition& rPos)
314  {
315  auto const pMarkAfter = upper_bound(
316  rMarks.begin(),
317  rMarks.end(),
318  rPos,
319  CompareIMarkStartsAfter());
320  if(pMarkAfter == rMarks.end())
321  return nullptr;
322  return *pMarkAfter;
323  };
324 
325  IMark* lcl_getMarkBefore(const MarkManager::container_t& rMarks, const SwPosition& rPos)
326  {
327  // candidates from which to choose the mark before
328  MarkManager::container_t vCandidates;
329  // no need to consider marks starting after rPos
330  auto const pCandidatesEnd = upper_bound(
331  rMarks.begin(),
332  rMarks.end(),
333  rPos,
334  CompareIMarkStartsAfter());
335  vCandidates.reserve(pCandidatesEnd - rMarks.begin());
336  // only marks ending before are candidates
337  remove_copy_if(
338  rMarks.begin(),
339  pCandidatesEnd,
340  back_inserter(vCandidates),
341  [&rPos] (const ::sw::mark::MarkBase *const pMark) { return !(pMark->GetMarkEnd() < rPos); } );
342  // no candidate left => we are in front of the first mark or there are none
343  if(vCandidates.empty()) return nullptr;
344  // return the highest (last) candidate using mark end ordering
345  return *max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd);
346  }
347 
348  bool lcl_FixCorrectedMark(
349  const bool bChangedPos,
350  const bool bChangedOPos,
351  MarkBase* io_pMark )
352  {
354  {
355  // annotation marks are allowed to span a table cell range.
356  // but trigger sorting to be save
357  return true;
358  }
359 
360  if ( ( bChangedPos || bChangedOPos )
361  && io_pMark->IsExpanded()
362  && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() !=
363  io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() )
364  {
365  if ( !bChangedOPos )
366  {
367  io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() );
368  }
369  io_pMark->ClearOtherMarkPos();
370  DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark);
371  if ( pDdeBkmk != nullptr
372  && pDdeBkmk->IsServer() )
373  {
374  pDdeBkmk->SetRefObject(nullptr);
375  }
376  return true;
377  }
378  return false;
379  }
380 
381  bool lcl_MarkEqualByStart(const ::sw::mark::MarkBase *const pFirst,
382  const ::sw::mark::MarkBase *const pSecond)
383  {
384  return !lcl_MarkOrderingByStart(pFirst, pSecond) &&
385  !lcl_MarkOrderingByStart(pSecond, pFirst);
386  }
387 
388  MarkManager::container_t::const_iterator lcl_FindMark(
389  MarkManager::container_t& rMarks,
390  const ::sw::mark::MarkBase *const pMarkToFind)
391  {
392  auto ppCurrentMark = lower_bound(
393  rMarks.begin(), rMarks.end(),
394  pMarkToFind, &lcl_MarkOrderingByStart);
395  // since there are usually not too many marks on the same start
396  // position, we are not doing a bisect search for the upper bound
397  // but instead start to iterate from pMarkLow directly
398  while (ppCurrentMark != rMarks.end() && lcl_MarkEqualByStart(*ppCurrentMark, pMarkToFind))
399  {
400  if(*ppCurrentMark == pMarkToFind)
401  {
402  return MarkManager::container_t::const_iterator(std::move(ppCurrentMark));
403  }
404  ++ppCurrentMark;
405  }
406  // reached a mark starting on a later start pos or the end of the
407  // vector => not found
408  return rMarks.end();
409  };
410 
411  MarkManager::container_t::const_iterator lcl_FindMarkAtPos(
412  MarkManager::container_t& rMarks,
413  const SwPosition& rPos,
414  const IDocumentMarkAccess::MarkType eType)
415  {
416  for (auto ppCurrentMark = lower_bound(
417  rMarks.begin(), rMarks.end(),
418  rPos,
419  CompareIMarkStartsBefore());
420  ppCurrentMark != rMarks.end();
421  ++ppCurrentMark)
422  {
423  // Once we reach a mark starting after the target pos
424  // we do not need to continue
425  if((*ppCurrentMark)->GetMarkStart() > rPos)
426  break;
427  if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType)
428  {
429  return MarkManager::container_t::const_iterator(std::move(ppCurrentMark));
430  }
431  }
432  // reached a mark starting on a later start pos or the end of the
433  // vector => not found
434  return rMarks.end();
435  };
436 
437  MarkManager::container_t::const_iterator lcl_FindMarkByName(
438  const OUString& rName,
439  const MarkManager::container_t::const_iterator& ppMarksBegin,
440  const MarkManager::container_t::const_iterator& ppMarksEnd)
441  {
442  return find_if(
443  ppMarksBegin,
444  ppMarksEnd,
445  [&rName] (::sw::mark::MarkBase const*const pMark) { return pMark->GetName() == rName; } );
446  }
447 
448  void lcl_DebugMarks(MarkManager::container_t const& rMarks)
449  {
450 #if OSL_DEBUG_LEVEL > 0
451  SAL_INFO("sw.core", rMarks.size() << " Marks");
452  for (auto ppMark = rMarks.begin();
453  ppMark != rMarks.end();
454  ++ppMark)
455  {
456  IMark* pMark = *ppMark;
457  const SwPosition* const pStPos = &pMark->GetMarkStart();
458  const SwPosition* const pEndPos = &pMark->GetMarkEnd();
459  SAL_INFO("sw.core",
460  sal_Int32(pStPos->nNode.GetIndex()) << "," <<
461  pStPos->nContent.GetIndex() << " " <<
462  sal_Int32(pEndPos->nNode.GetIndex()) << "," <<
463  pEndPos->nContent.GetIndex() << " " <<
464  typeid(*pMark).name() << " " <<
465  pMark->GetName());
466  }
467 #else
468  (void) rMarks;
469 #endif
470  assert(std::is_sorted(rMarks.begin(), rMarks.end(), lcl_MarkOrderingByStart));
471  };
472 }
473 
475 {
476  const std::type_info* const pMarkTypeInfo = &typeid(rBkmk);
477  // not using dynamic_cast<> here for performance
478  if(*pMarkTypeInfo == typeid(UnoMark))
479  return MarkType::UNO_BOOKMARK;
480  else if(*pMarkTypeInfo == typeid(DdeBookmark))
481  return MarkType::DDE_BOOKMARK;
482  else if(*pMarkTypeInfo == typeid(Bookmark))
483  return MarkType::BOOKMARK;
484  else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark))
486  else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark))
488  else if(*pMarkTypeInfo == typeid(AnnotationMark))
490  else if(*pMarkTypeInfo == typeid(TextFieldmark))
492  else if(*pMarkTypeInfo == typeid(CheckboxFieldmark))
494  else if(*pMarkTypeInfo == typeid(DropDownFieldmark))
496  else if(*pMarkTypeInfo == typeid(DateFieldmark))
498  else if(*pMarkTypeInfo == typeid(NavigatorReminder))
500  else
501  {
502  assert(false && "IDocumentMarkAccess::GetType(..)"
503  " - unknown MarkType. This needs to be fixed!");
504  return MarkType::UNO_BOOKMARK;
505  }
506 }
507 
509 {
510  return "__RefHeading__";
511 }
512 
514 {
515  return rPaM.Start()->nNode.GetNode().IsTextNode() &&
516  rPaM.Start()->nContent.GetIndex() == 0 &&
517  ( !rPaM.HasMark() ||
518  ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode &&
519  rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTextNode()->Len() ) );
520 }
521 
523 {
524  if (GetType(rMark) != MarkType::TEXT_FIELDMARK)
525  {
526  return; // TODO FORMDATE has no command?
527  }
528  SwPaM pam(sw::mark::FindFieldSep(rMark), rMark.GetMarkStart());
529  ++pam.GetPoint()->nContent; // skip CH_TXT_ATR_FIELDSTART
530  pam.GetDoc().getIDocumentContentOperations().DeleteAndJoin(pam);
531 }
532 
533 namespace sw::mark
534 {
535  MarkManager::MarkManager(SwDoc& rDoc)
536  : m_rDoc(rDoc)
537  , m_pLastActiveFieldmark(nullptr)
538  { }
539 
541  const OUString& rName,
542  const IDocumentMarkAccess::MarkType eType,
543  sw::mark::InsertMode const eMode,
544  SwPosition const*const pSepPos)
545  {
546 #if OSL_DEBUG_LEVEL > 0
547  {
548  const SwPosition* const pPos1 = rPaM.GetPoint();
549  const SwPosition* pPos2 = pPos1;
550  if(rPaM.HasMark())
551  pPos2 = rPaM.GetMark();
552  SAL_INFO("sw.core",
553  rName << " " <<
554  sal_Int32(pPos1->nNode.GetIndex() )<< "," <<
555  pPos1->nContent.GetIndex() << " " <<
556  sal_Int32(pPos2->nNode.GetIndex()) << "," <<
557  pPos2->nContent.GetIndex());
558  }
559 #endif
560  if ( (!rPaM.GetPoint()->nNode.GetNode().IsTextNode()
561  && (eType != MarkType::UNO_BOOKMARK
562  // SwXTextRange can be on table node or plain start node (FLY_AT_FLY)
563  || !rPaM.GetPoint()->nNode.GetNode().IsStartNode()))
564  || (!rPaM.GetMark()->nNode.GetNode().IsTextNode()
565  && (eType != MarkType::UNO_BOOKMARK
566  || !rPaM.GetMark()->nNode.GetNode().IsStartNode())))
567  {
568  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
569  " - refusing to create mark on non-textnode");
570  return nullptr;
571  }
572  // There should only be one CrossRefBookmark per Textnode per Type
574  && (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end()))
575  { // this can happen via UNO API
576  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
577  " - refusing to create duplicate CrossRefBookmark");
578  return nullptr;
579  }
580 
582  && (eMode == InsertMode::New
583  ? *rPaM.GetPoint() != *rPaM.GetMark()
584  // CopyText: pam covers CH_TXT_ATR_FORMELEMENT
585  : (rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode
586  || rPaM.Start()->nContent.GetIndex() + 1 != rPaM.End()->nContent.GetIndex())))
587  {
588  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
589  " - invalid range on point fieldmark");
590  return nullptr;
591  }
592 
593  if ((eType == MarkType::TEXT_FIELDMARK || eType == MarkType::DATE_FIELDMARK)
595  || (pSepPos && rPaM.GetPoint()->nNode.GetNode().StartOfSectionNode() != pSepPos->nNode.GetNode().StartOfSectionNode())))
596  {
597  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
598  " - invalid range on fieldmark, different nodes array sections");
599  return nullptr;
600  }
601 
602  if ((eType == MarkType::TEXT_FIELDMARK || eType == MarkType::DATE_FIELDMARK)
603  // can't check for Copy - it asserts - but it's also obviously unnecessary
604  && eMode == InsertMode::New
606  {
607  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
608  " - invalid range on fieldmark, overlaps existing fieldmark or meta-field");
609  return nullptr;
610  }
611 
612  // create mark
613  std::unique_ptr<::sw::mark::MarkBase> pMark;
614  switch(eType)
615  {
617  pMark = std::make_unique<TextFieldmark>(rPaM, rName);
618  break;
620  pMark = std::make_unique<CheckboxFieldmark>(rPaM);
621  break;
623  pMark = std::make_unique<DropDownFieldmark>(rPaM);
624  break;
626  pMark = std::make_unique<DateFieldmark>(rPaM);
627  break;
629  pMark = std::make_unique<NavigatorReminder>(rPaM);
630  break;
632  pMark = std::make_unique<Bookmark>(rPaM, vcl::KeyCode(), rName);
633  break;
635  pMark = std::make_unique<DdeBookmark>(rPaM);
636  break;
638  pMark = std::make_unique<CrossRefHeadingBookmark>(rPaM, vcl::KeyCode(), rName);
639  break;
641  pMark = std::make_unique<CrossRefNumItemBookmark>(rPaM, vcl::KeyCode(), rName);
642  break;
644  pMark = std::make_unique<UnoMark>(rPaM);
645  break;
647  pMark = std::make_unique<AnnotationMark>( rPaM, rName );
648  break;
649  }
650  assert(pMark && "MarkManager::makeMark(..) - Mark was not created.");
651 
652  if(pMark->GetMarkPos() != pMark->GetMarkStart())
653  pMark->Swap();
654 
655  // for performance reasons, we trust UnoMarks to have a (generated) unique name
657  pMark->SetName( getUniqueMarkName( pMark->GetName() ) );
658 
659  // insert any dummy chars before inserting into sorted vectors
660  pMark->InitDoc(m_rDoc, eMode, pSepPos);
661 
662  // register mark
663  lcl_InsertMarkSorted(m_vAllMarks, pMark.get());
664  switch(eType)
665  {
669  lcl_InsertMarkSorted(m_vBookmarks, pMark.get());
670  break;
675  lcl_InsertMarkSorted(m_vFieldmarks, pMark.get());
676  break;
678  lcl_InsertMarkSorted( m_vAnnotationMarks, pMark.get() );
679  break;
683  // no special array for these
684  break;
685  }
686  if (eMode == InsertMode::New
689  {
690  // due to SwInsText notifications everything is visible now - tell
691  // layout to hide as appropriate
692  // note: we don't know how many layouts there are and which
693  // parts they hide, so just notify the entire fieldmark, it
694  // should give the right result if not in the most efficient way
695  // note2: can't be done in InitDoc() because it requires the mark
696  // to be inserted in the vectors.
697  SwPaM const tmp(pMark->GetMarkPos(), pMark->GetOtherMarkPos());
699  }
700 
701  SAL_INFO("sw.core", "--- makeType ---");
702  SAL_INFO("sw.core", "Marks");
703  lcl_DebugMarks(m_vAllMarks);
704  SAL_INFO("sw.core", "Bookmarks");
705  lcl_DebugMarks(m_vBookmarks);
706  SAL_INFO("sw.core", "Fieldmarks");
707  lcl_DebugMarks(m_vFieldmarks);
708 
709  return pMark.release();
710  }
711 
713  const SwPaM& rPaM,
714  const OUString& rName,
715  const OUString& rType,
716  SwPosition const*const pSepPos)
717  {
718 
719  // Disable undo, because we handle it using SwUndoInsTextFieldmark
720  bool bUndoIsEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
722 
723  sw::mark::IMark* pMark = nullptr;
724  if(rType == ODF_FORMDATE)
725  {
726  pMark = makeMark(rPaM, rName,
729  pSepPos);
730  }
731  else
732  {
733  pMark = makeMark(rPaM, rName,
736  pSepPos);
737  }
738  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
739  if (pFieldMark)
740  pFieldMark->SetFieldname( rType );
741 
742  if (bUndoIsEnabled)
743  {
744  m_rDoc.GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
745  if (pFieldMark)
746  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsTextFieldmark>(*pFieldMark));
747  }
748 
749  return pFieldMark;
750  }
751 
753  const SwPaM& rPaM,
754  const OUString& rName,
755  const OUString& rType)
756  {
757  // Disable undo, because we handle it using SwUndoInsNoTextFieldmark
758  bool bUndoIsEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
760 
761  bool bEnableSetModified = m_rDoc.getIDocumentState().IsEnableSetModified();
763 
764  sw::mark::IMark* pMark = nullptr;
765  if(rType == ODF_FORMCHECKBOX)
766  {
767  pMark = makeMark( rPaM, rName,
770  }
771  else if(rType == ODF_FORMDROPDOWN)
772  {
773  pMark = makeMark( rPaM, rName,
776  }
777  else if(rType == ODF_FORMDATE)
778  {
779  pMark = makeMark( rPaM, rName,
782  }
783 
784  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
785  if (pFieldMark)
786  pFieldMark->SetFieldname( rType );
787 
788  if (bUndoIsEnabled)
789  {
790  m_rDoc.GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
791  if (pFieldMark)
792  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsNoTextFieldmark>(*pFieldMark));
793  }
794 
795  m_rDoc.getIDocumentState().SetEnableSetModified(bEnableSetModified);
797 
798  return pFieldMark;
799  }
800 
802  const SwTextNode& rTextNode,
803  const IDocumentMarkAccess::MarkType eType )
804  {
805  SwPosition aPos(rTextNode);
806  aPos.nContent.Assign(&const_cast<SwTextNode&>(rTextNode), 0);
807  auto const ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType);
808  if(ppExistingMark != m_vBookmarks.end())
809  return *ppExistingMark;
810  const SwPaM aPaM(aPos);
811  return makeMark(aPaM, OUString(), eType, sw::mark::InsertMode::New);
812  }
813 
815  const SwPaM& rPaM,
816  const OUString& rName )
817  {
820  }
821 
823  ::sw::mark::IMark* const io_pMark,
824  const SwPaM& rPaM)
825  {
826  assert(&io_pMark->GetMarkPos().GetDoc() == &m_rDoc &&
827  "<MarkManager::repositionMark(..)>"
828  " - Mark is not in my doc.");
829  MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark);
830  if (!pMarkBase)
831  return;
832 
833  pMarkBase->InvalidateFrames();
834 
835  pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
836  if(rPaM.HasMark())
837  pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
838  else
839  pMarkBase->ClearOtherMarkPos();
840 
841  if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
842  pMarkBase->Swap();
843 
844  pMarkBase->InvalidateFrames();
845 
846  sortMarks();
847  }
848 
850  ::sw::mark::IMark* io_pMark,
851  const OUString& rNewName )
852  {
853  assert(&io_pMark->GetMarkPos().GetDoc() == &m_rDoc &&
854  "<MarkManager::renameMark(..)>"
855  " - Mark is not in my doc.");
856  if ( io_pMark->GetName() == rNewName )
857  return true;
858  if (lcl_FindMarkByName(rNewName, m_vAllMarks.begin(), m_vAllMarks.end()) != m_vAllMarks.end())
859  return false;
860  if (::sw::mark::MarkBase* pMarkBase = dynamic_cast< ::sw::mark::MarkBase* >(io_pMark))
861  {
862  const OUString sOldName(pMarkBase->GetName());
863  pMarkBase->SetName(rNewName);
864 
865  if (dynamic_cast< ::sw::mark::Bookmark* >(io_pMark))
866  {
868  {
870  std::make_unique<SwUndoRenameBookmark>(sOldName, rNewName, m_rDoc));
871  }
873  }
874  }
875  return true;
876  }
877 
879  const SwNodeIndex& rOldNode,
880  const SwPosition& rNewPos,
881  const sal_Int32 nOffset)
882  {
883  const SwNode* const pOldNode = &rOldNode.GetNode();
884  SwPosition aNewPos(rNewPos);
885  aNewPos.nContent += nOffset;
886  bool isSortingNeeded = false;
887 
888  for (auto ppMark = m_vAllMarks.begin();
889  ppMark != m_vAllMarks.end();
890  ++ppMark)
891  {
892  ::sw::mark::MarkBase *const pMark = *ppMark;
893  // correction of non-existent non-MarkBase instances cannot be done
894  assert(pMark);
895  // is on position ??
896  bool bChangedPos = false;
897  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
898  {
899  pMark->SetMarkPos(aNewPos);
900  bChangedPos = true;
901  isSortingNeeded = true;
902  }
903  bool bChangedOPos = false;
904  if (pMark->IsExpanded() &&
905  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
906  {
907  // shift the OtherMark to aNewPos
908  pMark->SetOtherMarkPos(aNewPos);
909  bChangedOPos= true;
910  isSortingNeeded = true;
911  }
912  // illegal selection? collapse the mark and restore sorting later
913  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
914  }
915 
916  // restore sorting if needed
917  if(isSortingNeeded)
918  sortMarks();
919 
920  SAL_INFO("sw.core", "correctMarksAbsolute");
921  lcl_DebugMarks(m_vAllMarks);
922  }
923 
924  void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const sal_Int32 nOffset)
925  {
926  const SwNode* const pOldNode = &rOldNode.GetNode();
927  SwPosition aNewPos(rNewPos);
928  aNewPos.nContent += nOffset;
929  bool isSortingNeeded = false;
930 
931  for (auto ppMark = m_vAllMarks.begin();
932  ppMark != m_vAllMarks.end();
933  ++ppMark)
934  {
935  // is on position ??
936  bool bChangedPos = false, bChangedOPos = false;
937  ::sw::mark::MarkBase* const pMark = *ppMark;
938  // correction of non-existent non-MarkBase instances cannot be done
939  assert(pMark);
940  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
941  {
942  SwPosition aNewPosRel(aNewPos);
943  if (dynamic_cast< ::sw::mark::CrossRefBookmark *>(pMark))
944  {
945  // ensure that cross ref bookmark always starts at 0
946  aNewPosRel.nContent = 0; // HACK for WW8 import
947  isSortingNeeded = true; // and sort them to be safe...
948  }
949  aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex();
950  pMark->SetMarkPos(aNewPosRel);
951  bChangedPos = true;
952  }
953  if(pMark->IsExpanded() &&
954  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
955  {
956  SwPosition aNewPosRel(aNewPos);
957  aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex();
958  pMark->SetOtherMarkPos(aNewPosRel);
959  bChangedOPos = true;
960  }
961  // illegal selection? collapse the mark and restore sorting later
962  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
963  }
964 
965  // restore sorting if needed
966  if(isSortingNeeded)
967  sortMarks();
968 
969  SAL_INFO("sw.core", "correctMarksRelative");
970  lcl_DebugMarks(m_vAllMarks);
971  }
972 
973  static bool isDeleteMark(
974  ::sw::mark::MarkBase const*const pMark,
975  SwNodeIndex const& rStt,
976  SwNodeIndex const& rEnd,
977  SwIndex const*const pSttIdx,
978  SwIndex const*const pEndIdx,
979  bool & rbIsPosInRange,
980  bool & rbIsOtherPosInRange)
981  {
982  assert(pMark);
983  // navigator marks should not be moved
984  // TODO: Check if this might make them invalid
986  {
987  return false;
988  }
989 
990  // on position ??
991  rbIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
992  && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
993  rbIsOtherPosInRange = pMark->IsExpanded()
994  && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
995  && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
996  // special case: completely in range, touching the end?
997  if ( pEndIdx != nullptr
998  && ( ( rbIsOtherPosInRange
999  && pMark->GetMarkPos().nNode == rEnd
1000  && pMark->GetMarkPos().nContent == *pEndIdx )
1001  || ( rbIsPosInRange
1002  && pMark->IsExpanded()
1003  && pMark->GetOtherMarkPos().nNode == rEnd
1004  && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
1005  {
1006  rbIsPosInRange = true;
1007  rbIsOtherPosInRange = true;
1008  }
1009 
1010  if (rbIsPosInRange
1011  && (rbIsOtherPosInRange
1012  || !pMark->IsExpanded()))
1013  {
1014  // completely in range
1015 
1016  bool bDeleteMark = true;
1017  {
1018  switch ( IDocumentMarkAccess::GetType( *pMark ) )
1019  {
1022  // no delete of cross-reference bookmarks, if range is inside one paragraph
1023  bDeleteMark = rStt != rEnd;
1024  break;
1026  // no delete of UNO mark, if it is not expanded and only touches the start of the range
1027  bDeleteMark = rbIsOtherPosInRange
1028  || pMark->IsExpanded()
1029  || pSttIdx == nullptr
1030  || pMark->GetMarkPos().nNode != rStt
1031  || pMark->GetMarkPos().nContent != *pSttIdx;
1032  break;
1033  default:
1034  bDeleteMark = true;
1035  break;
1036  }
1037  }
1038  return bDeleteMark;
1039  }
1040  return false;
1041  }
1042 
1043  bool MarkManager::isBookmarkDeleted(SwPaM const& rPaM) const
1044  {
1045  SwPosition const& rStart(*rPaM.Start());
1046  SwPosition const& rEnd(*rPaM.End());
1047  for (auto ppMark = m_vBookmarks.begin();
1048  ppMark != m_vBookmarks.end();
1049  ++ppMark)
1050  {
1051  bool bIsPosInRange(false);
1052  bool bIsOtherPosInRange(false);
1053  bool const bDeleteMark = isDeleteMark(*ppMark,
1054  rStart.nNode, rEnd.nNode, &rStart.nContent, &rEnd.nContent,
1055  bIsPosInRange, bIsOtherPosInRange);
1056  if (bDeleteMark
1058  {
1059  return true;
1060  }
1061  }
1062  return false;
1063  }
1064 
1066  const SwNodeIndex& rStt,
1067  const SwNodeIndex& rEnd,
1068  std::vector<SaveBookmark>* pSaveBkmk,
1069  const SwIndex* pSttIdx,
1070  const SwIndex* pEndIdx )
1071  {
1072  std::vector<const_iterator_t> vMarksToDelete;
1073  bool bIsSortingNeeded = false;
1074 
1075  // boolean indicating, if at least one mark has been moved while collecting marks for deletion
1076  bool bMarksMoved = false;
1077  // have marks in the range been skipped instead of deleted
1078  bool bMarksSkipDeletion = false;
1079 
1080  // copy all bookmarks in the move area to a vector storing all position data as offset
1081  // reassignment is performed after the move
1082  for (auto ppMark = m_vAllMarks.begin();
1083  ppMark != m_vAllMarks.end();
1084  ++ppMark)
1085  {
1086  ::sw::mark::MarkBase *const pMark = *ppMark;
1087  bool bIsPosInRange(false);
1088  bool bIsOtherPosInRange(false);
1089  bool const bDeleteMark = isDeleteMark(pMark, rStt, rEnd, pSttIdx, pEndIdx, bIsPosInRange, bIsOtherPosInRange);
1090 
1091  if ( bIsPosInRange
1092  && ( bIsOtherPosInRange
1093  || !pMark->IsExpanded() ) )
1094  {
1095  if ( bDeleteMark )
1096  {
1097  if ( pSaveBkmk )
1098  {
1099  pSaveBkmk->push_back( SaveBookmark( *pMark, rStt, pSttIdx ) );
1100  }
1101  vMarksToDelete.emplace_back(ppMark);
1102  }
1103  else
1104  {
1105  bMarksSkipDeletion = true;
1106  }
1107  }
1108  else if ( bIsPosInRange != bIsOtherPosInRange )
1109  {
1110  // the bookmark is partially in the range
1111  // move position of that is in the range out of it
1112 
1113  std::unique_ptr< SwPosition > pNewPos;
1114  {
1115  if ( pEndIdx != nullptr )
1116  {
1117  pNewPos = std::make_unique< SwPosition >( rEnd, *pEndIdx );
1118  }
1119  else
1120  {
1121  pNewPos =
1122  lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() );
1123  }
1124  }
1125 
1126  bool bMoveMark = true;
1127  {
1128  switch ( IDocumentMarkAccess::GetType( *pMark ) )
1129  {
1132  // no move of cross-reference bookmarks, if move occurs inside a certain node
1133  bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode;
1134  break;
1136  // no move of annotation marks, if method is called to collect deleted marks
1137  bMoveMark = pSaveBkmk == nullptr;
1138  break;
1139  default:
1140  bMoveMark = true;
1141  break;
1142  }
1143  }
1144  if ( bMoveMark )
1145  {
1146  if ( bIsPosInRange )
1147  pMark->SetMarkPos(*pNewPos);
1148  else
1149  pMark->SetOtherMarkPos(*pNewPos);
1150  bMarksMoved = true;
1151 
1152  // illegal selection? collapse the mark and restore sorting later
1153  bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark );
1154  }
1155  }
1156  }
1157 
1158  {
1159  // fdo#61016 delay the deletion of the fieldmark characters
1160  // to prevent that from deleting the marks on that position
1161  // which would invalidate the iterators in vMarksToDelete
1162  std::vector< std::unique_ptr<ILazyDeleter> > vDelay;
1163  vDelay.reserve(vMarksToDelete.size());
1164 
1165  // If needed, sort mark containers containing subsets of the marks
1166  // in order to assure sorting. The sorting is critical for the
1167  // deletion of a mark as it is searched in these container for
1168  // deletion.
1169  if ( !vMarksToDelete.empty() && bMarksMoved )
1170  {
1171  sortSubsetMarks();
1172  }
1173  // we just remembered the iterators to delete, so we do not need to search
1174  // for the shared_ptr<> (the entry in m_vAllMarks) again
1175  // reverse iteration, since erasing an entry invalidates iterators
1176  // behind it (the iterators in vMarksToDelete are sorted)
1177  for ( std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin();
1178  pppMark != vMarksToDelete.rend();
1179  ++pppMark )
1180  {
1181  vDelay.push_back(deleteMark(*pppMark, pSaveBkmk != nullptr));
1182  }
1183  } // scope to kill vDelay
1184 
1185  // also need to sort if both marks were moved and not-deleted because
1186  // the not-deleted marks could be in wrong order vs. the moved ones
1187  if (bIsSortingNeeded || (bMarksMoved && bMarksSkipDeletion))
1188  {
1189  sortMarks();
1190  }
1191 
1192  SAL_INFO("sw.core", "deleteMarks");
1193  lcl_DebugMarks(m_vAllMarks);
1194  }
1195 
1196  namespace {
1197 
1198  struct LazyFieldmarkDeleter : public IDocumentMarkAccess::ILazyDeleter
1199  {
1200  std::unique_ptr<Fieldmark> m_pFieldmark;
1202  bool const m_isMoveNodes;
1203  LazyFieldmarkDeleter(Fieldmark *const pMark, SwDoc& rDoc, bool const isMoveNodes)
1204  : m_pFieldmark(pMark), m_rDoc(rDoc), m_isMoveNodes(isMoveNodes)
1205  {
1206  assert(m_pFieldmark);
1207  }
1208  virtual ~LazyFieldmarkDeleter() override
1209  {
1210  // note: because of the call chain from SwUndoDelete, the field
1211  // command *cannot* be deleted here as it would create a separate
1212  // SwUndoDelete that's interleaved with the SwHistory of the outer
1213  // one - only delete the CH_TXT_ATR_FIELD*!
1214  if (!m_isMoveNodes)
1215  {
1216  m_pFieldmark->ReleaseDoc(m_rDoc);
1217  }
1218  }
1219  };
1220 
1221  }
1222 
1223  std::unique_ptr<IDocumentMarkAccess::ILazyDeleter>
1224  MarkManager::deleteMark(const const_iterator_t& ppMark, bool const isMoveNodes)
1225  {
1226  std::unique_ptr<ILazyDeleter> ret;
1227  if (ppMark.get() == m_vAllMarks.end())
1228  return ret;
1229  IMark* pMark = *ppMark;
1230 
1231  switch(IDocumentMarkAccess::GetType(*pMark))
1232  {
1236  {
1237  auto const ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark.get());
1238  if ( ppBookmark != m_vBookmarks.end() )
1239  {
1240  m_vBookmarks.erase(ppBookmark);
1241  }
1242  else
1243  {
1244  assert(false &&
1245  "<MarkManager::deleteMark(..)> - Bookmark not found in Bookmark container.");
1246  }
1247  }
1248  break;
1249 
1254  {
1255  auto const ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark.get());
1256  if ( ppFieldmark != m_vFieldmarks.end() )
1257  {
1258  if(m_pLastActiveFieldmark == *ppFieldmark)
1260 
1261  m_vFieldmarks.erase(ppFieldmark);
1262  ret.reset(new LazyFieldmarkDeleter(dynamic_cast<Fieldmark*>(pMark), m_rDoc, isMoveNodes));
1263  }
1264  else
1265  {
1266  assert(false &&
1267  "<MarkManager::deleteMark(..)> - Fieldmark not found in Fieldmark container.");
1268  }
1269  }
1270  break;
1271 
1273  {
1274  auto const ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark.get());
1275  assert(ppAnnotationMark != m_vAnnotationMarks.end() &&
1276  "<MarkManager::deleteMark(..)> - Annotation Mark not found in Annotation Mark container.");
1277  m_vAnnotationMarks.erase(ppAnnotationMark);
1278  }
1279  break;
1280 
1284  // no special marks container
1285  break;
1286  }
1287  DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(pMark);
1288  if (pDdeBookmark)
1289  pDdeBookmark->DeregisterFromDoc(m_rDoc);
1290  //Effective STL Item 27, get a non-const iterator aI at the same
1291  //position as const iterator ppMark was
1292  auto aI = m_vAllMarks.begin();
1293  std::advance(aI, std::distance<container_t::const_iterator>(aI, ppMark.get()));
1294 
1295  m_vAllMarks.erase(aI);
1296  // If we don't have a lazy deleter
1297  if (!ret)
1298  // delete after we remove from the list, because the destructor can
1299  // recursively call into this method.
1300  delete pMark;
1301  return ret;
1302  }
1303 
1304  void MarkManager::deleteMark(const IMark* const pMark)
1305  {
1306  assert(&pMark->GetMarkPos().GetDoc() == &m_rDoc &&
1307  "<MarkManager::deleteMark(..)>"
1308  " - Mark is not in my doc.");
1309  // finds the last Mark that is starting before pMark
1310  // (pMarkLow < pMark)
1311  auto [it, endIt] = equal_range(
1312  m_vAllMarks.begin(),
1313  m_vAllMarks.end(),
1314  pMark->GetMarkStart(),
1315  CompareIMarkStartsBefore());
1316  for ( ; it != endIt; ++it)
1317  if (*it == pMark)
1318  {
1319  deleteMark(iterator(it), false);
1320  break;
1321  }
1322  }
1323 
1325  {
1327  m_vFieldmarks.clear();
1328  m_vBookmarks.clear();
1329  m_vAnnotationMarks.clear();
1330  for (const auto & p : m_vAllMarks)
1331  delete p;
1332  m_vAllMarks.clear();
1333  }
1334 
1336  {
1337  auto const ret = lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end());
1338  return IDocumentMarkAccess::iterator(ret);
1339  }
1340 
1342  {
1343  auto const ret = lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end());
1344  return IDocumentMarkAccess::iterator(ret);
1345  }
1346 
1348  { return m_vAllMarks.begin(); }
1349 
1351  { return m_vAllMarks.end(); }
1352 
1354  { return m_vAllMarks.size(); }
1355 
1357  { return m_vBookmarks.begin(); }
1358 
1360  { return m_vBookmarks.end(); }
1361 
1363  { return m_vBookmarks.size(); }
1364 
1366  { return m_vFieldmarks.begin(); }
1367 
1369  { return m_vFieldmarks.end(); }
1370 
1371 
1372  // finds the first that is starting after
1374  {
1375  return std::upper_bound(
1376  m_vBookmarks.begin(),
1377  m_vBookmarks.end(),
1378  rPos,
1379  CompareIMarkStartsAfter());
1380  }
1381 
1383  {
1384  auto const pFieldmark = find_if(
1385  m_vFieldmarks.begin(),
1386  m_vFieldmarks.end(),
1387  [&rPos] (::sw::mark::MarkBase const*const pMark) {
1388  return pMark->GetMarkStart() == rPos
1389  // end position includes the CH_TXT_ATR_FIELDEND
1390  || (pMark->GetMarkEnd().nContent.GetIndex() == rPos.nContent.GetIndex() + 1
1391  && pMark->GetMarkEnd().nNode == rPos.nNode);
1392  } );
1393  return (pFieldmark == m_vFieldmarks.end())
1394  ? nullptr
1395  : dynamic_cast<IFieldmark*>(*pFieldmark);
1396  }
1397 
1399  {
1400  auto itFieldmark = find_if(
1401  m_vFieldmarks.begin(),
1402  m_vFieldmarks.end(),
1403  [&rPos] (const ::sw::mark::MarkBase *const pMark) { return pMark->IsCoveringPosition(rPos); } );
1404  if (itFieldmark == m_vFieldmarks.end())
1405  return nullptr;
1406  auto pFieldmark(*itFieldmark);
1407  for ( ; itFieldmark != m_vFieldmarks.end()
1408  && (**itFieldmark).GetMarkStart() <= rPos; ++itFieldmark)
1409  { // find the innermost fieldmark
1410  if (rPos < (**itFieldmark).GetMarkEnd()
1411  && (pFieldmark->GetMarkStart() < (**itFieldmark).GetMarkStart()
1412  || (**itFieldmark).GetMarkEnd() < pFieldmark->GetMarkEnd()))
1413  {
1414  pFieldmark = *itFieldmark;
1415  }
1416  }
1417  return dynamic_cast<IFieldmark*>(pFieldmark);
1418  }
1419 
1421  {
1422  auto const pFieldmark = dynamic_cast<Fieldmark*>(getFieldmarkAt(rPos));
1423  assert(pFieldmark); // currently all callers require it to be there
1424 
1425  deleteMark(lcl_FindMark(m_vAllMarks, pFieldmark), false);
1426  }
1427 
1429  {
1430  bool bActualChange = false;
1431  if(rNewType == ODF_FORMDROPDOWN)
1432  {
1433  if (!dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark))
1434  bActualChange = true;
1435  if (!dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark)) // only allowed converting between checkbox <-> dropdown
1436  return nullptr;
1437  }
1438  else if(rNewType == ODF_FORMCHECKBOX)
1439  {
1440  if (!dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark))
1441  bActualChange = true;
1442  if (!dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark)) // only allowed converting between checkbox <-> dropdown
1443  return nullptr;
1444  }
1445  else if(rNewType == ODF_FORMDATE)
1446  {
1447  if (!dynamic_cast<::sw::mark::DateFieldmark*>(pFieldmark))
1448  bActualChange = true;
1449  if (!dynamic_cast<::sw::mark::TextFieldmark*>(pFieldmark)) // only allowed converting between date field <-> text field
1450  return nullptr;
1451  }
1452 
1453  if (!bActualChange)
1454  return nullptr;
1455 
1456  // Store attributes needed to create the new fieldmark
1457  OUString sName = pFieldmark->GetName();
1458  SwPaM const aPaM(pFieldmark->GetMarkStart());
1459 
1460  // Remove the old fieldmark and create a new one with the new type
1461  if (rNewType == ODF_FORMDROPDOWN || rNewType == ODF_FORMCHECKBOX)
1462  {
1463  SwPosition aNewPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
1464  deleteFieldmarkAt(aNewPos);
1465  return makeNoTextFieldBookmark(aPaM, sName, rNewType);
1466  }
1467  else if(rNewType == ODF_FORMDATE)
1468  {
1469  SwPosition aPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
1470  SwPaM aNewPaM(pFieldmark->GetMarkStart(), pFieldmark->GetMarkEnd());
1471  deleteFieldmarkAt(aPos);
1472  // HACK: hard-code the separator position here at the start because
1473  // writerfilter put it in the wrong place (at the end) on attach()
1474  SwPosition const sepPos(*aNewPaM.Start());
1475  return makeFieldBookmark(aNewPaM, sName, rNewType, &sepPos);
1476  }
1477  return nullptr;
1478  }
1479 
1481  {
1482  SwView* pSwView = dynamic_cast<SwView *>(rCursorShell.GetSfxViewShell());
1483  if(!pSwView)
1484  return;
1485 
1486  SwEditWin& rEditWin = pSwView->GetEditWin();
1487  SwPosition aPos(*rCursorShell.GetCursor()->GetPoint());
1488  IFieldmark* pFieldBM = getFieldmarkFor(aPos);
1489  FieldmarkWithDropDownButton* pNewActiveFieldmark = nullptr;
1490  if ((!pFieldBM || (pFieldBM->GetFieldname() != ODF_FORMDROPDOWN && pFieldBM->GetFieldname() != ODF_FORMDATE))
1491  && aPos.nContent.GetIndex() > 0 )
1492  {
1493  --aPos.nContent;
1494  pFieldBM = getFieldmarkFor(aPos);
1495  }
1496 
1497  if ( pFieldBM && (pFieldBM->GetFieldname() == ODF_FORMDROPDOWN ||
1498  pFieldBM->GetFieldname() == ODF_FORMDATE))
1499  {
1500  if (m_pLastActiveFieldmark != pFieldBM)
1501  {
1502  FieldmarkWithDropDownButton& rFormField = dynamic_cast<FieldmarkWithDropDownButton&>(*pFieldBM);
1503  pNewActiveFieldmark = &rFormField;
1504  }
1505  else
1506  {
1507  pNewActiveFieldmark = m_pLastActiveFieldmark;
1508  }
1509  }
1510 
1511  if(pNewActiveFieldmark != m_pLastActiveFieldmark)
1512  {
1514  m_pLastActiveFieldmark = pNewActiveFieldmark;
1515  if(pNewActiveFieldmark)
1516  pNewActiveFieldmark->ShowButton(&rEditWin);
1517  }
1518 
1519  LOKUpdateActiveField(pSwView);
1520  }
1521 
1523  {
1526 
1527  m_pLastActiveFieldmark = nullptr;
1528  }
1529 
1531  {
1533  return;
1534 
1536  {
1537  if (auto pDrowDown = m_pLastActiveFieldmark->GetFieldname() == ODF_FORMDROPDOWN ?
1539  nullptr)
1540  {
1541  pDrowDown->SendLOKShowMessage(pViewShell);
1542  }
1543  }
1544  else
1545  {
1546  // Check whether we have any drop down fieldmark at all.
1547  bool bDropDownFieldExist = false;
1548  for (auto aIter = m_vFieldmarks.begin(); aIter != m_vFieldmarks.end(); ++aIter)
1549  {
1550  IFieldmark *pMark = dynamic_cast<IFieldmark*>(*aIter);
1551  if (pMark && pMark->GetFieldname() == ODF_FORMDROPDOWN)
1552  {
1553  bDropDownFieldExist = true;
1554  break;
1555  }
1556  }
1557 
1558  if (bDropDownFieldExist)
1560  }
1561  }
1562 
1564  {
1565  IFieldmark *pMark = getFieldmarkAt(rPos);
1566  if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1567  return nullptr;
1568  return pMark;
1569  }
1570 
1571  std::vector<IFieldmark*> MarkManager::getNoTextFieldmarksIn(const SwPaM &rPaM) const
1572  {
1573  std::vector<IFieldmark*> aRet;
1574 
1575  for (auto aI = m_vFieldmarks.begin(),
1576  aEnd = m_vFieldmarks.end(); aI != aEnd; ++aI)
1577  {
1578  ::sw::mark::IMark* pI = *aI;
1579  const SwPosition &rStart = pI->GetMarkPos();
1580  if (!rPaM.ContainsPosition(rStart))
1581  continue;
1582 
1583  IFieldmark *pMark = dynamic_cast<IFieldmark*>(pI);
1584  if (!pMark || (pMark->GetFieldname() != ODF_FORMDROPDOWN
1585  && pMark->GetFieldname() != ODF_FORMCHECKBOX))
1586  {
1587  continue;
1588  }
1589 
1590  aRet.push_back(pMark);
1591  }
1592 
1593  return aRet;
1594  }
1595 
1597  { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
1598 
1600  { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
1601 
1603  {
1604  return m_vAnnotationMarks.begin();
1605  }
1606 
1608  {
1609  return m_vAnnotationMarks.end();
1610  }
1611 
1613  {
1614  return m_vAnnotationMarks.size();
1615  }
1616 
1618  {
1619  auto const ret = lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1620  return IDocumentMarkAccess::iterator(ret);
1621  }
1622 
1624  {
1625  auto const pAnnotationMark = find_if(
1626  m_vAnnotationMarks.begin(),
1627  m_vAnnotationMarks.end(),
1628  [&rPos] (const ::sw::mark::MarkBase *const pMark) { return pMark->IsCoveringPosition(rPos); } );
1629  if (pAnnotationMark == m_vAnnotationMarks.end())
1630  return nullptr;
1631  return *pAnnotationMark;
1632  }
1633 
1634  // finds the first that is starting after
1636  {
1637  return std::upper_bound(
1638  m_vAnnotationMarks.begin(),
1639  m_vAnnotationMarks.end(),
1640  rPos,
1641  CompareIMarkStartsAfter());
1642  }
1643 
1644  // create helper bookmark for annotations on tracked deletions
1646  const OUString& rName,
1647  const IDocumentMarkAccess::MarkType eType,
1648  sw::mark::InsertMode const eMode,
1649  SwPosition const*const pSepPos)
1650  {
1651  OUString sAnnotationBookmarkName(rName + S_ANNOTATION_BOOKMARK);
1652  return makeMark( rPaM, sAnnotationBookmarkName, eType, eMode, pSepPos);
1653  }
1654 
1655  // find helper bookmark of annotations on tracked deletions
1657  {
1658  OUString sAnnotationBookmarkName(rName + S_ANNOTATION_BOOKMARK);
1659  return findBookmark(sAnnotationBookmarkName);
1660  }
1661 
1662  // restore text ranges of annotations on tracked deletions
1663  // based on the helper bookmarks (which can survive I/O and hiding redlines)
1665  {
1666  for (auto iter = getBookmarksBegin();
1667  iter != getBookmarksEnd(); )
1668  {
1669  const OUString & rBookmarkName = (**iter).GetName();
1670  sal_Int32 nPos;
1671  if ( rBookmarkName.startsWith("__Annotation__") &&
1672  (nPos = rBookmarkName.indexOf(S_ANNOTATION_BOOKMARK)) > -1 )
1673  {
1674  ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
1675  IDocumentMarkAccess::const_iterator_t pMark = findAnnotationMark(rBookmarkName.copy(0, nPos));
1676  if ( pMark != getAnnotationMarksEnd() )
1677  {
1678  const SwPaM aPam((**iter).GetMarkStart(), (**pMark).GetMarkEnd());
1679  repositionMark(*pMark, aPam);
1680  }
1681  if (bDelete)
1682  {
1683  deleteMark(&**iter);
1684  // this invalidates iter, have to start over...
1685  iter = getBookmarksBegin();
1686  }
1687  else
1688  ++iter;
1689  }
1690  else
1691  ++iter;
1692  }
1693  }
1694 
1695  OUString MarkManager::getUniqueMarkName(const OUString& rName) const
1696  {
1697  OSL_ENSURE(rName.getLength(),
1698  "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1699  if( m_rDoc.IsInMailMerge())
1700  {
1701  OUString newName = rName + "MailMergeMark"
1702  + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
1703  + OUString::number( m_vAllMarks.size() + 1 );
1704  return newName;
1705  }
1706 
1707  if (lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end()) == m_vAllMarks.end())
1708  {
1709  return rName;
1710  }
1711  OUString sTmp;
1712 
1713  // try the name "<rName>XXX" (where XXX is a number starting from 1) unless there is
1714  // an unused name. Due to performance-reasons (especially in mailmerge-scenarios) there
1715  // is a map m_aMarkBasenameMapUniqueOffset which holds the next possible offset (XXX) for
1716  // rName (so there is no need to test for nCnt-values smaller than the offset).
1717  sal_Int32 nCnt = 1;
1718  MarkBasenameMapUniqueOffset_t::const_iterator aIter = m_aMarkBasenameMapUniqueOffset.find(rName);
1719  if(aIter != m_aMarkBasenameMapUniqueOffset.end()) nCnt = aIter->second;
1720  while(nCnt < SAL_MAX_INT32)
1721  {
1722  sTmp = rName + OUString::number(nCnt);
1723  nCnt++;
1724  if (lcl_FindMarkByName(sTmp, m_vAllMarks.begin(), m_vAllMarks.end()) == m_vAllMarks.end())
1725  {
1726  break;
1727  }
1728  }
1729  m_aMarkBasenameMapUniqueOffset[rName] = nCnt;
1730 
1731  return sTmp;
1732  }
1733 
1735  {
1736  const_cast< MarkManager* >(this)->sortMarks();
1737  }
1738 
1740  {
1741  sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1742  sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1743  sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1744  }
1745 
1747  {
1748  sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1749  sortSubsetMarks();
1750  }
1751 
1753 {
1754  struct
1755  {
1756  const char* pName;
1757  const container_t* pContainer;
1758  } aContainers[] =
1759  {
1760  // UNO marks are only part of all marks.
1761  {"allmarks", &m_vAllMarks},
1762  {"bookmarks", &m_vBookmarks},
1763  {"fieldmarks", &m_vFieldmarks},
1764  {"annotationmarks", &m_vAnnotationMarks}
1765  };
1766 
1767  (void)xmlTextWriterStartElement(pWriter, BAD_CAST("MarkManager"));
1768  for (const auto & rContainer : aContainers)
1769  {
1770  if (!rContainer.pContainer->empty())
1771  {
1772  (void)xmlTextWriterStartElement(pWriter, BAD_CAST(rContainer.pName));
1773  for (auto it = rContainer.pContainer->begin(); it != rContainer.pContainer->end(); ++it)
1774  (*it)->dumpAsXml(pWriter);
1775  (void)xmlTextWriterEndElement(pWriter);
1776  }
1777  }
1778  (void)xmlTextWriterEndElement(pWriter);
1779 }
1780 
1781 } // namespace ::sw::mark
1782 
1783 namespace
1784 {
1785  bool lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1786  {
1787  return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1788  }
1789 }
1790 
1791 // IDocumentMarkAccess for SwDoc
1793  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1794 
1796  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1797 
1798 SaveBookmark::SaveBookmark(
1799  const IMark& rBkmk,
1800  const SwNodeIndex & rMvPos,
1801  const SwIndex* pIdx)
1802  : m_aName(rBkmk.GetName())
1803  , m_bHidden(false)
1804  , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1805 {
1806  const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1807  if(pBookmark)
1808  {
1809  m_aShortName = pBookmark->GetShortName();
1810  m_aCode = pBookmark->GetKeyCode();
1811  m_bHidden = pBookmark->IsHidden();
1812  m_aHideCondition = pBookmark->GetHideCondition();
1813 
1814  ::sfx2::Metadatable const*const pMetadatable(
1815  dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1816  if (pMetadatable)
1817  {
1818  m_pMetadataUndo = pMetadatable->CreateUndo();
1819  }
1820  }
1821  m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1823 
1824  m_nNode1 -= rMvPos.GetIndex();
1825  if(pIdx && !m_nNode1)
1826  m_nContent1 -= pIdx->GetIndex();
1827 
1828  if(rBkmk.IsExpanded())
1829  {
1830  m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1832 
1833  m_nNode2 -= rMvPos.GetIndex();
1834  if(pIdx && !m_nNode2)
1835  m_nContent2 -= pIdx->GetIndex();
1836  }
1837  else
1838  {
1840  m_nContent2 = -1;
1841  }
1842 }
1843 
1845  SwDoc* pDoc,
1846  const SwNodeIndex& rNewPos,
1847  const SwIndex* pIdx)
1848 {
1849  SwPaM aPam(rNewPos.GetNode());
1850  if(pIdx)
1851  aPam.GetPoint()->nContent = *pIdx;
1852 
1853  if(NODE_OFFSET_MAX != m_nNode2)
1854  {
1855  aPam.SetMark();
1856 
1857  aPam.GetMark()->nNode += m_nNode2;
1858  if(pIdx && !m_nNode2)
1859  aPam.GetMark()->nContent += m_nContent2;
1860  else
1861  aPam.GetMark()->nContent.Assign(aPam.GetContentNode(false), m_nContent2);
1862  }
1863 
1864  aPam.GetPoint()->nNode += m_nNode1;
1865 
1866  if(pIdx && !m_nNode1)
1867  aPam.GetPoint()->nContent += m_nContent1;
1868  else
1869  aPam.GetPoint()->nContent.Assign(aPam.GetContentNode(), m_nContent1);
1870 
1871  if(aPam.HasMark()
1872  && !CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, true))
1873  return;
1874 
1875  ::sw::mark::IBookmark* const pBookmark = dynamic_cast<::sw::mark::IBookmark*>(
1876  pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName,
1878  if(!pBookmark)
1879  return;
1880 
1881  pBookmark->SetKeyCode(m_aCode);
1882  pBookmark->SetShortName(m_aShortName);
1883  pBookmark->Hide(m_bHidden);
1884  pBookmark->SetHideCondition(m_aHideCondition);
1885 
1886  if (m_pMetadataUndo)
1887  {
1888  ::sfx2::Metadatable * const pMeta(
1889  dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1890  assert(pMeta && "metadata undo, but not metadatable?");
1891  if (pMeta)
1892  {
1894  }
1895  }
1896 }
1897 
1898 // DelBookmarks
1899 
1901  const SwNodeIndex& rStt,
1902  const SwNodeIndex& rEnd,
1903  std::vector<SaveBookmark> * pSaveBkmk,
1904  const SwIndex* pSttIdx,
1905  const SwIndex* pEndIdx)
1906 {
1907  // illegal range ??
1908  if(rStt.GetIndex() > rEnd.GetIndex()
1909  || (rStt == rEnd && (!pSttIdx || !pEndIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1910  return;
1911  SwDoc& rDoc = rStt.GetNode().GetDoc();
1912 
1913  rDoc.getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1914 
1915  // Copy all Redlines which are in the move area into an array
1916  // which holds all position information as offset.
1917  // Assignment happens after moving.
1919  for(SwRangeRedline* pRedl : rTable)
1920  {
1921  // Is at position?
1922  SwPosition *const pRStt = pRedl->Start();
1923  SwPosition *const pREnd = pRedl->End();
1924 
1925  if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1926  {
1927  pRStt->nNode = rEnd;
1928  if( pEndIdx )
1929  pRStt->nContent = *pEndIdx;
1930  else
1931  {
1932  bool bStt = true;
1933  SwContentNode* pCNd = pRStt->nNode.GetNode().GetContentNode();
1934  if( !pCNd )
1935  pCNd = rDoc.GetNodes().GoNext( &pRStt->nNode );
1936  if (!pCNd)
1937  {
1938  bStt = false;
1939  pRStt->nNode = rStt;
1940  pCNd = SwNodes::GoPrevious( &pRStt->nNode );
1941  if( !pCNd )
1942  {
1943  pRStt->nNode = pREnd->nNode;
1944  pCNd = pRStt->nNode.GetNode().GetContentNode();
1945  }
1946  }
1947  pRStt->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1948  }
1949  }
1950  if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1951  {
1952  pREnd->nNode = rStt;
1953  if( pSttIdx )
1954  pREnd->nContent = *pSttIdx;
1955  else
1956  {
1957  bool bStt = false;
1958  SwContentNode* pCNd = pREnd->nNode.GetNode().GetContentNode();
1959  if( !pCNd )
1960  pCNd = SwNodes::GoPrevious( &pREnd->nNode );
1961  if( !pCNd )
1962  {
1963  bStt = true;
1964  pREnd->nNode = rEnd;
1965  pCNd = rDoc.GetNodes().GoNext( &pREnd->nNode );
1966  if( !pCNd )
1967  {
1968  pREnd->nNode = pRStt->nNode;
1969  pCNd = pREnd->nNode.GetNode().GetContentNode();
1970  }
1971  }
1972  pREnd->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1973  }
1974  }
1975  }
1976 }
1977 
1978 namespace sw {
1979 
1980 SwInsText MakeSwInsText(SwTextNode & rNode, sal_Int32 const nPos, sal_Int32 const nLen)
1981 {
1982  SwCursor cursor(SwPosition(rNode, nPos), nullptr);
1983  bool isInsideFieldmarkCommand(false);
1984  bool isInsideFieldmarkResult(false);
1985  while (auto const*const pMark = rNode.GetDoc().getIDocumentMarkAccess()->getFieldmarkFor(*cursor.GetPoint()))
1986  {
1987  if (sw::mark::FindFieldSep(*pMark) < *cursor.GetPoint())
1988  {
1989  isInsideFieldmarkResult = true;
1990  }
1991  else
1992  {
1993  isInsideFieldmarkCommand = true;
1994  }
1995  *cursor.GetPoint() = pMark->GetMarkStart();
1996  if (!cursor.Left(1))
1997  {
1998  break;
1999  }
2000  }
2001  return SwInsText(nPos, nLen, isInsideFieldmarkCommand, isInsideFieldmarkResult);
2002 }
2003 
2004 } // namespace sw
2005 
2006 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual sw::mark::IMark * getAnnotationMarkFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1623
virtual sal_Int32 Len() const
Definition: node.cxx:1237
virtual void ShowButton(SwEditWin *pEditWin)=0
static void SendLOKHideMessage(const SfxViewShell *pViewShell)
bool IsInMailMerge() const
Definition: doc.hxx:959
virtual const_iterator_t findFirstAnnotationStartsAfter(const SwPosition &rPos) const override
Finds the first mark that is starting after.
Definition: docbm.cxx:1635
virtual sal_Int32 getAllMarksCount() const override
returns the number of marks.
Definition: docbm.cxx:1353
virtual const OUString & GetName() const =0
Marks a position in the document model.
Definition: pam.hxx:36
void UpdateFramesForAddDeleteRedline(SwDoc &rDoc, SwPaM const &rPam)
void DelBookmarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx)
Definition: docbm.cxx:1900
sw::mark::FieldmarkWithDropDownButton * m_pLastActiveFieldmark
OUString m_aName
constexpr SwNodeOffset NODE_OFFSET_MAX(SAL_MAX_INT32)
virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition &rPos) const override
Finds the first mark that is starting after.
Definition: docbm.cxx:1373
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:38
SwNodeOffset m_nNode2
Definition: mvsave.hxx:66
wrapper iterator: wraps iterator of implementation while hiding MarkBase class; only IMark instances ...
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:277
virtual void SetModified()=0
Must be called manually at changes of format.
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:474
container_t m_vFieldmarks
const SwPosition * GetMark() const
Definition: pam.hxx:210
OUString getUniqueMarkName(const OUString &rName) const
Definition: docbm.cxx:1695
sal_Int64 n
Provides access to the marks of a document.
bool Left(sal_uInt16 nCnt)
Definition: swcrsr.hxx:172
Definition: doc.hxx:187
void SetInDoc(SwDoc *pDoc, const SwNodeIndex &, const SwIndex *pIdx=nullptr)
Definition: docbm.cxx:1844
virtual const SwPosition & GetMarkPos() const =0
constexpr OUStringLiteral ODF_FORMDATE
SwPosition FindFieldSep(IFieldmark const &rMark)
return position of the CH_TXT_ATR_FIELDSEP for rMark
virtual ::sw::mark::IFieldmark * getFieldmarkAfter(const SwPosition &rPos) const override
Definition: docbm.cxx:1596
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1317
SwNode & GetNode() const
Definition: ndindex.hxx:128
OUString newName(std::u16string_view aNewPrefix, const OUString &aOldPrefix, std::u16string_view old_Name)
SwEditWin & GetEditWin()
Definition: view.hxx:416
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:1347
void LOKUpdateActiveField(const SfxViewShell *pViewShell)
Definition: docbm.cxx:1530
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1792
Dialog to specify the properties of date form field.
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
virtual const_iterator_t getAnnotationMarksBegin() const override
Definition: docbm.cxx:1602
SfxViewShell * GetSfxViewShell() const
Definition: viewsh.hxx:446
virtual const_iterator_t findAnnotationBookmark(const OUString &rName) const override
Definition: docbm.cxx:1656
virtual const_iterator_t getFieldmarksBegin() const override
returns a STL-like random access iterator to the begin of the sequence of fieldmarks.
Definition: docbm.cxx:1365
SwNodeOffset m_nNode1
Definition: mvsave.hxx:65
virtual ::sw::mark::IFieldmark * getFieldmarkFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1398
Fieldmark with a drop down button (e.g. this button opens the date picker for a date field) ...
virtual sw::mark::IFieldmark * makeNoTextFieldBookmark(const SwPaM &rPaM, const OUString &rName, const OUString &rType) override
Definition: docbm.cxx:752
virtual bool IsExpanded() const override
SwDoc & m_rDoc
Definition: docbm.cxx:1201
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:1359
virtual const OUString & GetHideCondition() const =0
virtual const OUString & GetName() const override
virtual void clearAllMarks() override
Clear (deletes) all marks.
Definition: docbm.cxx:1324
static SW_DLLPUBLIC OUString GetCrossRefHeadingBookmarkNamePrefix()
Definition: docbm.cxx:508
static SW_DLLPUBLIC bool IsLegalPaMForCrossRefHeadingBookmark(const SwPaM &rPaM)
Definition: docbm.cxx:513
bool operator==(iterator const &rOther) const
Definition: docbm.cxx:108
SwIndex nContent
Definition: pam.hxx:39
container_t m_vBookmarks
virtual ::sw::mark::IFieldmark * getFieldmarkAt(const SwPosition &rPos) const override
get Fieldmark for CH_TXT_ATR_FIELDSTART/CH_TXT_ATR_FIELDEND at rPos
Definition: docbm.cxx:1382
virtual ::sw::mark::IFieldmark * getFieldmarkFor(const SwPosition &pos) const =0
sal_Int32 m_nContent1
Definition: mvsave.hxx:67
virtual ::sw::mark::IMark * makeMark(const SwPaM &rPaM, const OUString &rProposedName, MarkType eMark,::sw::mark::InsertMode eMode, SwPosition const *pSepPos=nullptr)=0
Generates a new mark in the document for a certain selection.
iterator & operator-=(difference_type)
Definition: docbm.cxx:147
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
bool IsStartNode() const
Definition: node.hxx:636
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: docbm.cxx:1752
bool CheckNodesRange(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, bool bChkSection)
Check if the given range is inside one of the defined top-level sections.
Definition: pam.cxx:258
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:161
virtual OUString GetName() const override
virtual void DeregisterFromDoc(SwDoc &rDoc)
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:801
bool operator!=(iterator const &rOther) const
Definition: docbm.cxx:113
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:1065
virtual bool DoesUndo() const =0
Is Undo enabled?
virtual void SetKeyCode(const vcl::KeyCode &)=0
const char * sName
virtual void SetShortName(const OUString &)=0
bool ContainsPosition(const SwPosition &rPos) const
Definition: pam.hxx:258
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
virtual void Hide(bool hide)=0
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
sal_uInt16 char * pName
virtual sal_Int32 getAnnotationMarksCount() const override
Definition: docbm.cxx:1612
virtual ::sw::mark::IMark * makeMark(const SwPaM &rPaM, const OUString &rName, IDocumentMarkAccess::MarkType eMark, sw::mark::InsertMode eMode, SwPosition const *pSepPos=nullptr) override
Definition: docbm.cxx:540
container_t m_vAnnotationMarks
#define SAL_MAX_INT32
OUString m_aShortName
Definition: mvsave.hxx:60
std::optional< std::vector<::sw::mark::MarkBase * >::const_iterator > m_pIter
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.
virtual ::sw::mark::IMark * makeAnnotationBookmark(const SwPaM &rPaM, const OUString &rName, IDocumentMarkAccess::MarkType eMark, sw::mark::InsertMode eMode, SwPosition const *pSepPos=nullptr) override
Definition: docbm.cxx:1645
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:133
SwDoc & GetDoc()
Definition: node.hxx:213
virtual const_iterator_t getFieldmarksEnd() const override
returns a STL-like random access iterator to the end of the sequence of fieldmarks.
Definition: docbm.cxx:1368
virtual const_iterator_t getAnnotationMarksEnd() const override
Definition: docbm.cxx:1607
const SwPosition * GetPoint() const
Definition: pam.hxx:208
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:206
std::vector< sw::mark::MarkBase * > container_t
virtual void assureSortedMarkContainers() const override
Definition: docbm.cxx:1734
MarkBasenameMapUniqueOffset_t m_aMarkBasenameMapUniqueOffset
SwContentNode * GetContentNode()
Definition: node.hxx:627
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:206
virtual const_iterator_t findMark(const OUString &rName) const override
Finds a mark by name.
Definition: docbm.cxx:1335
virtual const OUString & GetShortName() const =0
virtual auto InvalidateFrames() -> void
virtual bool renameMark(::sw::mark::IMark *io_pMark, const OUString &rNewName) override
Renames an existing Mark, if possible.
Definition: docbm.cxx:849
iterator operator-(difference_type) const
Definition: docbm.cxx:153
iterator operator+(difference_type) const
Definition: docbm.cxx:142
Marks a character position inside a document model node.
Definition: index.hxx:33
float u
virtual bool IsCoveringPosition(const SwPosition &rPos) const =0
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
std::shared_ptr< MetadatableUndo > CreateUndo() const
std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndo
Definition: mvsave.hxx:69
Marks a node in the document model.
Definition: ndindex.hxx:30
virtual const vcl::KeyCode & GetKeyCode() const =0
std::unique_ptr< Fieldmark > m_pFieldmark
Definition: docbm.cxx:1200
virtual void SetHideCondition(const OUString &)=0
iterator & operator=(iterator const &rOther)
Definition: docbm.cxx:72
constexpr OUStringLiteral S_ANNOTATION_BOOKMARK
Definition: docbm.cxx:52
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:1350
virtual const_iterator_t findAnnotationMark(const OUString &rName) const override
Definition: docbm.cxx:1617
const SwPosition * Start() const
Definition: pam.hxx:213
void SetMark(const sw::mark::IMark *pMark)
Definition: index.cxx:222
static bool isDeleteMark(::sw::mark::MarkBase const *const pMark, SwNodeIndex const &rStt, SwNodeIndex const &rEnd, SwIndex const *const pSttIdx, SwIndex const *const pEndIdx, bool &rbIsPosInRange, bool &rbIsOtherPosInRange)
Definition: docbm.cxx:973
virtual sw::mark::IMark * makeAnnotationMark(const SwPaM &rPaM, const OUString &rName) override
Definition: docbm.cxx:814
virtual std::unique_ptr< ILazyDeleter > deleteMark(const const_iterator_t &ppMark, bool isMoveNodes) override
Deletes a mark.
Definition: docbm.cxx:1224
virtual SwPosition & GetOtherMarkPos() const override
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:195
virtual sal_Int32 getBookmarksCount() const override
returns the number of IBookmarks.
Definition: docbm.cxx:1362
virtual bool isBookmarkDeleted(SwPaM const &rPaM) const override
check if the selection would delete a BOOKMARK
Definition: docbm.cxx:1043
bool operator<=(iterator const &rOther) const
Definition: docbm.cxx:176
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:878
virtual void NotifyCursorUpdate(const SwCursorShell &rCursorShell) override
Definition: docbm.cxx:1480
const SwNodes & GetNodes() const
Definition: ndindex.hxx:165
virtual sw::mark::IFieldmark * makeFieldBookmark(const SwPaM &rPaM, const OUString &rName, const OUString &rType, SwPosition const *pSepPos=nullptr) override
Definition: docbm.cxx:712
#define SAL_INFO(area, stream)
sal_Int32 GetIndex() const
Definition: index.hxx:91
OString DateTimeToOString(const DateTime &rDateTime)
virtual SwPosition & GetMarkPos() const override
SwNodes & GetNodes()
Definition: doc.hxx:408
bool operator>(iterator const &rOther) const
Definition: docbm.cxx:172
virtual const_iterator_t findBookmark(const OUString &rName) const override
Finds a bookmark by name.
Definition: docbm.cxx:1341
const SwPosition * End() const
Definition: pam.hxx:218
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:924
SwDoc & GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:180
bool const m_isMoveNodes
Definition: docbm.cxx:1202
IDocumentMarkAccess::MarkType m_eOrigBkmType
Definition: mvsave.hxx:64
virtual void SetMarkPos(const SwPosition &rNewPos)
void * p
virtual void restoreAnnotationMarks(bool bDelete=true) override
Definition: docbm.cxx:1664
iterator & operator+=(difference_type)
Definition: docbm.cxx:136
virtual ::sw::mark::IFieldmark * getFieldmarkBefore(const SwPosition &rPos) const override
Definition: docbm.cxx:1599
virtual ::sw::mark::IFieldmark * getDropDownFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1563
virtual const SwPosition & GetMarkEnd() const =0
static void DeleteFieldmarkCommand(::sw::mark::IFieldmark const &rMark)
Definition: docbm.cxx:522
virtual void deleteFieldmarkAt(const SwPosition &rPos) override
Definition: docbm.cxx:1420
virtual void SetEnableSetModified(bool bEnableSetModified)=0
virtual OUString GetFieldname() const =0
virtual ::sw::mark::IFieldmark * changeFormFieldmarkType(::sw::mark::IFieldmark *pFieldmark, const OUString &rNewType) override
Definition: docbm.cxx:1428
#define SAL_WARN(area, stream)
virtual void ClearFieldActivation() override
Definition: docbm.cxx:1522
vcl::KeyCode m_aCode
Definition: mvsave.hxx:63
constexpr OUStringLiteral ODF_FORMCHECKBOX
struct _xmlTextWriter * xmlTextWriterPtr
virtual const SwPosition & GetMarkStart() const =0
::sw::mark::IMark * operator*() const
Definition: docbm.cxx:91
sal_Int32 m_nContent2
Definition: mvsave.hxx:68
InsertMode
Definition: IMark.hxx:31
virtual void SetOtherMarkPos(const SwPosition &rNewPos)
virtual std::vector<::sw::mark::IFieldmark * > getNoTextFieldmarksIn(const SwPaM &rPaM) const override
Definition: docbm.cxx:1571
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:1356
bool IsFieldmarkOverlap(SwPaM const &rPaM)
check if rPaM is valid range of new fieldmark
bool operator<(iterator const &rOther) const
Definition: docbm.cxx:168
bool operator>=(iterator const &rOther) const
Definition: docbm.cxx:180
virtual bool IsExpanded() const =0
std::vector<::sw::mark::MarkBase * >::const_iterator const & get() const
Definition: docbm.cxx:57
bool IsTextNode() const
Definition: node.hxx:648
constexpr OUStringLiteral ODF_FORMDROPDOWN
value_type operator[](difference_type) const
Definition: docbm.cxx:163
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:822
SwInsText MakeSwInsText(SwTextNode &rNode, sal_Int32 const nPos, sal_Int32 const nLen)
Definition: docbm.cxx:1980
void RestoreMetadata(std::shared_ptr< MetadatableUndo > const &i_pUndo)
Fieldmark representing a drop-down form field.
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1300
virtual bool IsHidden() const =0
OUString m_aHideCondition
Definition: mvsave.hxx:62
virtual OUString GetFieldname() const override
Definition: view.hxx:144
sal_uInt16 nPos
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
virtual const SwPosition & GetOtherMarkPos() const =0
bool m_bDetectedRangeSegmentation false
Base class of the Writer document model elements.
Definition: node.hxx:81
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo