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