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