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 <bookmrk.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 
51 using namespace ::sw::mark;
52 
53 std::vector<::sw::mark::MarkBase*>::const_iterator const&
55 {
56  return *m_pIter;
57 }
58 
59 IDocumentMarkAccess::iterator::iterator(std::vector<::sw::mark::MarkBase*>::const_iterator const& rIter)
60  : m_pIter(new std::vector<::sw::mark::MarkBase*>::const_iterator(rIter))
61 {
62 }
63 
65  : m_pIter(new std::vector<::sw::mark::MarkBase*>::const_iterator(*rOther.m_pIter))
66 {
67 }
68 
70 {
71  m_pIter.reset(new std::vector<::sw::mark::MarkBase*>::const_iterator(*rOther.m_pIter));
72  return *this;
73 }
74 
76  : m_pIter(std::move(rOther.m_pIter))
77 {
78 }
79 
81 {
82  m_pIter = std::move(rOther.m_pIter);
83  return *this;
84 }
85 
87 {
88 }
89 
90 // ARGH why does it *need* to return const& ?
91 ::sw::mark::IMark* /*const&*/
93 {
94  return static_cast<sw::mark::IMark*>(**m_pIter);
95 }
96 
98 {
99  ++(*m_pIter);
100  return *this;
101 }
103 {
104  iterator tmp(*this);
105  ++(*m_pIter);
106  return tmp;
107 }
108 
110 {
111  return *m_pIter == *rOther.m_pIter;
112 }
113 
115 {
116  return *m_pIter != *rOther.m_pIter;
117 }
118 
120  : m_pIter(new std::vector<::sw::mark::MarkBase*>::const_iterator())
121 {
122 }
123 
125 {
126  --(*m_pIter);
127  return *this;
128 }
129 
131 {
132  iterator tmp(*this);
133  --(*m_pIter);
134  return tmp;
135 }
136 
138 {
139  (*m_pIter) += n;
140  return *this;
141 }
142 
144 {
145  return iterator(*m_pIter + n);
146 }
147 
149 {
150  (*m_pIter) -= n;
151  return *this;
152 }
153 
155 {
156  return iterator(*m_pIter - n);
157 }
158 
160 {
161  return *m_pIter - *rOther.m_pIter;
162 }
163 
165 {
166  return static_cast<sw::mark::IMark*>((*m_pIter)[n]);
167 }
168 
170 {
171  return *m_pIter < *rOther.m_pIter;
172 }
174 {
175  return *m_pIter > *rOther.m_pIter;
176 }
178 {
179  return *m_pIter <= *rOther.m_pIter;
180 }
182 {
183  return *m_pIter >= *rOther.m_pIter;
184 }
185 
186 
187 namespace
188 {
189  bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
190  {
191  return pIdx != nullptr
192  ? ( rPos.nNode > rNdIdx
193  || ( rPos.nNode == rNdIdx
194  && rPos.nContent >= pIdx->GetIndex() ) )
195  : rPos.nNode >= rNdIdx;
196  }
197 
198  bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
199  {
200  return rPos.nNode < rNdIdx
201  || ( pIdx != nullptr
202  && rPos.nNode == rNdIdx
203  && rPos.nContent < pIdx->GetIndex() );
204  }
205 
206  bool lcl_MarkOrderingByStart(const ::sw::mark::MarkBase *const pFirst,
207  const ::sw::mark::MarkBase *const pSecond)
208  {
209  auto const& rFirstStart(pFirst->GetMarkStart());
210  auto const& rSecondStart(pSecond->GetMarkStart());
211  if (rFirstStart.nNode != rSecondStart.nNode)
212  {
213  return rFirstStart.nNode < rSecondStart.nNode;
214  }
215  const sal_Int32 nFirstContent = rFirstStart.nContent.GetIndex();
216  const sal_Int32 nSecondContent = rSecondStart.nContent.GetIndex();
217  if (nFirstContent != 0 || nSecondContent != 0)
218  {
219  return nFirstContent < nSecondContent;
220  }
221  auto *const pCRFirst (dynamic_cast<::sw::mark::CrossRefBookmark const*>(pFirst));
222  auto *const pCRSecond(dynamic_cast<::sw::mark::CrossRefBookmark const*>(pSecond));
223  if ((pCRFirst == nullptr) == (pCRSecond == nullptr))
224  {
225  return false; // equal
226  }
227  return pCRFirst != nullptr; // cross-ref sorts *before*
228  }
229 
230  bool lcl_MarkOrderingByEnd(const ::sw::mark::MarkBase *const pFirst,
231  const ::sw::mark::MarkBase *const pSecond)
232  {
233  return pFirst->GetMarkEnd() < pSecond->GetMarkEnd();
234  }
235 
236  void lcl_InsertMarkSorted(MarkManager::container_t& io_vMarks,
237  ::sw::mark::MarkBase *const pMark)
238  {
239  io_vMarks.insert(
240  lower_bound(
241  io_vMarks.begin(),
242  io_vMarks.end(),
243  pMark,
244  &lcl_MarkOrderingByStart),
245  pMark);
246  }
247 
248  std::unique_ptr<SwPosition> lcl_PositionFromContentNode(
249  SwContentNode * const pContentNode,
250  const bool bAtEnd)
251  {
252  std::unique_ptr<SwPosition> pResult(new SwPosition(*pContentNode));
253  pResult->nContent.Assign(pContentNode, bAtEnd ? pContentNode->Len() : 0);
254  return pResult;
255  }
256 
257  // return a position at the begin of rEnd, if it is a ContentNode
258  // else set it to the begin of the Node after rEnd, if there is one
259  // else set it to the end of the node before rStt
260  // else set it to the ContentNode of the Pos outside the Range
261  std::unique_ptr<SwPosition> lcl_FindExpelPosition(
262  const SwNodeIndex& rStt,
263  const SwNodeIndex& rEnd,
264  const SwPosition& rOtherPosition)
265  {
266  SwContentNode * pNode = rEnd.GetNode().GetContentNode();
267  bool bPosAtEndOfNode = false;
268  if ( pNode == nullptr)
269  {
270  SwNodeIndex aEnd = rEnd;
271  pNode = rEnd.GetNodes().GoNext( &aEnd );
272  bPosAtEndOfNode = false;
273  }
274  if ( pNode == nullptr )
275  {
276  SwNodeIndex aStt = rStt;
277  pNode = SwNodes::GoPrevious(&aStt);
278  bPosAtEndOfNode = true;
279  }
280  if ( pNode != nullptr )
281  {
282  return lcl_PositionFromContentNode( pNode, bPosAtEndOfNode );
283  }
284 
285  return std::make_unique<SwPosition>(rOtherPosition);
286  }
287 
288  struct CompareIMarkStartsBefore
289  {
290  bool operator()(SwPosition const& rPos,
291  const sw::mark::IMark* pMark)
292  {
293  return rPos < pMark->GetMarkStart();
294  }
295  bool operator()(const sw::mark::IMark* pMark,
296  SwPosition const& rPos)
297  {
298  return pMark->GetMarkStart() < rPos;
299  }
300  };
301 
302  // Apple llvm-g++ 4.2.1 with _GLIBCXX_DEBUG won't eat boost::bind for this
303  // Neither will MSVC 2008 with _DEBUG
304  struct CompareIMarkStartsAfter
305  {
306  bool operator()(SwPosition const& rPos,
307  const sw::mark::IMark* pMark)
308  {
309  return pMark->GetMarkStart() > rPos;
310  }
311  };
312 
313 
314  IMark* lcl_getMarkAfter(const MarkManager::container_t& rMarks, const SwPosition& rPos)
315  {
316  auto const pMarkAfter = upper_bound(
317  rMarks.begin(),
318  rMarks.end(),
319  rPos,
320  CompareIMarkStartsAfter());
321  if(pMarkAfter == rMarks.end())
322  return nullptr;
323  return *pMarkAfter;
324  };
325 
326  IMark* lcl_getMarkBefore(const MarkManager::container_t& rMarks, const SwPosition& rPos)
327  {
328  // candidates from which to choose the mark before
329  MarkManager::container_t vCandidates;
330  // no need to consider marks starting after rPos
331  auto const pCandidatesEnd = upper_bound(
332  rMarks.begin(),
333  rMarks.end(),
334  rPos,
335  CompareIMarkStartsAfter());
336  vCandidates.reserve(pCandidatesEnd - rMarks.begin());
337  // only marks ending before are candidates
338  remove_copy_if(
339  rMarks.begin(),
340  pCandidatesEnd,
341  back_inserter(vCandidates),
342  [&rPos] (const ::sw::mark::MarkBase *const pMark) { return !(pMark->GetMarkEnd() < rPos); } );
343  // no candidate left => we are in front of the first mark or there are none
344  if(vCandidates.empty()) return nullptr;
345  // return the highest (last) candidate using mark end ordering
346  return *max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd);
347  }
348 
349  bool lcl_FixCorrectedMark(
350  const bool bChangedPos,
351  const bool bChangedOPos,
352  MarkBase* io_pMark )
353  {
355  {
356  // annotation marks are allowed to span a table cell range.
357  // but trigger sorting to be save
358  return true;
359  }
360 
361  if ( ( bChangedPos || bChangedOPos )
362  && io_pMark->IsExpanded()
363  && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() !=
364  io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() )
365  {
366  if ( !bChangedOPos )
367  {
368  io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() );
369  }
370  io_pMark->ClearOtherMarkPos();
371  DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark);
372  if ( pDdeBkmk != nullptr
373  && pDdeBkmk->IsServer() )
374  {
375  pDdeBkmk->SetRefObject(nullptr);
376  }
377  return true;
378  }
379  return false;
380  }
381 
382  bool lcl_MarkEqualByStart(const ::sw::mark::MarkBase *const pFirst,
383  const ::sw::mark::MarkBase *const pSecond)
384  {
385  return !lcl_MarkOrderingByStart(pFirst, pSecond) &&
386  !lcl_MarkOrderingByStart(pSecond, pFirst);
387  }
388 
389  MarkManager::container_t::const_iterator lcl_FindMark(
390  MarkManager::container_t& rMarks,
391  const ::sw::mark::MarkBase *const pMarkToFind)
392  {
393  auto ppCurrentMark = lower_bound(
394  rMarks.begin(), rMarks.end(),
395  pMarkToFind, &lcl_MarkOrderingByStart);
396  // since there are usually not too many marks on the same start
397  // position, we are not doing a bisect search for the upper bound
398  // but instead start to iterate from pMarkLow directly
399  while (ppCurrentMark != rMarks.end() && lcl_MarkEqualByStart(*ppCurrentMark, pMarkToFind))
400  {
401  if(*ppCurrentMark == pMarkToFind)
402  {
403  return MarkManager::container_t::const_iterator(std::move(ppCurrentMark));
404  }
405  ++ppCurrentMark;
406  }
407  // reached a mark starting on a later start pos or the end of the
408  // vector => not found
409  return rMarks.end();
410  };
411 
412  MarkManager::container_t::const_iterator lcl_FindMarkAtPos(
413  MarkManager::container_t& rMarks,
414  const SwPosition& rPos,
415  const IDocumentMarkAccess::MarkType eType)
416  {
417  for (auto ppCurrentMark = lower_bound(
418  rMarks.begin(), rMarks.end(),
419  rPos,
420  CompareIMarkStartsBefore());
421  ppCurrentMark != rMarks.end();
422  ++ppCurrentMark)
423  {
424  // Once we reach a mark starting after the target pos
425  // we do not need to continue
426  if((*ppCurrentMark)->GetMarkStart() > rPos)
427  break;
428  if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType)
429  {
430  return MarkManager::container_t::const_iterator(std::move(ppCurrentMark));
431  }
432  }
433  // reached a mark starting on a later start pos or the end of the
434  // vector => not found
435  return rMarks.end();
436  };
437 
438  MarkManager::container_t::const_iterator lcl_FindMarkByName(
439  const OUString& rName,
440  const MarkManager::container_t::const_iterator& ppMarksBegin,
441  const MarkManager::container_t::const_iterator& ppMarksEnd)
442  {
443  return find_if(
444  ppMarksBegin,
445  ppMarksEnd,
446  [&rName] (::sw::mark::MarkBase const*const pMark) { return pMark->GetName() == rName; } );
447  }
448 
449  void lcl_DebugMarks(MarkManager::container_t const& rMarks)
450  {
451 #if OSL_DEBUG_LEVEL > 0
452  SAL_INFO("sw.core", rMarks.size() << " Marks");
453  for (auto ppMark = rMarks.begin();
454  ppMark != rMarks.end();
455  ++ppMark)
456  {
457  IMark* pMark = *ppMark;
458  const SwPosition* const pStPos = &pMark->GetMarkStart();
459  const SwPosition* const pEndPos = &pMark->GetMarkEnd();
460  SAL_INFO("sw.core",
461  pStPos->nNode.GetIndex() << "," <<
462  pStPos->nContent.GetIndex() << " " <<
463  pEndPos->nNode.GetIndex() << "," <<
464  pEndPos->nContent.GetIndex() << " " <<
465  typeid(*pMark).name() << " " <<
466  pMark->GetName());
467  }
468 #else
469  (void) rMarks;
470 #endif
471  assert(std::is_sorted(rMarks.begin(), rMarks.end(), lcl_MarkOrderingByStart));
472  };
473 }
474 
476 {
477  const std::type_info* const pMarkTypeInfo = &typeid(rBkmk);
478  // not using dynamic_cast<> here for performance
479  if(*pMarkTypeInfo == typeid(UnoMark))
480  return MarkType::UNO_BOOKMARK;
481  else if(*pMarkTypeInfo == typeid(DdeBookmark))
482  return MarkType::DDE_BOOKMARK;
483  else if(*pMarkTypeInfo == typeid(Bookmark))
484  return MarkType::BOOKMARK;
485  else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark))
487  else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark))
489  else if(*pMarkTypeInfo == typeid(AnnotationMark))
491  else if(*pMarkTypeInfo == typeid(TextFieldmark))
493  else if(*pMarkTypeInfo == typeid(CheckboxFieldmark))
495  else if(*pMarkTypeInfo == typeid(DropDownFieldmark))
497  else if(*pMarkTypeInfo == typeid(DateFieldmark))
499  else if(*pMarkTypeInfo == typeid(NavigatorReminder))
501  else
502  {
503  assert(false && "IDocumentMarkAccess::GetType(..)"
504  " - unknown MarkType. This needs to be fixed!");
505  return MarkType::UNO_BOOKMARK;
506  }
507 }
508 
510 {
511  return "__RefHeading__";
512 }
513 
515 {
516  return rPaM.Start()->nNode.GetNode().IsTextNode() &&
517  rPaM.Start()->nContent.GetIndex() == 0 &&
518  ( !rPaM.HasMark() ||
519  ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode &&
520  rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTextNode()->Len() ) );
521 }
522 
524 {
525  if (GetType(rMark) != MarkType::TEXT_FIELDMARK)
526  {
527  return; // TODO FORMDATE has no command?
528  }
529  SwPaM pam(sw::mark::FindFieldSep(rMark), rMark.GetMarkStart());
530  ++pam.GetPoint()->nContent; // skip CH_TXT_ATR_FIELDSTART
531  pam.GetDoc().getIDocumentContentOperations().DeleteAndJoin(pam);
532 }
533 
534 namespace sw::mark
535 {
536  MarkManager::MarkManager(SwDoc& rDoc)
537  : m_vAllMarks()
538  , m_vBookmarks()
539  , m_vFieldmarks()
540  , m_vAnnotationMarks()
541  , m_rDoc(rDoc)
542  , m_pLastActiveFieldmark(nullptr)
543  { }
544 
546  const OUString& rName,
547  const IDocumentMarkAccess::MarkType eType,
548  sw::mark::InsertMode const eMode,
549  SwPosition const*const pSepPos)
550  {
551 #if OSL_DEBUG_LEVEL > 0
552  {
553  const SwPosition* const pPos1 = rPaM.GetPoint();
554  const SwPosition* pPos2 = pPos1;
555  if(rPaM.HasMark())
556  pPos2 = rPaM.GetMark();
557  SAL_INFO("sw.core",
558  rName << " " <<
559  pPos1->nNode.GetIndex() << "," <<
560  pPos1->nContent.GetIndex() << " " <<
561  pPos2->nNode.GetIndex() << "," <<
562  pPos2->nContent.GetIndex());
563  }
564 #endif
565  if ( (!rPaM.GetPoint()->nNode.GetNode().IsTextNode()
566  && (eType != MarkType::UNO_BOOKMARK
567  // SwXTextRange can be on table node or plain start node (FLY_AT_FLY)
568  || !rPaM.GetPoint()->nNode.GetNode().IsStartNode()))
569  || (!rPaM.GetMark()->nNode.GetNode().IsTextNode()
570  && (eType != MarkType::UNO_BOOKMARK
571  || !rPaM.GetMark()->nNode.GetNode().IsStartNode())))
572  {
573  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
574  " - refusing to create mark on non-textnode");
575  return nullptr;
576  }
577  // There should only be one CrossRefBookmark per Textnode per Type
579  && (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end()))
580  { // this can happen via UNO API
581  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
582  " - refusing to create duplicate CrossRefBookmark");
583  return nullptr;
584  }
585 
587  && (eMode == InsertMode::New
588  ? *rPaM.GetPoint() != *rPaM.GetMark()
589  // CopyText: pam covers CH_TXT_ATR_FORMELEMENT
590  : (rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode
591  || rPaM.Start()->nContent.GetIndex() + 1 != rPaM.End()->nContent.GetIndex())))
592  {
593  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
594  " - invalid range on point fieldmark");
595  return nullptr;
596  }
597 
598  if ((eType == MarkType::TEXT_FIELDMARK || eType == MarkType::DATE_FIELDMARK)
600  || (pSepPos && rPaM.GetPoint()->nNode.GetNode().StartOfSectionNode() != pSepPos->nNode.GetNode().StartOfSectionNode())))
601  {
602  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
603  " - invalid range on fieldmark, different nodes array sections");
604  return nullptr;
605  }
606 
607  if ((eType == MarkType::TEXT_FIELDMARK || eType == MarkType::DATE_FIELDMARK)
608  // can't check for Copy - it asserts - but it's also obviously unnecessary
609  && eMode == InsertMode::New
611  {
612  SAL_WARN("sw.core", "MarkManager::makeMark(..)"
613  " - invalid range on fieldmark, overlaps existing fieldmark or meta-field");
614  return nullptr;
615  }
616 
617  // create mark
618  std::unique_ptr<::sw::mark::MarkBase> pMark;
619  switch(eType)
620  {
622  pMark = std::make_unique<TextFieldmark>(rPaM, rName);
623  break;
625  pMark = std::make_unique<CheckboxFieldmark>(rPaM);
626  break;
628  pMark = std::make_unique<DropDownFieldmark>(rPaM);
629  break;
631  pMark = std::make_unique<DateFieldmark>(rPaM);
632  break;
634  pMark = std::make_unique<NavigatorReminder>(rPaM);
635  break;
637  pMark = std::make_unique<Bookmark>(rPaM, vcl::KeyCode(), rName);
638  break;
640  pMark = std::make_unique<DdeBookmark>(rPaM);
641  break;
643  pMark = std::make_unique<CrossRefHeadingBookmark>(rPaM, vcl::KeyCode(), rName);
644  break;
646  pMark = std::make_unique<CrossRefNumItemBookmark>(rPaM, vcl::KeyCode(), rName);
647  break;
649  pMark = std::make_unique<UnoMark>(rPaM);
650  break;
652  pMark = std::make_unique<AnnotationMark>( rPaM, rName );
653  break;
654  }
655  assert(pMark && "MarkManager::makeMark(..) - Mark was not created.");
656 
657  if(pMark->GetMarkPos() != pMark->GetMarkStart())
658  pMark->Swap();
659 
660  // for performance reasons, we trust UnoMarks to have a (generated) unique name
662  pMark->SetName( getUniqueMarkName( pMark->GetName() ) );
663 
664  // insert any dummy chars before inserting into sorted vectors
665  pMark->InitDoc(m_rDoc, eMode, pSepPos);
666 
667  // register mark
668  lcl_InsertMarkSorted(m_vAllMarks, pMark.get());
669  switch(eType)
670  {
674  lcl_InsertMarkSorted(m_vBookmarks, pMark.get());
675  break;
680  lcl_InsertMarkSorted(m_vFieldmarks, pMark.get());
681  break;
683  lcl_InsertMarkSorted( m_vAnnotationMarks, pMark.get() );
684  break;
688  // no special array for these
689  break;
690  }
693  {
694  // due to SwInsText notifications everything is visible now - tell
695  // layout to hide as appropriate
696  // note: we don't know how many layouts there are and which
697  // parts they hide, so just notify the entire fieldmark, it
698  // should give the right result if not in the most efficient way
699  // note2: can't be done in InitDoc() because it requires the mark
700  // to be inserted in the vectors.
701  SwPaM const tmp(pMark->GetMarkPos(), pMark->GetOtherMarkPos());
703  }
704 
705  SAL_INFO("sw.core", "--- makeType ---");
706  SAL_INFO("sw.core", "Marks");
707  lcl_DebugMarks(m_vAllMarks);
708  SAL_INFO("sw.core", "Bookmarks");
709  lcl_DebugMarks(m_vBookmarks);
710  SAL_INFO("sw.core", "Fieldmarks");
711  lcl_DebugMarks(m_vFieldmarks);
712 
713  return pMark.release();
714  }
715 
717  const SwPaM& rPaM,
718  const OUString& rName,
719  const OUString& rType,
720  SwPosition const*const pSepPos)
721  {
722 
723  // Disable undo, because we handle it using SwUndoInsTextFieldmark
724  bool bUndoIsEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
726 
727  sw::mark::IMark* pMark = nullptr;
728  if(rType == ODF_FORMDATE)
729  {
730  pMark = makeMark(rPaM, rName,
733  pSepPos);
734  }
735  else
736  {
737  pMark = makeMark(rPaM, rName,
740  pSepPos);
741  }
742  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
743  if (pFieldMark)
744  pFieldMark->SetFieldname( rType );
745 
746  if (bUndoIsEnabled)
747  {
748  m_rDoc.GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
749  if (pFieldMark)
750  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsTextFieldmark>(*pFieldMark));
751  }
752 
753  return pFieldMark;
754  }
755 
757  const SwPaM& rPaM,
758  const OUString& rName,
759  const OUString& rType)
760  {
761  // Disable undo, because we handle it using SwUndoInsNoTextFieldmark
762  bool bUndoIsEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
764 
765  bool bEnableSetModified = m_rDoc.getIDocumentState().IsEnableSetModified();
767 
768  sw::mark::IMark* pMark = nullptr;
769  if(rType == ODF_FORMCHECKBOX)
770  {
771  pMark = makeMark( rPaM, rName,
774  }
775  else if(rType == ODF_FORMDROPDOWN)
776  {
777  pMark = makeMark( rPaM, rName,
780  }
781  else if(rType == ODF_FORMDATE)
782  {
783  pMark = makeMark( rPaM, rName,
786  }
787 
788  sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
789  if (pFieldMark)
790  pFieldMark->SetFieldname( rType );
791 
792  if (bUndoIsEnabled)
793  {
794  m_rDoc.GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled);
795  if (pFieldMark)
796  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsNoTextFieldmark>(*pFieldMark));
797  }
798 
799  m_rDoc.getIDocumentState().SetEnableSetModified(bEnableSetModified);
801 
802  return pFieldMark;
803  }
804 
806  const SwTextNode& rTextNode,
807  const IDocumentMarkAccess::MarkType eType )
808  {
809  SwPosition aPos(rTextNode);
810  aPos.nContent.Assign(&const_cast<SwTextNode&>(rTextNode), 0);
811  auto const ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType);
812  if(ppExistingMark != m_vBookmarks.end())
813  return *ppExistingMark;
814  const SwPaM aPaM(aPos);
815  return makeMark(aPaM, OUString(), eType, sw::mark::InsertMode::New);
816  }
817 
819  const SwPaM& rPaM,
820  const OUString& rName )
821  {
824  }
825 
827  ::sw::mark::IMark* const io_pMark,
828  const SwPaM& rPaM)
829  {
830  assert(&io_pMark->GetMarkPos().GetDoc() == &m_rDoc &&
831  "<MarkManager::repositionMark(..)>"
832  " - Mark is not in my doc.");
833  MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark);
834  if (!pMarkBase)
835  return;
836 
837  pMarkBase->InvalidateFrames();
838 
839  pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
840  if(rPaM.HasMark())
841  pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
842  else
843  pMarkBase->ClearOtherMarkPos();
844 
845  if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
846  pMarkBase->Swap();
847 
848  pMarkBase->InvalidateFrames();
849 
850  sortMarks();
851  }
852 
854  ::sw::mark::IMark* io_pMark,
855  const OUString& rNewName )
856  {
857  assert(&io_pMark->GetMarkPos().GetDoc() == &m_rDoc &&
858  "<MarkManager::renameMark(..)>"
859  " - Mark is not in my doc.");
860  if ( io_pMark->GetName() == rNewName )
861  return true;
862  if (lcl_FindMarkByName(rNewName, m_vAllMarks.begin(), m_vAllMarks.end()) != m_vAllMarks.end())
863  return false;
864  if (::sw::mark::MarkBase* pMarkBase = dynamic_cast< ::sw::mark::MarkBase* >(io_pMark))
865  {
866  const OUString sOldName(pMarkBase->GetName());
867  pMarkBase->SetName(rNewName);
868 
869  if (dynamic_cast< ::sw::mark::Bookmark* >(io_pMark))
870  {
872  {
874  std::make_unique<SwUndoRenameBookmark>(sOldName, rNewName, m_rDoc));
875  }
877  }
878  }
879  return true;
880  }
881 
883  const SwNodeIndex& rOldNode,
884  const SwPosition& rNewPos,
885  const sal_Int32 nOffset)
886  {
887  const SwNode* const pOldNode = &rOldNode.GetNode();
888  SwPosition aNewPos(rNewPos);
889  aNewPos.nContent += nOffset;
890  bool isSortingNeeded = false;
891 
892  for (auto ppMark = m_vAllMarks.begin();
893  ppMark != m_vAllMarks.end();
894  ++ppMark)
895  {
896  ::sw::mark::MarkBase *const pMark = *ppMark;
897  // correction of non-existent non-MarkBase instances cannot be done
898  assert(pMark);
899  // is on position ??
900  bool bChangedPos = false;
901  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
902  {
903  pMark->SetMarkPos(aNewPos);
904  bChangedPos = true;
905  isSortingNeeded = true;
906  }
907  bool bChangedOPos = false;
908  if (pMark->IsExpanded() &&
909  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
910  {
911  // shift the OtherMark to aNewPos
912  pMark->SetOtherMarkPos(aNewPos);
913  bChangedOPos= true;
914  isSortingNeeded = true;
915  }
916  // illegal selection? collapse the mark and restore sorting later
917  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
918  }
919 
920  // restore sorting if needed
921  if(isSortingNeeded)
922  sortMarks();
923 
924  SAL_INFO("sw.core", "correctMarksAbsolute");
925  lcl_DebugMarks(m_vAllMarks);
926  }
927 
928  void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const sal_Int32 nOffset)
929  {
930  const SwNode* const pOldNode = &rOldNode.GetNode();
931  SwPosition aNewPos(rNewPos);
932  aNewPos.nContent += nOffset;
933  bool isSortingNeeded = false;
934 
935  for (auto ppMark = m_vAllMarks.begin();
936  ppMark != m_vAllMarks.end();
937  ++ppMark)
938  {
939  // is on position ??
940  bool bChangedPos = false, bChangedOPos = false;
941  ::sw::mark::MarkBase* const pMark = *ppMark;
942  // correction of non-existent non-MarkBase instances cannot be done
943  assert(pMark);
944  if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
945  {
946  SwPosition aNewPosRel(aNewPos);
947  if (dynamic_cast< ::sw::mark::CrossRefBookmark *>(pMark))
948  {
949  // ensure that cross ref bookmark always starts at 0
950  aNewPosRel.nContent = 0; // HACK for WW8 import
951  isSortingNeeded = true; // and sort them to be safe...
952  }
953  aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex();
954  pMark->SetMarkPos(aNewPosRel);
955  bChangedPos = true;
956  }
957  if(pMark->IsExpanded() &&
958  &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
959  {
960  SwPosition aNewPosRel(aNewPos);
961  aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex();
962  pMark->SetOtherMarkPos(aNewPosRel);
963  bChangedOPos = true;
964  }
965  // illegal selection? collapse the mark and restore sorting later
966  isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
967  }
968 
969  // restore sorting if needed
970  if(isSortingNeeded)
971  sortMarks();
972 
973  SAL_INFO("sw.core", "correctMarksRelative");
974  lcl_DebugMarks(m_vAllMarks);
975  }
976 
977  static bool isDeleteMark(
978  ::sw::mark::MarkBase const*const pMark,
979  SwNodeIndex const& rStt,
980  SwNodeIndex const& rEnd,
981  SwIndex const*const pSttIdx,
982  SwIndex const*const pEndIdx,
983  bool & rbIsPosInRange,
984  bool & rbIsOtherPosInRange)
985  {
986  assert(pMark);
987  // navigator marks should not be moved
988  // TODO: Check if this might make them invalid
990  {
991  return false;
992  }
993 
994  // on position ??
995  rbIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
996  && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
997  rbIsOtherPosInRange = pMark->IsExpanded()
998  && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
999  && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
1000  // special case: completely in range, touching the end?
1001  if ( pEndIdx != nullptr
1002  && ( ( rbIsOtherPosInRange
1003  && pMark->GetMarkPos().nNode == rEnd
1004  && pMark->GetMarkPos().nContent == *pEndIdx )
1005  || ( rbIsPosInRange
1006  && pMark->IsExpanded()
1007  && pMark->GetOtherMarkPos().nNode == rEnd
1008  && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
1009  {
1010  rbIsPosInRange = true;
1011  rbIsOtherPosInRange = true;
1012  }
1013 
1014  if (rbIsPosInRange
1015  && (rbIsOtherPosInRange
1016  || !pMark->IsExpanded()))
1017  {
1018  // completely in range
1019 
1020  bool bDeleteMark = true;
1021  {
1022  switch ( IDocumentMarkAccess::GetType( *pMark ) )
1023  {
1026  // no delete of cross-reference bookmarks, if range is inside one paragraph
1027  bDeleteMark = rStt != rEnd;
1028  break;
1030  // no delete of UNO mark, if it is not expanded and only touches the start of the range
1031  bDeleteMark = rbIsOtherPosInRange
1032  || pMark->IsExpanded()
1033  || pSttIdx == nullptr
1034  || pMark->GetMarkPos().nNode != rStt
1035  || pMark->GetMarkPos().nContent != *pSttIdx;
1036  break;
1037  default:
1038  bDeleteMark = true;
1039  break;
1040  }
1041  }
1042  return bDeleteMark;
1043  }
1044  return false;
1045  }
1046 
1047  bool MarkManager::isBookmarkDeleted(SwPaM const& rPaM) const
1048  {
1049  SwPosition const& rStart(*rPaM.Start());
1050  SwPosition const& rEnd(*rPaM.End());
1051  for (auto ppMark = m_vBookmarks.begin();
1052  ppMark != m_vBookmarks.end();
1053  ++ppMark)
1054  {
1055  bool bIsPosInRange(false);
1056  bool bIsOtherPosInRange(false);
1057  bool const bDeleteMark = isDeleteMark(*ppMark,
1058  rStart.nNode, rEnd.nNode, &rStart.nContent, &rEnd.nContent,
1059  bIsPosInRange, bIsOtherPosInRange);
1060  if (bDeleteMark
1062  {
1063  return true;
1064  }
1065  }
1066  return false;
1067  }
1068 
1070  const SwNodeIndex& rStt,
1071  const SwNodeIndex& rEnd,
1072  std::vector<SaveBookmark>* pSaveBkmk,
1073  const SwIndex* pSttIdx,
1074  const SwIndex* pEndIdx )
1075  {
1076  std::vector<const_iterator_t> vMarksToDelete;
1077  bool bIsSortingNeeded = false;
1078 
1079  // boolean indicating, if at least one mark has been moved while collecting marks for deletion
1080  bool bMarksMoved = false;
1081  // have marks in the range been skipped instead of deleted
1082  bool bMarksSkipDeletion = false;
1083 
1084  // copy all bookmarks in the move area to a vector storing all position data as offset
1085  // reassignment is performed after the move
1086  for (auto ppMark = m_vAllMarks.begin();
1087  ppMark != m_vAllMarks.end();
1088  ++ppMark)
1089  {
1090  ::sw::mark::MarkBase *const pMark = *ppMark;
1091  bool bIsPosInRange(false);
1092  bool bIsOtherPosInRange(false);
1093  bool const bDeleteMark = isDeleteMark(pMark, rStt, rEnd, pSttIdx, pEndIdx, bIsPosInRange, bIsOtherPosInRange);
1094 
1095  if ( bIsPosInRange
1096  && ( bIsOtherPosInRange
1097  || !pMark->IsExpanded() ) )
1098  {
1099  if ( bDeleteMark )
1100  {
1101  if ( pSaveBkmk )
1102  {
1103  pSaveBkmk->push_back( SaveBookmark( *pMark, rStt, pSttIdx ) );
1104  }
1105  vMarksToDelete.emplace_back(ppMark);
1106  }
1107  else
1108  {
1109  bMarksSkipDeletion = true;
1110  }
1111  }
1112  else if ( bIsPosInRange != bIsOtherPosInRange )
1113  {
1114  // the bookmark is partially in the range
1115  // move position of that is in the range out of it
1116 
1117  std::unique_ptr< SwPosition > pNewPos;
1118  {
1119  if ( pEndIdx != nullptr )
1120  {
1121  pNewPos = std::make_unique< SwPosition >( rEnd, *pEndIdx );
1122  }
1123  else
1124  {
1125  pNewPos =
1126  lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() );
1127  }
1128  }
1129 
1130  bool bMoveMark = true;
1131  {
1132  switch ( IDocumentMarkAccess::GetType( *pMark ) )
1133  {
1136  // no move of cross-reference bookmarks, if move occurs inside a certain node
1137  bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode;
1138  break;
1140  // no move of annotation marks, if method is called to collect deleted marks
1141  bMoveMark = pSaveBkmk == nullptr;
1142  break;
1143  default:
1144  bMoveMark = true;
1145  break;
1146  }
1147  }
1148  if ( bMoveMark )
1149  {
1150  if ( bIsPosInRange )
1151  pMark->SetMarkPos(*pNewPos);
1152  else
1153  pMark->SetOtherMarkPos(*pNewPos);
1154  bMarksMoved = true;
1155 
1156  // illegal selection? collapse the mark and restore sorting later
1157  bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark );
1158  }
1159  }
1160  }
1161 
1162  {
1163  // fdo#61016 delay the deletion of the fieldmark characters
1164  // to prevent that from deleting the marks on that position
1165  // which would invalidate the iterators in vMarksToDelete
1166  std::vector< std::unique_ptr<ILazyDeleter> > vDelay;
1167  vDelay.reserve(vMarksToDelete.size());
1168 
1169  // If needed, sort mark containers containing subsets of the marks
1170  // in order to assure sorting. The sorting is critical for the
1171  // deletion of a mark as it is searched in these container for
1172  // deletion.
1173  if ( !vMarksToDelete.empty() && bMarksMoved )
1174  {
1175  sortSubsetMarks();
1176  }
1177  // we just remembered the iterators to delete, so we do not need to search
1178  // for the shared_ptr<> (the entry in m_vAllMarks) again
1179  // reverse iteration, since erasing an entry invalidates iterators
1180  // behind it (the iterators in vMarksToDelete are sorted)
1181  for ( std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin();
1182  pppMark != vMarksToDelete.rend();
1183  ++pppMark )
1184  {
1185  vDelay.push_back(deleteMark(*pppMark));
1186  }
1187  } // scope to kill vDelay
1188 
1189  // also need to sort if both marks were moved and not-deleted because
1190  // the not-deleted marks could be in wrong order vs. the moved ones
1191  if (bIsSortingNeeded || (bMarksMoved && bMarksSkipDeletion))
1192  {
1193  sortMarks();
1194  }
1195 
1196  SAL_INFO("sw.core", "deleteMarks");
1197  lcl_DebugMarks(m_vAllMarks);
1198  }
1199 
1200  namespace {
1201 
1202  struct LazyFieldmarkDeleter : public IDocumentMarkAccess::ILazyDeleter
1203  {
1204  std::unique_ptr<Fieldmark> m_pFieldmark;
1206  LazyFieldmarkDeleter(Fieldmark* pMark, SwDoc& rDoc)
1207  : m_pFieldmark(pMark), m_rDoc(rDoc)
1208  {
1209  assert(m_pFieldmark);
1210  }
1211  virtual ~LazyFieldmarkDeleter() override
1212  {
1213  // note: because of the call chain from SwUndoDelete, the field
1214  // command *cannot* be deleted here as it would create a separate
1215  // SwUndoDelete that's interleaved with the SwHistory of the outer
1216  // one - only delete the CH_TXT_ATR_FIELD*!
1217  m_pFieldmark->ReleaseDoc(m_rDoc);
1218  }
1219  };
1220 
1221  }
1222 
1223  std::unique_ptr<IDocumentMarkAccess::ILazyDeleter>
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));
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));
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  if (!pFieldmark)
1424  return;
1425 
1426  deleteMark(lcl_FindMark(m_vAllMarks, pFieldmark));
1427  }
1428 
1430  {
1431  bool bActualChange = false;
1432  if(rNewType == ODF_FORMDROPDOWN)
1433  {
1434  if (!dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark))
1435  bActualChange = true;
1436  if (!dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark)) // only allowed converting between checkbox <-> dropdown
1437  return nullptr;
1438  }
1439  else if(rNewType == ODF_FORMCHECKBOX)
1440  {
1441  if (!dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark))
1442  bActualChange = true;
1443  if (!dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark)) // only allowed converting between checkbox <-> dropdown
1444  return nullptr;
1445  }
1446  else if(rNewType == ODF_FORMDATE)
1447  {
1448  if (!dynamic_cast<::sw::mark::DateFieldmark*>(pFieldmark))
1449  bActualChange = true;
1450  if (!dynamic_cast<::sw::mark::TextFieldmark*>(pFieldmark)) // only allowed converting between date field <-> text field
1451  return nullptr;
1452  }
1453 
1454  if (!bActualChange)
1455  return nullptr;
1456 
1457  // Store attributes needed to create the new fieldmark
1458  OUString sName = pFieldmark->GetName();
1459  SwPaM aPaM(pFieldmark->GetMarkPos());
1460 
1461  // Remove the old fieldmark and create a new one with the new type
1462  if(aPaM.GetPoint()->nContent > 0 && (rNewType == ODF_FORMDROPDOWN || rNewType == ODF_FORMCHECKBOX))
1463  {
1464  --aPaM.GetPoint()->nContent;
1465  SwPosition aNewPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
1466  deleteFieldmarkAt(aNewPos);
1467  return makeNoTextFieldBookmark(aPaM, sName, rNewType);
1468  }
1469  else if(rNewType == ODF_FORMDATE)
1470  {
1471  SwPosition aPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent);
1472  SwPaM aNewPaM(pFieldmark->GetMarkStart(), pFieldmark->GetMarkEnd());
1473  deleteFieldmarkAt(aPos);
1474  // HACK: hard-code the separator position here at the start because
1475  // writerfilter put it in the wrong place (at the end) on attach()
1476  SwPosition const sepPos(*aNewPaM.Start());
1477  return makeFieldBookmark(aNewPaM, sName, rNewType, &sepPos);
1478  }
1479  return nullptr;
1480  }
1481 
1483  {
1484  SwView* pSwView = dynamic_cast<SwView *>(rCursorShell.GetSfxViewShell());
1485  if(!pSwView)
1486  return;
1487 
1488  SwEditWin& rEditWin = pSwView->GetEditWin();
1489  SwPosition aPos(*rCursorShell.GetCursor()->GetPoint());
1490  IFieldmark* pFieldBM = getFieldmarkFor(aPos);
1491  FieldmarkWithDropDownButton* pNewActiveFieldmark = nullptr;
1492  if ((!pFieldBM || (pFieldBM->GetFieldname() != ODF_FORMDROPDOWN && pFieldBM->GetFieldname() != ODF_FORMDATE))
1493  && aPos.nContent.GetIndex() > 0 )
1494  {
1495  --aPos.nContent;
1496  pFieldBM = getFieldmarkFor(aPos);
1497  }
1498 
1499  if ( pFieldBM && (pFieldBM->GetFieldname() == ODF_FORMDROPDOWN ||
1500  pFieldBM->GetFieldname() == ODF_FORMDATE))
1501  {
1502  if (m_pLastActiveFieldmark != pFieldBM)
1503  {
1504  FieldmarkWithDropDownButton& rFormField = dynamic_cast<FieldmarkWithDropDownButton&>(*pFieldBM);
1505  pNewActiveFieldmark = &rFormField;
1506  }
1507  else
1508  {
1509  pNewActiveFieldmark = m_pLastActiveFieldmark;
1510  }
1511  }
1512 
1513  if(pNewActiveFieldmark != m_pLastActiveFieldmark)
1514  {
1516  m_pLastActiveFieldmark = pNewActiveFieldmark;
1517  if(pNewActiveFieldmark)
1518  pNewActiveFieldmark->ShowButton(&rEditWin);
1519  }
1520  }
1521 
1523  {
1526 
1527  m_pLastActiveFieldmark = nullptr;
1528  }
1529 
1531  {
1532  IFieldmark *pMark = getFieldmarkAt(rPos);
1533  if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1534  return nullptr;
1535  return pMark;
1536  }
1537 
1538  std::vector<IFieldmark*> MarkManager::getDropDownsFor(const SwPaM &rPaM) const
1539  {
1540  std::vector<IFieldmark*> aRet;
1541 
1542  for (auto aI = m_vFieldmarks.begin(),
1543  aEnd = m_vFieldmarks.end(); aI != aEnd; ++aI)
1544  {
1545  ::sw::mark::IMark* pI = *aI;
1546  const SwPosition &rStart = pI->GetMarkPos();
1547  if (!rPaM.ContainsPosition(rStart))
1548  continue;
1549 
1550  IFieldmark *pMark = dynamic_cast<IFieldmark*>(pI);
1551  if (!pMark || pMark->GetFieldname() != ODF_FORMDROPDOWN)
1552  continue;
1553 
1554  aRet.push_back(pMark);
1555  }
1556 
1557  return aRet;
1558  }
1559 
1561  { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
1562 
1564  { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
1565 
1567  {
1568  return m_vAnnotationMarks.begin();
1569  }
1570 
1572  {
1573  return m_vAnnotationMarks.end();
1574  }
1575 
1577  {
1578  return m_vAnnotationMarks.size();
1579  }
1580 
1582  {
1583  auto const ret = lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1584  return IDocumentMarkAccess::iterator(ret);
1585  }
1586 
1588  {
1589  auto const pAnnotationMark = find_if(
1590  m_vAnnotationMarks.begin(),
1591  m_vAnnotationMarks.end(),
1592  [&rPos] (const ::sw::mark::MarkBase *const pMark) { return pMark->IsCoveringPosition(rPos); } );
1593  if (pAnnotationMark == m_vAnnotationMarks.end())
1594  return nullptr;
1595  return *pAnnotationMark;
1596  }
1597 
1598  // finds the first that is starting after
1600  {
1601  return std::upper_bound(
1602  m_vAnnotationMarks.begin(),
1603  m_vAnnotationMarks.end(),
1604  rPos,
1605  CompareIMarkStartsAfter());
1606  }
1607 
1608  OUString MarkManager::getUniqueMarkName(const OUString& rName) const
1609  {
1610  OSL_ENSURE(rName.getLength(),
1611  "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1612  if( m_rDoc.IsInMailMerge())
1613  {
1614  OUString newName = rName + "MailMergeMark"
1615  + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
1616  + OUString::number( m_vAllMarks.size() + 1 );
1617  return newName;
1618  }
1619 
1620  if (lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end()) == m_vAllMarks.end())
1621  {
1622  return rName;
1623  }
1624  OUString sTmp;
1625 
1626  // try the name "<rName>XXX" (where XXX is a number starting from 1) unless there is
1627  // an unused name. Due to performance-reasons (especially in mailmerge-scenarios) there
1628  // is a map m_aMarkBasenameMapUniqueOffset which holds the next possible offset (XXX) for
1629  // rName (so there is no need to test for nCnt-values smaller than the offset).
1630  sal_Int32 nCnt = 1;
1631  MarkBasenameMapUniqueOffset_t::const_iterator aIter = m_aMarkBasenameMapUniqueOffset.find(rName);
1632  if(aIter != m_aMarkBasenameMapUniqueOffset.end()) nCnt = aIter->second;
1633  while(nCnt < SAL_MAX_INT32)
1634  {
1635  sTmp = rName + OUString::number(nCnt);
1636  nCnt++;
1637  if (lcl_FindMarkByName(sTmp, m_vAllMarks.begin(), m_vAllMarks.end()) == m_vAllMarks.end())
1638  {
1639  break;
1640  }
1641  }
1642  m_aMarkBasenameMapUniqueOffset[rName] = nCnt;
1643 
1644  return sTmp;
1645  }
1646 
1648  {
1649  const_cast< MarkManager* >(this)->sortMarks();
1650  }
1651 
1653  {
1654  sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1655  sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1656  sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1657  }
1658 
1660  {
1661  sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1662  sortSubsetMarks();
1663  }
1664 
1666 {
1667  struct
1668  {
1669  const char* pName;
1670  const container_t* pContainer;
1671  } aContainers[] =
1672  {
1673  // UNO marks are only part of all marks.
1674  {"allmarks", &m_vAllMarks},
1675  {"bookmarks", &m_vBookmarks},
1676  {"fieldmarks", &m_vFieldmarks},
1677  {"annotationmarks", &m_vAnnotationMarks}
1678  };
1679 
1680  xmlTextWriterStartElement(pWriter, BAD_CAST("MarkManager"));
1681  for (const auto & rContainer : aContainers)
1682  {
1683  if (!rContainer.pContainer->empty())
1684  {
1685  xmlTextWriterStartElement(pWriter, BAD_CAST(rContainer.pName));
1686  for (auto it = rContainer.pContainer->begin(); it != rContainer.pContainer->end(); ++it)
1687  (*it)->dumpAsXml(pWriter);
1688  xmlTextWriterEndElement(pWriter);
1689  }
1690  }
1691  xmlTextWriterEndElement(pWriter);
1692 }
1693 
1694 } // namespace ::sw::mark
1695 
1696 namespace
1697 {
1698  bool lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1699  {
1700  return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1701  }
1702 }
1703 
1704 // IDocumentMarkAccess for SwDoc
1706  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1707 
1709  { return static_cast< IDocumentMarkAccess* >(mpMarkManager.get()); }
1710 
1711 SaveBookmark::SaveBookmark(
1712  const IMark& rBkmk,
1713  const SwNodeIndex & rMvPos,
1714  const SwIndex* pIdx)
1715  : m_aName(rBkmk.GetName())
1716  , m_bHidden(false)
1717  , m_aCode()
1718  , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1719 {
1720  const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1721  if(pBookmark)
1722  {
1723  m_aShortName = pBookmark->GetShortName();
1724  m_aCode = pBookmark->GetKeyCode();
1725  m_bHidden = pBookmark->IsHidden();
1726  m_aHideCondition = pBookmark->GetHideCondition();
1727 
1728  ::sfx2::Metadatable const*const pMetadatable(
1729  dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1730  if (pMetadatable)
1731  {
1732  m_pMetadataUndo = pMetadatable->CreateUndo();
1733  }
1734  }
1735  m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1737 
1738  m_nNode1 -= rMvPos.GetIndex();
1739  if(pIdx && !m_nNode1)
1740  m_nContent1 -= pIdx->GetIndex();
1741 
1742  if(rBkmk.IsExpanded())
1743  {
1744  m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1746 
1747  m_nNode2 -= rMvPos.GetIndex();
1748  if(pIdx && !m_nNode2)
1749  m_nContent2 -= pIdx->GetIndex();
1750  }
1751  else
1752  {
1753  m_nNode2 = ULONG_MAX;
1754  m_nContent2 = -1;
1755  }
1756 }
1757 
1759  SwDoc* pDoc,
1760  const SwNodeIndex& rNewPos,
1761  const SwIndex* pIdx)
1762 {
1763  SwPaM aPam(rNewPos.GetNode());
1764  if(pIdx)
1765  aPam.GetPoint()->nContent = *pIdx;
1766 
1767  if(ULONG_MAX != m_nNode2)
1768  {
1769  aPam.SetMark();
1770 
1771  aPam.GetMark()->nNode += m_nNode2;
1772  if(pIdx && !m_nNode2)
1773  aPam.GetMark()->nContent += m_nContent2;
1774  else
1775  aPam.GetMark()->nContent.Assign(aPam.GetContentNode(false), m_nContent2);
1776  }
1777 
1778  aPam.GetPoint()->nNode += m_nNode1;
1779 
1780  if(pIdx && !m_nNode1)
1781  aPam.GetPoint()->nContent += m_nContent1;
1782  else
1783  aPam.GetPoint()->nContent.Assign(aPam.GetContentNode(), m_nContent1);
1784 
1785  if(aPam.HasMark()
1786  && !CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, true))
1787  return;
1788 
1789  ::sw::mark::IBookmark* const pBookmark = dynamic_cast<::sw::mark::IBookmark*>(
1790  pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName,
1792  if(!pBookmark)
1793  return;
1794 
1795  pBookmark->SetKeyCode(m_aCode);
1796  pBookmark->SetShortName(m_aShortName);
1797  pBookmark->Hide(m_bHidden);
1798  pBookmark->SetHideCondition(m_aHideCondition);
1799 
1800  if (m_pMetadataUndo)
1801  {
1802  ::sfx2::Metadatable * const pMeta(
1803  dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1804  assert(pMeta && "metadata undo, but not metadatable?");
1805  if (pMeta)
1806  {
1808  }
1809  }
1810 }
1811 
1812 // DelBookmarks
1813 
1815  const SwNodeIndex& rStt,
1816  const SwNodeIndex& rEnd,
1817  std::vector<SaveBookmark> * pSaveBkmk,
1818  const SwIndex* pSttIdx,
1819  const SwIndex* pEndIdx)
1820 {
1821  // illegal range ??
1822  if(rStt.GetIndex() > rEnd.GetIndex()
1823  || (rStt == rEnd && (!pSttIdx || !pEndIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1824  return;
1825  SwDoc& rDoc = rStt.GetNode().GetDoc();
1826 
1827  rDoc.getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1828 
1829  // Copy all Redlines which are in the move area into an array
1830  // which holds all position information as offset.
1831  // Assignment happens after moving.
1833  for(SwRangeRedline* pRedl : rTable)
1834  {
1835  // Is at position?
1836  SwPosition *const pRStt = pRedl->Start();
1837  SwPosition *const pREnd = pRedl->End();
1838 
1839  if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1840  {
1841  pRStt->nNode = rEnd;
1842  if( pEndIdx )
1843  pRStt->nContent = *pEndIdx;
1844  else
1845  {
1846  bool bStt = true;
1847  SwContentNode* pCNd = pRStt->nNode.GetNode().GetContentNode();
1848  if( !pCNd )
1849  pCNd = rDoc.GetNodes().GoNext( &pRStt->nNode );
1850  if (!pCNd)
1851  {
1852  bStt = false;
1853  pRStt->nNode = rStt;
1854  pCNd = SwNodes::GoPrevious( &pRStt->nNode );
1855  if( !pCNd )
1856  {
1857  pRStt->nNode = pREnd->nNode;
1858  pCNd = pRStt->nNode.GetNode().GetContentNode();
1859  }
1860  }
1861  pRStt->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1862  }
1863  }
1864  if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1865  {
1866  pREnd->nNode = rStt;
1867  if( pSttIdx )
1868  pREnd->nContent = *pSttIdx;
1869  else
1870  {
1871  bool bStt = false;
1872  SwContentNode* pCNd = pREnd->nNode.GetNode().GetContentNode();
1873  if( !pCNd )
1874  pCNd = SwNodes::GoPrevious( &pREnd->nNode );
1875  if( !pCNd )
1876  {
1877  bStt = true;
1878  pREnd->nNode = rEnd;
1879  pCNd = rDoc.GetNodes().GoNext( &pREnd->nNode );
1880  if( !pCNd )
1881  {
1882  pREnd->nNode = pRStt->nNode;
1883  pCNd = pREnd->nNode.GetNode().GetContentNode();
1884  }
1885  }
1886  pREnd->nContent.Assign( pCNd, bStt ? 0 : pCNd->Len() );
1887  }
1888  }
1889  }
1890 }
1891 
1892 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual sw::mark::IMark * getAnnotationMarkFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1587
virtual sal_Int32 Len() const
Definition: node.cxx:1241
virtual void ShowButton(SwEditWin *pEditWin)=0
bool IsInMailMerge() const
Definition: doc.hxx:961
virtual const_iterator_t findFirstAnnotationStartsAfter(const SwPosition &rPos) const override
Finds the first mark that is starting after.
Definition: docbm.cxx:1599
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: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:1814
sw::mark::FieldmarkWithDropDownButton * m_pLastActiveFieldmark
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:190
OUString m_aName
virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition &rPos) const override
Finds the first mark that is starting after.
Definition: docbm.cxx:1373
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:274
virtual void SetModified()=0
Must be called manually at changes of format.
std::unique_ptr< std::vector<::sw::mark::MarkBase * >::const_iterator > m_pIter
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:475
container_t m_vFieldmarks
const SwPosition * GetMark() const
Definition: pam.hxx:209
OUString getUniqueMarkName(const OUString &rName) const
Definition: docbm.cxx:1608
sal_Int64 n
Provides access to the marks of a document.
Definition: doc.hxx:186
#define ODF_FORMCHECKBOX
void SetInDoc(SwDoc *pDoc, const SwNodeIndex &, const SwIndex *pIdx=nullptr)
Definition: docbm.cxx:1758
virtual const SwPosition & GetMarkPos() const =0
SwPosition FindFieldSep(IFieldmark const &rMark)
return position of the CH_TXT_ATR_FIELDSEP for rMark
Definition: bookmrk.cxx:56
virtual ::sw::mark::IFieldmark * getFieldmarkAfter(const SwPosition &rPos) const override
Definition: docbm.cxx:1560
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1301
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:402
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
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1705
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:1566
SfxViewShell * GetSfxViewShell() const
Definition: viewsh.hxx:441
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
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) ...
Definition: bookmrk.hxx:268
virtual sw::mark::IFieldmark * makeNoTextFieldBookmark(const SwPaM &rPaM, const OUString &rName, const OUString &rType) override
Definition: docbm.cxx:756
virtual bool IsExpanded() const override
Definition: bookmrk.hxx:76
SwDoc & m_rDoc
Definition: docbm.cxx:1205
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
Definition: bookmrk.hxx:51
virtual void clearAllMarks() override
Clear (deletes) all marks.
Definition: docbm.cxx:1324
static SW_DLLPUBLIC OUString GetCrossRefHeadingBookmarkNamePrefix()
Definition: docbm.cxx:509
static SW_DLLPUBLIC bool IsLegalPaMForCrossRefHeadingBookmark(const SwPaM &rPaM)
Definition: docbm.cxx:514
bool operator==(iterator const &rOther) const
Definition: docbm.cxx:109
SwIndex nContent
Definition: pam.hxx:38
container_t m_vBookmarks
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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
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:148
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
bool IsStartNode() const
Definition: node.hxx:627
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: docbm.cxx:1665
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:257
virtual void DeregisterFromDoc(SwDoc &rDoc)
Definition: bookmrk.cxx:373
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:805
bool operator!=(iterator const &rOther) const
Definition: docbm.cxx:114
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:1069
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:1576
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:545
container_t m_vAnnotationMarks
#define SAL_MAX_INT32
OUString m_aShortName
Definition: mvsave.hxx:60
virtual void deleteMarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< ::sw::mark::SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx)=0
Deletes marks in a range.
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
SwDoc & GetDoc()
Definition: node.hxx:211
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:1571
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:1647
MarkBasenameMapUniqueOffset_t m_aMarkBasenameMapUniqueOffset
SwContentNode * GetContentNode()
Definition: node.hxx:618
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:1335
virtual std::unique_ptr< ILazyDeleter > deleteMark(const const_iterator_t &ppMark) override
Deletes a mark.
Definition: docbm.cxx:1224
virtual const OUString & GetShortName() const =0
virtual auto InvalidateFrames() -> void
Definition: bookmrk.cxx:352
virtual bool renameMark(::sw::mark::IMark *io_pMark, const OUString &rNewName) override
Renames an existing Mark, if possible.
Definition: docbm.cxx:853
iterator operator-(difference_type) const
Definition: docbm.cxx:154
iterator operator+(difference_type) const
Definition: docbm.cxx:143
Marks a character position inside a document model node.
Definition: index.hxx:33
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:1204
virtual void SetHideCondition(const OUString &)=0
iterator & operator=(iterator const &rOther)
Definition: docbm.cxx:69
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:1581
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:977
virtual sw::mark::IMark * makeAnnotationMark(const SwPaM &rPaM, const OUString &rName) override
Definition: docbm.cxx:818
virtual SwPosition & GetOtherMarkPos() const override
Definition: bookmrk.hxx:53
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
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:1047
bool operator<=(iterator const &rOther) const
Definition: docbm.cxx:177
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:882
virtual void NotifyCursorUpdate(const SwCursorShell &rCursorShell) override
Definition: docbm.cxx:1482
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:716
#define SAL_INFO(area, stream)
sal_Int32 GetIndex() const
Definition: index.hxx:91
OString DateTimeToOString(const DateTime &rDateTime)
virtual SwPosition & GetMarkPos() const override
Definition: bookmrk.hxx:49
SwNodes & GetNodes()
Definition: doc.hxx:407
bool operator>(iterator const &rOther) const
Definition: docbm.cxx:173
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: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:928
SwDoc & GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:179
IDocumentMarkAccess::MarkType m_eOrigBkmType
Definition: mvsave.hxx:64
virtual void SetMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:279
void * p
iterator & operator+=(difference_type)
Definition: docbm.cxx:137
virtual ::sw::mark::IFieldmark * getFieldmarkBefore(const SwPosition &rPos) const override
Definition: docbm.cxx:1563
virtual ::sw::mark::IFieldmark * getDropDownFor(const SwPosition &rPos) const override
Definition: docbm.cxx:1530
virtual const SwPosition & GetMarkEnd() const =0
static void DeleteFieldmarkCommand(::sw::mark::IFieldmark const &rMark)
Definition: docbm.cxx:523
virtual void deleteFieldmarkAt(const SwPosition &rPos) override
Definition: docbm.cxx:1420
virtual std::vector< ::sw::mark::IFieldmark * > getDropDownsFor(const SwPaM &rPaM) const override
Definition: docbm.cxx:1538
#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:1429
#define SAL_WARN(area, stream)
virtual void ClearFieldActivation() override
Definition: docbm.cxx:1522
vcl::KeyCode m_aCode
Definition: mvsave.hxx:63
virtual const SwPosition & GetMarkStart() const =0
::sw::mark::IMark * operator*() const
Definition: docbm.cxx:92
sal_Int32 m_nContent2
Definition: mvsave.hxx:68
InsertMode
Definition: IMark.hxx:31
virtual void SetOtherMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:285
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:169
bool operator>=(iterator const &rOther) const
Definition: docbm.cxx:181
virtual bool IsExpanded() const =0
std::vector<::sw::mark::MarkBase * >::const_iterator const & get() const
Definition: docbm.cxx:54
bool IsTextNode() const
Definition: node.hxx:639
value_type operator[](difference_type) const
Definition: docbm.cxx:164
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:826
void RestoreMetadata(std::shared_ptr< MetadatableUndo > const &i_pUndo)
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1284
virtual bool IsHidden() const =0
OUString m_aHideCondition
Definition: mvsave.hxx:62
Definition: view.hxx:144
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:846
#define ODF_FORMDROPDOWN
virtual const SwPosition & GetOtherMarkPos() const =0
Base class of the Writer document model elements.
Definition: node.hxx:79
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo