LCOV - code coverage report
Current view: top level - sw/source/filter/xml - XMLRedlineImportHelper.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 189 251 75.3 %
Date: 2014-11-03 Functions: 24 27 88.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10