LibreOffice Module sw (master)  1
XMLRedlineImportHelper.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 <sal/config.h>
22 #include <sal/log.hxx>
23 
24 #include <cstddef>
25 
27 #include <unotextcursor.hxx>
28 #include <unotextrange.hxx>
29 #include <unocrsr.hxx>
30 #include <ndtxt.hxx>
31 #include <doc.hxx>
34 #include <tools/datetime.hxx>
35 #include <poolfmt.hxx>
36 #include <unoredline.hxx>
38 #include "xmlimp.hxx"
40 #include <o3tl/any.hxx>
41 #include <xmloff/xmltoken.hxx>
42 #include <vcl/svapp.hxx>
43 
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::xmloff::token;
47 
48 using ::com::sun::star::text::XTextCursor;
49 using ::com::sun::star::text::XTextRange;
50 using ::com::sun::star::text::XWordCursor;
51 using ::com::sun::star::lang::XUnoTunnel;
52 using ::com::sun::star::beans::XPropertySet;
53 using ::com::sun::star::beans::XPropertySetInfo;
54 // collision with tools/DateTime: use UNO DateTime as util::DateTime
55 // using util::DateTime;
56 
57 // a few helper functions
58 static SwDoc* lcl_GetDocViaTunnel( Reference<XTextCursor> const & rCursor )
59 {
60  Reference<XUnoTunnel> xTunnel( rCursor, UNO_QUERY);
61  OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextCursor");
62  OTextCursorHelper *const pXCursor =
63  comphelper::getFromUnoTunnel<OTextCursorHelper>(xTunnel);
64  OSL_ENSURE( pXCursor, "OTextCursorHelper missing" );
65  return pXCursor ? pXCursor->GetDoc() : nullptr;
66 }
67 
68 static SwDoc* lcl_GetDocViaTunnel( Reference<XTextRange> const & rRange )
69 {
70  Reference<XUnoTunnel> xTunnel(rRange, UNO_QUERY);
71  OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextRange");
72  SwXTextRange *const pXRange =
73  comphelper::getFromUnoTunnel<SwXTextRange>(xTunnel);
74  // #i115174#: this may be a SvxUnoTextRange
75  // OSL_ENSURE( pXRange, "SwXTextRange missing" );
76  return pXRange ? &pXRange->GetDoc() : nullptr;
77 }
78 
79 // XTextRangeOrNodeIndexPosition: store a position into the text
80 // *either* as an XTextRange or as an SwNodeIndex. The reason is that
81 // we must store either pointers to StartNodes (because redlines may
82 // start on start nodes) or to a text position, and there appears to
83 // be no existing type that could do both. Things are complicated by
84 // the matter that (e.g in section import) we delete a few characters,
85 // which may cause bookmarks (as used by XTextRange) to be deleted.
86 
87 namespace {
88 
89 class XTextRangeOrNodeIndexPosition
90 {
91  Reference<XTextRange> m_xRange;
92  std::unique_ptr<SwNodeIndex> m_pIndex; // pIndex will point to the *previous* node
93 
94 public:
95  XTextRangeOrNodeIndexPosition();
96 
97  void Set( Reference<XTextRange> const & rRange );
98  void Set( SwNodeIndex const & rIndex );
99  void SetAsNodeIndex( Reference<XTextRange> const & rRange );
100 
101  void CopyPositionInto(SwPosition& rPos, SwDoc & rDoc);
102  SwDoc* GetDoc();
103 
104  bool IsValid() const;
105 };
106 
107 }
108 
109 XTextRangeOrNodeIndexPosition::XTextRangeOrNodeIndexPosition()
110 {
111 }
112 
113 void XTextRangeOrNodeIndexPosition::Set( Reference<XTextRange> const & rRange )
114 {
115  m_xRange = rRange->getStart(); // set bookmark
116  m_pIndex.reset();
117 }
118 
119 void XTextRangeOrNodeIndexPosition::Set( SwNodeIndex const & rIndex )
120 {
121  m_pIndex.reset( new SwNodeIndex(rIndex) );
122  (*m_pIndex)-- ; // previous node!!!
123  m_xRange = nullptr;
124 }
125 
126 void XTextRangeOrNodeIndexPosition::SetAsNodeIndex(
127  Reference<XTextRange> const & rRange )
128 {
129  // XTextRange -> XTunnel -> SwXTextRange
130  SwDoc* pDoc = lcl_GetDocViaTunnel(rRange);
131 
132  if (!pDoc)
133  {
134  SAL_WARN("sw", "no SwDoc");
135  return;
136  }
137 
138  // SwXTextRange -> PaM
139  SwUnoInternalPaM aPaM(*pDoc);
140  bool bSuccess = ::sw::XTextRangeToSwPaM(aPaM, rRange);
141  OSL_ENSURE(bSuccess, "illegal range");
142 
143  // PaM -> Index
144  Set(aPaM.GetPoint()->nNode);
145 }
146 
147 void
148 XTextRangeOrNodeIndexPosition::CopyPositionInto(SwPosition& rPos, SwDoc & rDoc)
149 {
150  OSL_ENSURE(IsValid(), "Can't get Position");
151 
152  // create PAM from start cursor (if no node index is present)
153  if (nullptr == m_pIndex)
154  {
155  SwUnoInternalPaM aUnoPaM(rDoc);
156  bool bSuccess = ::sw::XTextRangeToSwPaM(aUnoPaM, m_xRange);
157  OSL_ENSURE(bSuccess, "illegal range");
158 
159  rPos = *aUnoPaM.GetPoint();
160  }
161  else
162  {
163  rPos.nNode = *m_pIndex;
164  rPos.nNode++; // pIndex points to previous index !!!
165  rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(), 0 );
166  }
167 }
168 
169 SwDoc* XTextRangeOrNodeIndexPosition::GetDoc()
170 {
171  OSL_ENSURE(IsValid(), "Can't get Doc");
172 
173  return (nullptr != m_pIndex) ? &m_pIndex->GetNodes().GetDoc() : lcl_GetDocViaTunnel(m_xRange);
174 }
175 
176 bool XTextRangeOrNodeIndexPosition::IsValid() const
177 {
178  return ( m_xRange.is() || (m_pIndex != nullptr) );
179 }
180 
181 // RedlineInfo: temporary storage for redline data
183 {
184 public:
185  RedlineInfo();
186  ~RedlineInfo();
187 
188  // redline type (insert, delete, ...)
190 
191  // info fields:
192  OUString sAuthor; // change author string
193  OUString sComment; // change comment string
194  util::DateTime aDateTime; // change DateTime
195  bool bMergeLastParagraph; // the SwRangeRedline::IsDelLastPara flag
196 
197  // each position can may be either empty, an XTextRange, or an SwNodeIndex
198 
199  // start pos of anchor (may be empty)
200  XTextRangeOrNodeIndexPosition aAnchorStart;
201 
202  // end pos of anchor (may be empty)
203  XTextRangeOrNodeIndexPosition aAnchorEnd;
204 
205  // index of content node (maybe NULL)
207 
208  // next redline info (for hierarchical redlines)
210 
211  // store whether we expect an adjustment for this redline
213 };
214 
217  bMergeLastParagraph( false ),
218  pContentIndex(nullptr),
219  pNextRedline(nullptr),
220  bNeedsAdjustment( false )
221 {
222 }
223 
225 {
226  delete pContentIndex;
227  delete pNextRedline;
228 }
229 
230 constexpr OUStringLiteral g_sShowChanges = u"ShowChanges";
231 constexpr OUStringLiteral g_sRecordChanges = u"RecordChanges";
232 constexpr OUStringLiteral g_sRedlineProtectionKey = u"RedlineProtectionKey";
233 
235  SvXMLImport & rImport,
236  bool bNoRedlinesPlease,
237  const Reference<XPropertySet> & rModel,
238  const Reference<XPropertySet> & rImportInfo )
239  : m_rImport(rImport),
240  m_sInsertion( GetXMLToken( XML_INSERTION )),
241  m_sDeletion( GetXMLToken( XML_DELETION )),
242  m_sFormatChange( GetXMLToken( XML_FORMAT_CHANGE )),
243  m_bIgnoreRedlines(bNoRedlinesPlease),
244  m_xModelPropertySet(rModel),
245  m_xImportInfoPropertySet(rImportInfo)
246 {
247  // check to see if redline mode is handled outside of component
248  bool bHandleShowChanges = true;
249  bool bHandleRecordChanges = true;
250  bool bHandleProtectionKey = true;
251  if ( m_xImportInfoPropertySet.is() )
252  {
253  Reference<XPropertySetInfo> xInfo =
254  m_xImportInfoPropertySet->getPropertySetInfo();
255 
256  bHandleShowChanges = ! xInfo->hasPropertyByName( g_sShowChanges );
257  bHandleRecordChanges = ! xInfo->hasPropertyByName( g_sRecordChanges );
258  bHandleProtectionKey = ! xInfo->hasPropertyByName( g_sRedlineProtectionKey );
259  }
260 
261  // get redline mode
262  m_bShowChanges = *o3tl::doAccess<bool>(
263  ( bHandleShowChanges ? m_xModelPropertySet : m_xImportInfoPropertySet )
264  ->getPropertyValue( g_sShowChanges ));
265  m_bRecordChanges = *o3tl::doAccess<bool>(
266  ( bHandleRecordChanges ? m_xModelPropertySet : m_xImportInfoPropertySet )
267  ->getPropertyValue( g_sRecordChanges ));
268  {
269  Any aAny = (bHandleProtectionKey ? m_xModelPropertySet
271  ->getPropertyValue( g_sRedlineProtectionKey );
272  aAny >>= m_aProtectionKey;
273  }
274 
275  // set redline mode to "don't record changes"
276  if( bHandleRecordChanges )
277  {
278  m_xModelPropertySet->setPropertyValue( g_sRecordChanges, Any(false) );
279  }
280 }
281 
283 {
284  // delete all left over (and obviously incomplete) RedlineInfos (and map)
285  for( const auto& rEntry : m_aRedlineMap )
286  {
287  RedlineInfo* pInfo = rEntry.second;
288 
289  // left-over redlines. Insert them if possible (but assert),
290  // and delete the incomplete ones. Finally, delete it.
291  if( IsReady(pInfo) )
292  {
293  OSL_FAIL("forgotten RedlineInfo; now inserted");
294  InsertIntoDocument( pInfo );
295  }
296  else
297  {
298  // try if only the adjustment was missing
299  pInfo->bNeedsAdjustment = false;
300  if( IsReady(pInfo) )
301  {
302  OSL_FAIL("RedlineInfo without adjustment; now inserted");
303  InsertIntoDocument( pInfo );
304  }
305  else
306  {
307  // this situation occurs if redlines aren't closed
308  // (i.e. end without start, or start without
309  // end). This may well be a problem in the file,
310  // rather than the code.
311  OSL_FAIL("incomplete redline (maybe file was corrupt); "
312  "now deleted");
313  }
314  }
315  delete pInfo;
316  }
317  m_aRedlineMap.clear();
318 
319  // set redline mode, either to info property set, or directly to
320  // the document
321  bool bHandleShowChanges = true;
322  bool bHandleRecordChanges = true;
323  bool bHandleProtectionKey = true;
324  if ( m_xImportInfoPropertySet.is() )
325  {
326  Reference<XPropertySetInfo> xInfo =
327  m_xImportInfoPropertySet->getPropertySetInfo();
328 
329  bHandleShowChanges = ! xInfo->hasPropertyByName( g_sShowChanges );
330  bHandleRecordChanges = ! xInfo->hasPropertyByName( g_sRecordChanges );
331  bHandleProtectionKey = ! xInfo->hasPropertyByName( g_sRedlineProtectionKey );
332  }
333 
334  // set redline mode & key
335  try
336  {
337  Any aAny;
338 
339  aAny <<= m_bShowChanges;
340  if ( bHandleShowChanges )
341  {
342  aAny <<= true;
343  m_xModelPropertySet->setPropertyValue( g_sShowChanges, aAny );
344  // TODO maybe we need some property for the view-setting?
346  assert(pDoc);
348  }
349  else
350  m_xImportInfoPropertySet->setPropertyValue( g_sShowChanges, aAny );
351 
352  aAny <<= m_bRecordChanges;
353  if ( bHandleRecordChanges )
354  m_xModelPropertySet->setPropertyValue( g_sRecordChanges, aAny );
355  else
356  m_xImportInfoPropertySet->setPropertyValue( g_sRecordChanges, aAny );
357 
358  aAny <<= m_aProtectionKey;
359  if ( bHandleProtectionKey )
360  m_xModelPropertySet->setPropertyValue( g_sRedlineProtectionKey, aAny );
361  else
362  m_xImportInfoPropertySet->setPropertyValue( g_sRedlineProtectionKey, aAny);
363  }
364  catch (const uno::RuntimeException &) // fdo#65882
365  {
366  SAL_WARN( "sw", "potentially benign ordering issue during shutdown" );
367  }
368 }
369 
371  std::u16string_view rType,
372  const OUString& rId,
373  const OUString& rAuthor,
374  const OUString& rComment,
375  const util::DateTime& rDateTime,
376  bool bMergeLastPara)
377 {
378  // we need to do the following:
379  // 1) parse type string
380  // 2) create RedlineInfo and fill it with data
381  // 3) check for existing redline with same ID
382  // 3a) insert redline into map
383  // 3b) attach to existing redline
384 
385  // ad 1)
387  if (rType == m_sInsertion)
388  {
389  eType = RedlineType::Insert;
390  }
391  else if (rType == m_sDeletion)
392  {
393  eType = RedlineType::Delete;
394  }
395  else if (rType == m_sFormatChange)
396  {
397  eType = RedlineType::Format;
398  }
399  else
400  {
401  // no proper type found: early out!
402  return;
403  }
404 
405  // ad 2) create a new RedlineInfo
406  RedlineInfo* pInfo = new RedlineInfo();
407 
408  // fill entries
409  pInfo->eType = eType;
410  pInfo->sAuthor = rAuthor;
411  pInfo->sComment = rComment;
412  pInfo->aDateTime = rDateTime;
413  pInfo->bMergeLastParagraph = bMergeLastPara;
414 
415  // ad 3)
416  auto itPair = m_aRedlineMap.emplace(rId, pInfo);
417  if (itPair.second)
418  return;
419 
420  // 3b) we already have a redline with this name: hierarchical redlines
421  // insert pInfo as last element in the chain.
422  // (hierarchy sanity checking happens on inserting into the document)
423 
424  // find last element
425  RedlineInfo* pInfoChain;
426  for( pInfoChain = itPair.first->second;
427  nullptr != pInfoChain->pNextRedline;
428  pInfoChain = pInfoChain->pNextRedline) ; // empty loop
429 
430  // insert as last element
431  pInfoChain->pNextRedline = pInfo;
432 }
433 
435  Reference<XTextCursor> const & xOldCursor,
436  const OUString& rId)
437 {
438  Reference<XTextCursor> xReturn;
439 
440  // this method will modify the document directly -> lock SolarMutex
441  SolarMutexGuard aGuard;
442 
443  // get RedlineInfo
444  RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
445  if (m_aRedlineMap.end() != aFind)
446  {
447  // get document from old cursor (via tunnel)
448  SwDoc* pDoc = lcl_GetDocViaTunnel(xOldCursor);
449 
450  if (!pDoc)
451  {
452  SAL_WARN("sw", "no SwDoc => cannot create section.");
453  return nullptr;
454  }
455 
456  // create text section for redline
458  (RES_POOLCOLL_STANDARD, false );
459  SwStartNode* pRedlineNode = pDoc->GetNodes().MakeTextSection(
460  pDoc->GetNodes().GetEndOfRedlines(),
462  pColl);
463 
464  // remember node-index in RedlineInfo
465  SwNodeIndex aIndex(*pRedlineNode);
466  aFind->second->pContentIndex = new SwNodeIndex(aIndex);
467 
468  // create XText for document
469  rtl::Reference<SwXRedlineText> pXText = new SwXRedlineText(pDoc, aIndex);
470 
471  // create (UNO-) cursor
472  SwPosition aPos(*pRedlineNode);
474  new SwXTextCursor(*pDoc, pXText, CursorType::Redline, aPos);
475  pXCursor->GetCursor().Move(fnMoveForward, GoInNode);
476  // cast to avoid ambiguity
477  xReturn = static_cast<text::XWordCursor*>(pXCursor.get());
478  }
479  // else: unknown redline -> Ignore
480 
481  return xReturn;
482 }
483 
485  const OUString& rId,
486  bool bStart,
487  Reference<XTextRange> const & rRange,
488  bool bIsOutsideOfParagraph)
489 {
490  RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
491  if (m_aRedlineMap.end() == aFind)
492  return;
493 
494  // RedlineInfo found; now set Cursor
495  RedlineInfo* pInfo = aFind->second;
496  if (bIsOutsideOfParagraph)
497  {
498  // outside of paragraph: remember SwNodeIndex
499  if (bStart)
500  {
501  pInfo->aAnchorStart.SetAsNodeIndex(rRange);
502  }
503  else
504  {
505  pInfo->aAnchorEnd.SetAsNodeIndex(rRange);
506  }
507 
508  // also remember that we expect an adjustment for this redline
509  pInfo->bNeedsAdjustment = true;
510  }
511  else
512  {
513  // inside of a paragraph: use regular XTextRanges (bookmarks)
514  if (bStart)
515  pInfo->aAnchorStart.Set(rRange);
516  else
517  pInfo->aAnchorEnd.Set(rRange);
518  }
519 
520  // if this Cursor was the last missing info, we insert the
521  // node into the document
522  // then we can remove the entry from the map and destroy the object
523  if (IsReady(pInfo))
524  {
525  InsertIntoDocument(pInfo);
526  m_aRedlineMap.erase(rId);
527  delete pInfo;
528  }
529  // else: unknown Id -> ignore
530 }
531 
533  const OUString& rId)
534 {
535  // this method will modify the document directly -> lock SolarMutex
536  SolarMutexGuard aGuard;
537 
538  // start + end nodes are treated the same. For either it's
539  // necessary that the target node already exists.
540 
541  RedlineMapType::iterator aFind = m_aRedlineMap.find(rId);
542  if (m_aRedlineMap.end() == aFind)
543  return;
544 
545  // RedlineInfo found; now set Cursor
546  RedlineInfo* pInfo = aFind->second;
547 
548  pInfo->bNeedsAdjustment = false;
549 
550  // if now ready, insert into document
551  if( IsReady(pInfo) )
552  {
553  InsertIntoDocument(pInfo);
554  m_aRedlineMap.erase(rId);
555  delete pInfo;
556  }
557  // else: can't find redline -> ignore
558 }
559 
560 inline bool XMLRedlineImportHelper::IsReady(const RedlineInfo* pRedline)
561 {
562  // we can insert a redline if we have start & end, and we don't
563  // expect adjustments for either of these
564  return ( pRedline->aAnchorEnd.IsValid() &&
565  pRedline->aAnchorStart.IsValid() &&
566  !pRedline->bNeedsAdjustment );
567 }
568 
570 {
571  OSL_ENSURE(nullptr != pRedlineInfo, "need redline info");
572  OSL_ENSURE(IsReady(pRedlineInfo), "redline info not complete yet!");
573 
574  // this method will modify the document directly -> lock SolarMutex
575  SolarMutexGuard aGuard;
576 
577  // Insert the Redline as described by pRedlineInfo into the
578  // document. If we are in insert mode, don't insert any redlines
579  // (and delete 'deleted' inline redlines)
580 
581  // get the document (from one of the positions)
582  SwDoc* pDoc = pRedlineInfo->aAnchorStart.GetDoc();
583 
584  if (!pDoc)
585  {
586  SAL_WARN("sw", "no SwDoc => cannot insert redline.");
587  return;
588  }
589 
590  // now create the PaM for the redline
591  SwPaM aPaM(pDoc->GetNodes().GetEndOfContent());
592  pRedlineInfo->aAnchorStart.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
593  aPaM.SetMark();
594  pRedlineInfo->aAnchorEnd.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
595 
596  // collapse PaM if (start == end)
597  if (*aPaM.GetPoint() == *aPaM.GetMark())
598  {
599  aPaM.DeleteMark();
600  }
601 
602  // cover three cases:
603  // 1) empty redlines (no range, no content)
604  // 2) check for:
605  // a) bIgnoreRedline (e.g. insert mode)
606  // b) illegal PaM range (CheckNodesRange())
607  // c) redline with empty content section (quite useless)
608  // 3) normal case: insert redline
609  SwTextNode const* pTempNode(nullptr);
610  if( !aPaM.HasMark() && (pRedlineInfo->pContentIndex == nullptr) )
611  {
612  // these redlines have no function, and will thus be ignored (just as
613  // in sw3io), so no action here
614  }
615  else if ( m_bIgnoreRedlines ||
616  !CheckNodesRange( aPaM.GetPoint()->nNode,
617  aPaM.GetMark()->nNode,
618  true )
619  || (pRedlineInfo->pContentIndex
620  && (pRedlineInfo->pContentIndex->GetIndex() + 2
621  == pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex())
622  && (pTempNode = pDoc->GetNodes()[pRedlineInfo->pContentIndex->GetIndex() + 1]->GetTextNode()) != nullptr
623  && pTempNode->GetText().isEmpty()
624  && !pTempNode->GetpSwpHints()
625  && pTempNode->GetAnchoredFlys().empty()))
626  {
627  // ignore redline (e.g. file loaded in insert mode):
628  // delete 'deleted' redlines and forget about the whole thing
629  if (RedlineType::Delete == pRedlineInfo->eType)
630  {
632  // And what about the "deleted nodes"?
633  // They have to be deleted as well (#i80689)!
634  if( m_bIgnoreRedlines && pRedlineInfo->pContentIndex != nullptr )
635  {
636  SwNodeIndex aIdx( *pRedlineInfo->pContentIndex );
637  const SwNode* pEnd = aIdx.GetNode().EndOfSectionNode();
638  if( pEnd )
639  {
640  SwNodeIndex aEnd( *pEnd, 1 );
641  SwPaM aDel( aIdx, aEnd );
643  }
644  }
645  }
646  }
647  else
648  {
649  // regular file loading: insert redline
650 
651  // create redline (using pRedlineData which gets copied in SwRangeRedline())
652  SwRedlineData* pRedlineData = ConvertRedline(pRedlineInfo, pDoc);
653  SwRangeRedline* pRedline =
654  new SwRangeRedline( pRedlineData, *aPaM.GetPoint(),
655  !pRedlineInfo->bMergeLastParagraph );
656 
657  // tdf#107292 fix order of delete redlines at the same position by removing
658  // the already inserted redlines temporarily and inserting them back in reverse
659  // order after inserting pRedline
660  std::vector<const SwRangeRedline*> aSwapRedlines;
661  if ( RedlineType::Delete == pRedlineInfo->eType )
662  {
664  while ( const SwRangeRedline* pRedline2 =
665  pDoc->getIDocumentRedlineAccess().GetRedline( *pRedline->Start(), &n ) )
666  {
667  SwRedlineTable& aRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
668  aSwapRedlines.push_back(pRedline2);
669  aRedlineTable.Remove(n);
670  }
671  }
672 
673  // set mark
674  if( aPaM.HasMark() )
675  {
676  pRedline->SetMark();
677  *(pRedline->GetMark()) = *aPaM.GetMark();
678  }
679 
680  // set content node (if necessary)
681  if (nullptr != pRedlineInfo->pContentIndex)
682  {
683  SwNodeOffset nPoint = aPaM.GetPoint()->nNode.GetIndex();
684  if( nPoint < pRedlineInfo->pContentIndex->GetIndex() ||
685  nPoint > pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex() )
686  pRedline->SetContentIdx(pRedlineInfo->pContentIndex);
687  else
688  SAL_WARN("sw", "Recursive change tracking");
689  }
690 
691  // set redline mode (without doing the associated book-keeping)
693  pDoc->getIDocumentRedlineAccess().AppendRedline(pRedline, false);
694 
695  // restore the correct order of the delete redlines at the same position
696  for (auto i = aSwapRedlines.rbegin(); i != aSwapRedlines.rend(); ++i)
697  pDoc->getIDocumentRedlineAccess().AppendRedline(const_cast<SwRangeRedline*>(*i), false);
698 
700  }
701 }
702 
704  RedlineInfo* pRedlineInfo,
705  SwDoc* pDoc)
706 {
707  // convert info:
708  // 1) Author String -> Author ID (default to zero)
709  std::size_t nAuthorId = (nullptr == pDoc) ? 0 :
710  pDoc->getIDocumentRedlineAccess().InsertRedlineAuthor( pRedlineInfo->sAuthor );
711 
712  // 2) util::DateTime -> DateTime
713  DateTime aDT( DateTime::EMPTY );
714  aDT.SetYear( pRedlineInfo->aDateTime.Year );
715  aDT.SetMonth( pRedlineInfo->aDateTime.Month );
716  aDT.SetDay( pRedlineInfo->aDateTime.Day );
717  aDT.SetHour( pRedlineInfo->aDateTime.Hours );
718  aDT.SetMin( pRedlineInfo->aDateTime.Minutes );
719  aDT.SetSec( pRedlineInfo->aDateTime.Seconds );
720  aDT.SetNanoSec( pRedlineInfo->aDateTime.NanoSeconds );
721 
722  // 3) recursively convert next redline
723  // ( check presence and sanity of hierarchical redline info )
724  SwRedlineData* pNext = nullptr;
725  if ( (nullptr != pRedlineInfo->pNextRedline) &&
726  (RedlineType::Delete == pRedlineInfo->eType) &&
727  (RedlineType::Insert == pRedlineInfo->pNextRedline->eType) )
728  {
729  pNext = ConvertRedline(pRedlineInfo->pNextRedline, pDoc);
730  }
731 
732  // create redline data
733  SwRedlineData* pData = new SwRedlineData(pRedlineInfo->eType,
734  nAuthorId, aDT,
735  pRedlineInfo->sComment,
736  pNext); // next data (if available)
737 
738  return pData;
739 }
740 
742 {
743  m_bShowChanges = bShow;
744 }
745 
747 {
748  m_bRecordChanges = bRecord;
749 }
750 
752  const Sequence<sal_Int8> & rKey )
753 {
754  m_aProtectionKey = rKey;
755 }
756 
757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:692
Starts a section of nodes in the document model.
Definition: node.hxx:313
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:687
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
Marks a position in the document model.
Definition: pam.hxx:36
constexpr OUStringLiteral g_sShowChanges
void SetContentIdx(const SwNodeIndex *)
Definition: docredln.cxx:1855
const OUString & GetText() const
Definition: ndtxt.hxx:218
void SetSec(sal_uInt16 nNewSec)
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:226
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
SwNodeIndex nNode
Definition: pam.hxx:38
css::uno::Sequence< sal_Int8 > m_aProtectionKey
std::unique_ptr< sal_Int32[]> pData
XML_INSERTION
const SwPosition * GetMark() const
Definition: pam.hxx:210
XMLRedlineImportHelper(SvXMLImport &rImport, bool bIgnoreRedlines, const css::uno::Reference< css::beans::XPropertySet > &rModel, const css::uno::Reference< css::beans::XPropertySet > &rImportInfoSet)
XML_FORMAT_CHANGE
sal_Int64 n
void Remove(size_type nPos)
Definition: docredln.cxx:643
Definition: doc.hxx:187
RedlineInfo * pNextRedline
virtual void DeleteRange(SwPaM &)=0
Delete a range SwFlyFrameFormat.
::sw::DocumentRedlineManager const & GetDocumentRedlineManager() const
Definition: doc.cxx:345
SwNode & GetNode() const
Definition: ndindex.hxx:119
static bool IsReady(const RedlineInfo *pRedline)
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
void SetRecordChanges(bool bRecordChanges)
void SetHour(sal_uInt16 nNewHour)
const SwDoc & GetDoc() const
Definition: unoobj2.cxx:767
SwIndex nContent
Definition: pam.hxx:39
void SetProtectionKey(const css::uno::Sequence< sal_Int8 > &rKey)
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
void SetShowChanges(bool bShowChanges)
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
constexpr OUStringLiteral g_sRecordChanges
void SetYear(sal_Int16 nNewYear)
bool CheckNodesRange(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, bool bChkSection)
Check if the given range is inside one of the defined top-level sections.
Definition: pam.cxx:257
std::vector< SwFrameFormat * > const & GetAnchoredFlys() const
Definition: node.hxx:298
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:152
RedlineFlags on.
css::uno::Reference< css::text::XTextCursor > CreateRedlineTextSection(css::uno::Reference< css::text::XTextCursor > const &xOldCursor, const OUString &rId)
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:162
DocumentType eType
SwStartNode * MakeTextSection(const SwNodeIndex &rWhere, SwStartNodeType eSttNdTyp, SwTextFormatColl *pColl)
Definition: nodes.cxx:1896
XTextRangeOrNodeIndexPosition aAnchorEnd
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
static SwDoc * lcl_GetDocViaTunnel(Reference< XTextCursor > const &rCursor)
css::uno::Reference< css::beans::XPropertySet > m_xImportInfoPropertySet
int i
bool GoInNode(SwPaM &rPam, SwMoveFnCollection const &fnMove)
Definition: pam.cxx:959
void SetDay(sal_uInt16 nNewDay)
SwXRedlineText provides an XText which may be used to write directly into a redline node...
Definition: unoredline.hxx:34
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
SwContentNode * GetContentNode()
Definition: node.hxx:625
vector_type::size_type size_type
Definition: docary.hxx:222
float u
void SetHideRedlines(bool const bHideRedlines)
Marks a node in the document model.
Definition: ndindex.hxx:30
virtual std::size_t InsertRedlineAuthor(const OUString &rAuthor)=0
const SwPosition * Start() const
Definition: pam.hxx:213
bool XTextRangeToSwPaM(SwUnoInternalPaM &rToFill, const uno::Reference< text::XTextRange > &xTextRange,::sw::TextRangeMode const eMode)
Definition: unoobj2.cxx:1107
void SetCursor(const OUString &rId, bool bStart, css::uno::Reference< css::text::XTextRange > const &rRange, bool bIsOutsideOfParagraph)
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
void AdjustStartNodeCursor(const OUString &rId)
Adjust the start (end) position for a redline that begins in a start node.
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
std::deque< AttacherIndex_Impl > aIndex
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
SwMoveFnCollection const & fnMoveForward
SwPam::Move()/Find() default argument.
Definition: paminit.cxx:59
const SvXMLImport & m_rImport
SwNodes & GetNodes()
Definition: doc.hxx:408
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
void Add(std::u16string_view rType, const OUString &rId, const OUString &rAuthor, const OUString &rComment, const css::util::DateTime &rDateTime, bool bMergeLastParagraph)
void SetNanoSec(sal_uInt32 nNewNanoSec)
void SetMin(sal_uInt16 nNewMin)
XML_DELETION
css::uno::Reference< css::beans::XPropertySet > m_xModelPropertySet
SwRedlineData * ConvertRedline(RedlineInfo *pRedline, SwDoc *pDoc)
XTextRangeOrNodeIndexPosition aAnchorStart
#define SAL_WARN(area, stream)
RedlineType
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:476
util::DateTime aDateTime
virtual const SwRedlineTable & GetRedlineTable() const =0
SwNode & GetEndOfRedlines() const
Section for all Redlines.
Definition: ndarr.hxx:157
SwDoc * GetDocFromXMLImport(SvXMLImport const &)
Definition: xmlimp.cxx:1621
SwNodeIndex * pContentIndex
virtual void Insert(SotClipboardFormatId nFormat, const OUString &rFormatName) override
void InsertIntoDocument(RedlineInfo *pRedline)
void SetMonth(sal_uInt16 nNewMonth)
no RedlineFlags
constexpr OUStringLiteral g_sRedlineProtectionKey
bool m_bDetectedRangeSegmentation false
Base class of the Writer document model elements.
Definition: node.hxx:81