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