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