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