blob: b8691d07be161e8ab82141ab50e7f47a29082856 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include "XMLRedlineImportHelper.hxx"
#include <unotextcursor.hxx>
#include <unotextrange.hxx>
#include <unocrsr.hxx>
#include "doc.hxx"
#include <tools/datetime.hxx>
#include "poolfmt.hxx"
#include "unoredline.hxx"
#include <xmloff/xmltoken.hxx>
#include <com/sun/star/frame/XModel.hpp>
// for locking SolarMutex: svapp + mutex
#include <vcl/svapp.hxx>
#include <vos/mutex.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::xmloff::token;
using ::rtl::OUString;
using ::com::sun::star::frame::XModel;
using ::com::sun::star::text::XTextCursor;
using ::com::sun::star::text::XTextRange;
using ::com::sun::star::text::XText;
using ::com::sun::star::text::XWordCursor;
using ::com::sun::star::lang::XUnoTunnel;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::beans::XPropertySetInfo;
// collision with tools/DateTime: use UNO DateTime as util::DateTime
// using util::DateTime;
//
// a few helper functions
//
SwDoc* lcl_GetDocViaTunnel( Reference<XTextCursor> & rCursor )
{
Reference<XUnoTunnel> xTunnel( rCursor, UNO_QUERY);
OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextCursor");
OTextCursorHelper *const pXCursor =
::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xTunnel);
OSL_ENSURE( pXCursor, "OTextCursorHelper missing" );
return (pXCursor) ? pXCursor->GetDoc() : 0;
}
SwDoc* lcl_GetDocViaTunnel( Reference<XTextRange> & rRange )
{
Reference<XUnoTunnel> xTunnel(rRange, UNO_QUERY);
OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextRange");
SwXTextRange *const pXRange =
::sw::UnoTunnelGetImplementation<SwXTextRange>(xTunnel);
// #i115174#: this may be a SvxUnoTextRange
// OSL_ENSURE( pXRange, "SwXTextRange missing" );
return (pXRange) ? pXRange->GetDoc() : 0;
}
//
// XTextRangeOrNodeIndexPosition: store a position into the text
// *either* as an XTextRange or as an SwNodeIndex. The reason is that
// we must store either pointers to StartNodes (because redlines may
// start on start nodes) or to a text position, and there appears to
// be no existing type that could do both. Things are complicated by
// the matter that (e.g in section import) we delete a few characters,
// which may cause bookmarks (as used by XTextRange) to be deleted.
//
class XTextRangeOrNodeIndexPosition
{
Reference<XTextRange> xRange;
SwNodeIndex* pIndex; /// pIndex will point to the *previous* node
public:
XTextRangeOrNodeIndexPosition();
~XTextRangeOrNodeIndexPosition();
void Set( Reference<XTextRange> & rRange );
void Set( SwNodeIndex& rIndex );
void SetAsNodeIndex( Reference<XTextRange> & rRange );
void CopyPositionInto(SwPosition& rPos, SwDoc & rDoc);
SwDoc* GetDoc();
sal_Bool IsValid();
};
XTextRangeOrNodeIndexPosition::XTextRangeOrNodeIndexPosition() :
xRange(NULL),
pIndex(NULL)
{
}
XTextRangeOrNodeIndexPosition::~XTextRangeOrNodeIndexPosition()
{
delete pIndex;
}
void XTextRangeOrNodeIndexPosition::Set( Reference<XTextRange> & rRange )
{
xRange = rRange->getStart(); // set bookmark
if (NULL != pIndex)
{
delete pIndex;
pIndex = NULL;
}
}
void XTextRangeOrNodeIndexPosition::Set( SwNodeIndex& rIndex )
{
if (NULL != pIndex)
delete pIndex;
pIndex = new SwNodeIndex(rIndex);
(*pIndex)-- ; // previous node!!!
xRange = NULL;
}
void XTextRangeOrNodeIndexPosition::SetAsNodeIndex(
Reference<XTextRange> & rRange )
{
// XTextRange -> XTunnel -> SwXTextRange
SwDoc* pDoc = lcl_GetDocViaTunnel(rRange);
if (!pDoc)
{
OSL_TRACE("SetAsNodeIndex: no SwDoc");
return;
}
// SwXTextRange -> PaM
SwUnoInternalPaM aPaM(*pDoc);
#ifdef DBG_UTIL
sal_Bool bSuccess =
#endif
::sw::XTextRangeToSwPaM(aPaM, rRange);
DBG_ASSERT(bSuccess, "illegal range");
// PaM -> Index
Set(aPaM.GetPoint()->nNode);
}
void
XTextRangeOrNodeIndexPosition::CopyPositionInto(SwPosition& rPos, SwDoc & rDoc)
{
DBG_ASSERT(IsValid(), "Can't get Position");
// create PAM from start cursor (if no node index is present)
if (NULL == pIndex)
{
SwUnoInternalPaM aUnoPaM(rDoc);
#ifdef DBG_UTIL
sal_Bool bSuccess =
#endif
::sw::XTextRangeToSwPaM(aUnoPaM, xRange);
DBG_ASSERT(bSuccess, "illegal range");
rPos = *aUnoPaM.GetPoint();
}
else
{
rPos.nNode = *pIndex;
rPos.nNode++; // pIndex points to previous index !!!
rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), 0 );
}
}
SwDoc* XTextRangeOrNodeIndexPosition::GetDoc()
{
DBG_ASSERT(IsValid(), "Can't get Doc");
return (NULL != pIndex) ? pIndex->GetNodes().GetDoc() : lcl_GetDocViaTunnel(xRange);
}
sal_Bool XTextRangeOrNodeIndexPosition::IsValid()
{
return ( xRange.is() || (pIndex != NULL) );
}
//
// RedlineInfo: temporary storage for redline data
//
class RedlineInfo
{
public:
RedlineInfo();
~RedlineInfo();
/// redline type (insert, delete, ...)
RedlineType_t eType;
// info fields:
OUString sAuthor; /// change author string
OUString sComment; /// change comment string
util::DateTime aDateTime; /// change DateTime
sal_Bool bMergeLastParagraph; /// the SwRedline::IsDelLastPara flag
// each position can may be either empty, an XTextRange, or an SwNodeIndex
// start pos of anchor (may be empty)
XTextRangeOrNodeIndexPosition aAnchorStart;
// end pos of anchor (may be empty)
XTextRangeOrNodeIndexPosition aAnchorEnd;
/// index of content node (maybe NULL)
SwNodeIndex* pContentIndex;
/// next redline info (for hierarchical redlines)
RedlineInfo* pNextRedline;
/// store whether we expect an adjustment for this redline
sal_Bool bNeedsAdjustment;
};
RedlineInfo::RedlineInfo() :
eType(nsRedlineType_t::REDLINE_INSERT),
sAuthor(),
sComment(),
aDateTime(),
bMergeLastParagraph( sal_False ),
aAnchorStart(),
aAnchorEnd(),
pContentIndex(NULL),
pNextRedline(NULL),
bNeedsAdjustment( sal_False )
{
}
RedlineInfo::~RedlineInfo()
{
delete pContentIndex;
delete pNextRedline;
}
//
// XMLRedlineImportHelper
//
XMLRedlineImportHelper::XMLRedlineImportHelper(
sal_Bool bNoRedlinesPlease,
const Reference<XPropertySet> & rModel,
const Reference<XPropertySet> & rImportInfo ) :
sEmpty(),
sInsertion( GetXMLToken( XML_INSERTION )),
sDeletion( GetXMLToken( XML_DELETION )),
sFormatChange( GetXMLToken( XML_FORMAT_CHANGE )),
sShowChanges(RTL_CONSTASCII_USTRINGPARAM("ShowChanges")),
sRecordChanges(RTL_CONSTASCII_USTRINGPARAM("RecordChanges")),
sRedlineProtectionKey(RTL_CONSTASCII_USTRINGPARAM("RedlineProtectionKey")),
aRedlineMap(),
bIgnoreRedlines(bNoRedlinesPlease),
xModelPropertySet(rModel),
xImportInfoPropertySet(rImportInfo)
{
// check to see if redline mode is handled outside of component
sal_Bool bHandleShowChanges = sal_True;
sal_Bool bHandleRecordChanges = sal_True;
sal_Bool bHandleProtectionKey = sal_True;
if ( xImportInfoPropertySet.is() )
{
Reference<XPropertySetInfo> xInfo =
xImportInfoPropertySet->getPropertySetInfo();
bHandleShowChanges = ! xInfo->hasPropertyByName( sShowChanges );
bHandleRecordChanges = ! xInfo->hasPropertyByName( sRecordChanges );
bHandleProtectionKey = ! xInfo->hasPropertyByName( sRedlineProtectionKey );
}
// get redline mode
bShowChanges = *(sal_Bool*)
( bHandleShowChanges ? xModelPropertySet : xImportInfoPropertySet )
->getPropertyValue( sShowChanges ).getValue();
bRecordChanges = *(sal_Bool*)
( bHandleRecordChanges ? xModelPropertySet : xImportInfoPropertySet )
->getPropertyValue( sRecordChanges ).getValue();
{
Any aAny = (bHandleProtectionKey ? xModelPropertySet
: xImportInfoPropertySet )
->getPropertyValue( sRedlineProtectionKey );
aAny >>= aProtectionKey;
}
// set redline mode to "don't record changes"
if( bHandleRecordChanges )
{
Any aAny;
sal_Bool bTmp = sal_False;
aAny.setValue( &bTmp, ::getBooleanCppuType() );
xModelPropertySet->setPropertyValue( sRecordChanges, aAny );
}
}
XMLRedlineImportHelper::~XMLRedlineImportHelper()
{
// delete all left over (and obviously incomplete) RedlineInfos (and map)
RedlineMapType::iterator aFind = aRedlineMap.begin();
for( ; aRedlineMap.end() != aFind; aFind++ )
{
RedlineInfo* pInfo = aFind->second;
// left-over redlines. Insert them if possible (but assert),
// and delete the incomplete ones. Finally, delete it.
if( IsReady(pInfo) )
{
DBG_ERROR("forgotten RedlineInfo; now inserted");
InsertIntoDocument( pInfo );
}
else
{
// try if only the adjustment was missing
pInfo->bNeedsAdjustment = sal_False;
if( IsReady(pInfo) )
{
DBG_ERROR("RedlineInfo without adjustment; now inserted");
InsertIntoDocument( pInfo );
}
else
{
// this situation occurs if redlines aren't closed
// (i.e. end without start, or start without
// end). This may well be a problem in the file,
// rather than the code.
DBG_ERROR("incomplete redline (maybe file was corrupt); "
"now deleted");
}
}
delete pInfo;
}
aRedlineMap.clear();
// set redline mode, either to info property set, or directly to
// the document
sal_Bool bHandleShowChanges = sal_True;
sal_Bool bHandleRecordChanges = sal_True;
sal_Bool bHandleProtectionKey = sal_True;
if ( xImportInfoPropertySet.is() )
{
Reference<XPropertySetInfo> xInfo =
xImportInfoPropertySet->getPropertySetInfo();
bHandleShowChanges = ! xInfo->hasPropertyByName( sShowChanges );
bHandleRecordChanges = ! xInfo->hasPropertyByName( sRecordChanges );
bHandleProtectionKey = ! xInfo->hasPropertyByName( sRedlineProtectionKey );
}
// set redline mode & key
Any aAny;
aAny.setValue( &bShowChanges, ::getBooleanCppuType() );
if ( bHandleShowChanges )
xModelPropertySet->setPropertyValue( sShowChanges, aAny );
else
xImportInfoPropertySet->setPropertyValue( sShowChanges, aAny );
aAny.setValue( &bRecordChanges, ::getBooleanCppuType() );
if ( bHandleRecordChanges )
xModelPropertySet->setPropertyValue( sRecordChanges, aAny );
else
xImportInfoPropertySet->setPropertyValue( sRecordChanges, aAny );
aAny <<= aProtectionKey;
if ( bHandleProtectionKey )
xModelPropertySet->setPropertyValue( sRedlineProtectionKey, aAny );
else
xImportInfoPropertySet->setPropertyValue( sRedlineProtectionKey, aAny);
}
void XMLRedlineImportHelper::Add(
const OUString& rType,
const OUString& rId,
const OUString& rAuthor,
const OUString& rComment,
const util::DateTime& rDateTime,
sal_Bool bMergeLastPara)
{
// we need to do the following:
// 1) parse type string
// 2) create RedlineInfo and fill it with data
// 3) check for existing redline with same ID
// 3a) insert redline into map
// 3b) attach to existing redline
// ad 1)
RedlineType_t eType;
if (rType.equals(sInsertion))
{
eType = nsRedlineType_t::REDLINE_INSERT;
}
else if (rType.equals(sDeletion))
{
eType = nsRedlineType_t::REDLINE_DELETE;
}
else if (rType.equals(sFormatChange))
{
eType = nsRedlineType_t::REDLINE_FORMAT;
}
else
{
// no proper type found: early out!
return;
}
// ad 2) create a new RedlineInfo
RedlineInfo* pInfo = new RedlineInfo();
// fill entries
pInfo->eType = eType;
pInfo->sAuthor = rAuthor;
pInfo->sComment = rComment;
pInfo->aDateTime = rDateTime;
pInfo->bMergeLastParagraph = bMergeLastPara;
// ad 3)
if (aRedlineMap.end() == aRedlineMap.find(rId))
{
// 3a) insert into map
aRedlineMap[rId] = pInfo;
}
else
{
// 3b) we already have a redline with this name: hierarchical redlines
// insert pInfo as last element in the chain.
// (hierarchy sanity checking happens on insertino into the document)
// find last element
RedlineInfo* pInfoChain;
for( pInfoChain = aRedlineMap[rId];
NULL != pInfoChain->pNextRedline;
pInfoChain = pInfoChain->pNextRedline) ; // empty loop
// insert as last element
pInfoChain->pNextRedline = pInfo;
}
}
Reference<XTextCursor> XMLRedlineImportHelper::CreateRedlineTextSection(
Reference<XTextCursor> xOldCursor,
const OUString& rId)
{
Reference<XTextCursor> xReturn;
// this method will modify the document directly -> lock SolarMutex
vos::OGuard aGuard(Application::GetSolarMutex());
// get RedlineInfo
RedlineMapType::iterator aFind = aRedlineMap.find(rId);
if (aRedlineMap.end() != aFind)
{
// get document from old cursor (via tunnel)
SwDoc* pDoc = lcl_GetDocViaTunnel(xOldCursor);
if (!pDoc)
{
OSL_TRACE("XMLRedlineImportHelper::CreateRedlineTextSection: "
"no SwDoc => cannot create section.");
return 0;
}
// create text section for redline
SwTxtFmtColl *pColl = pDoc->GetTxtCollFromPool
(RES_POOLCOLL_STANDARD, false );
SwStartNode* pRedlineNode = pDoc->GetNodes().MakeTextSection(
pDoc->GetNodes().GetEndOfRedlines(),
SwNormalStartNode,
pColl);
// remember node-index in RedlineInfo
SwNodeIndex aIndex(*pRedlineNode);
aFind->second->pContentIndex = new SwNodeIndex(aIndex);
// create XText for document
SwXText* pXText = new SwXRedlineText(pDoc, aIndex);
Reference<XText> xText = pXText; // keep Reference until end of method
// create (UNO-) cursor
SwPosition aPos(*pRedlineNode);
SwXTextCursor *const pXCursor =
new SwXTextCursor(*pDoc, pXText, CURSOR_REDLINE, aPos);
pXCursor->GetCursor()->Move(fnMoveForward, fnGoNode);
// cast to avoid ambiguity
xReturn = static_cast<text::XWordCursor*>(pXCursor);
}
// else: unknown redline -> Ignore
return xReturn;
}
void XMLRedlineImportHelper::SetCursor(
const OUString& rId,
sal_Bool bStart,
Reference<XTextRange> & rRange,
sal_Bool bIsOutsideOfParagraph)
{
RedlineMapType::iterator aFind = aRedlineMap.find(rId);
if (aRedlineMap.end() != aFind)
{
// RedlineInfo found; now set Cursor
RedlineInfo* pInfo = aFind->second;
if (bIsOutsideOfParagraph)
{
// outside of paragraph: remember SwNodeIndex
if (bStart)
{
pInfo->aAnchorStart.SetAsNodeIndex(rRange);
}
else
{
pInfo->aAnchorEnd.SetAsNodeIndex(rRange);
}
// also remember that we expect an adjustment for this redline
pInfo->bNeedsAdjustment = sal_True;
}
else
{
// inside of a paragraph: use regular XTextRanges (bookmarks)
if (bStart)
pInfo->aAnchorStart.Set(rRange);
else
pInfo->aAnchorEnd.Set(rRange);
}
// if this Cursor was the last missing info, we insert the
// node into the document
// then we can remove the entry from the map and destroy the object
if (IsReady(pInfo))
{
InsertIntoDocument(pInfo);
aRedlineMap.erase(rId);
delete pInfo;
}
}
// else: unknown Id -> ignore
}
void XMLRedlineImportHelper::AdjustStartNodeCursor(
const OUString& rId, /// ID used in RedlineAdd() call
sal_Bool /*bStart*/,
Reference<XTextRange> & /*rRange*/)
{
// this method will modify the document directly -> lock SolarMutex
vos::OGuard aGuard(Application::GetSolarMutex());
// start + end nodes are treated the same. For either it's
// necessary that the target node already exists.
RedlineMapType::iterator aFind = aRedlineMap.find(rId);
if (aRedlineMap.end() != aFind)
{
// RedlineInfo found; now set Cursor
RedlineInfo* pInfo = aFind->second;
pInfo->bNeedsAdjustment = sal_False;
// if now ready, insert into document
if( IsReady(pInfo) )
{
InsertIntoDocument(pInfo);
aRedlineMap.erase(rId);
delete pInfo;
}
}
// else: can't find redline -> ignore
}
inline sal_Bool XMLRedlineImportHelper::IsReady(RedlineInfo* pRedline)
{
// we can insert a redline if we have start & end, and we don't
// expect adjustments for either of these
return ( pRedline->aAnchorEnd.IsValid() &&
pRedline->aAnchorStart.IsValid() &&
!pRedline->bNeedsAdjustment );
}
void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
{
DBG_ASSERT(NULL != pRedlineInfo, "need redline info");
DBG_ASSERT(IsReady(pRedlineInfo), "redline info not complete yet!");
// this method will modify the document directly -> lock SolarMutex
vos::OGuard aGuard(Application::GetSolarMutex());
// Insert the Redline as described by pRedlineInfo into the
// document. If we are in insert mode, don't insert any redlines
// (and delete 'deleted' inline redlines)
// get the document (from one of the positions)
SwDoc* pDoc = pRedlineInfo->aAnchorStart.GetDoc();
if (!pDoc)
{
OSL_TRACE("XMLRedlineImportHelper::InsertIntoDocument: "
"no SwDoc => cannot insert redline.");
return;
}
// now create the PaM for the redline
SwPaM aPaM(pDoc->GetNodes().GetEndOfContent());
pRedlineInfo->aAnchorStart.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
aPaM.SetMark();
pRedlineInfo->aAnchorEnd.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
// collapse PaM if (start == end)
if (*aPaM.GetPoint() == *aPaM.GetMark())
{
aPaM.DeleteMark();
}
// cover three cases:
// 1) empty redlines (no range, no content) #100921#
// 2) check for:
// a) bIgnoreRedline (e.g. insert mode)
// b) illegal PaM range (CheckNodesRange())
// 3) normal case: insert redline
if( !aPaM.HasMark() && (pRedlineInfo->pContentIndex == NULL) )
{
// these redlines have no function, and will thus be ignored (just as
// in sw3io), so no action here
}
else if ( bIgnoreRedlines ||
!CheckNodesRange( aPaM.GetPoint()->nNode,
aPaM.GetMark()->nNode,
sal_True ) )
{
// ignore redline (e.g. file loaded in insert mode):
// delete 'deleted' redlines and forget about the whole thing
if (nsRedlineType_t::REDLINE_DELETE == pRedlineInfo->eType)
{
pDoc->DeleteRange(aPaM);
// And what about the "deleted nodes"?
// They have to be deleted as well (#i80689)!
if( bIgnoreRedlines && pRedlineInfo->pContentIndex != NULL )
{
SwNodeIndex aIdx( *pRedlineInfo->pContentIndex );
const SwNode* pEnd = aIdx.GetNode().EndOfSectionNode();
if( pEnd )
{
SwNodeIndex aEnd( *pEnd, 1 );
SwPaM aDel( aIdx, aEnd );
pDoc->DeleteRange(aDel);
}
}
}
}
else
{
// regular file loading: insert redline
// create redline (using pRedlineData which gets copied in SwRedline())
SwRedlineData* pRedlineData = ConvertRedline(pRedlineInfo, pDoc);
SwRedline* pRedline =
new SwRedline( pRedlineData, *aPaM.GetPoint(), sal_True,
!pRedlineInfo->bMergeLastParagraph, sal_False );
// set mark
if( aPaM.HasMark() )
{
pRedline->SetMark();
*(pRedline->GetMark()) = *aPaM.GetMark();
}
// set content node (if necessary)
if (NULL != pRedlineInfo->pContentIndex)
{
sal_uLong nPoint = aPaM.GetPoint()->nNode.GetIndex();
if( nPoint < pRedlineInfo->pContentIndex->GetIndex() ||
nPoint > pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex() )
pRedline->SetContentIdx(pRedlineInfo->pContentIndex);
#ifdef DBG_UTIL
else
ASSERT( false, "Recursive change tracking" );
#endif
}
// set redline mode (without doing the associated book-keeping)
pDoc->SetRedlineMode_intern(nsRedlineMode_t::REDLINE_ON);
pDoc->AppendRedline(pRedline, false);
pDoc->SetRedlineMode_intern(nsRedlineMode_t::REDLINE_NONE);
}
}
SwRedlineData* XMLRedlineImportHelper::ConvertRedline(
RedlineInfo* pRedlineInfo,
SwDoc* pDoc)
{
// convert info:
// 1) Author String -> Author ID (default to zero)
sal_uInt16 nAuthorId = (NULL == pDoc) ? 0 :
pDoc->InsertRedlineAuthor( pRedlineInfo->sAuthor );
// 2) util::DateTime -> DateTime
DateTime aDT;
aDT.SetYear( pRedlineInfo->aDateTime.Year );
aDT.SetMonth( pRedlineInfo->aDateTime.Month );
aDT.SetDay( pRedlineInfo->aDateTime.Day );
aDT.SetHour( pRedlineInfo->aDateTime.Hours );
aDT.SetMin( pRedlineInfo->aDateTime.Minutes );
aDT.SetSec( pRedlineInfo->aDateTime.Seconds );
aDT.Set100Sec( pRedlineInfo->aDateTime.HundredthSeconds );
// 3) recursively convert next redline
// ( check presence and sanity of hierarchical redline info )
SwRedlineData* pNext = NULL;
if ( (NULL != pRedlineInfo->pNextRedline) &&
(nsRedlineType_t::REDLINE_DELETE == pRedlineInfo->eType) &&
(nsRedlineType_t::REDLINE_INSERT == pRedlineInfo->pNextRedline->eType) )
{
pNext = ConvertRedline(pRedlineInfo->pNextRedline, pDoc);
}
// create redline data
SwRedlineData* pData = new SwRedlineData(pRedlineInfo->eType,
nAuthorId, aDT,
pRedlineInfo->sComment,
pNext, // next data (if available)
NULL); // no extra data
return pData;
}
void XMLRedlineImportHelper::SetShowChanges( sal_Bool bShow )
{
bShowChanges = bShow;
}
void XMLRedlineImportHelper::SetRecordChanges( sal_Bool bRecord )
{
bRecordChanges = bRecord;
}
void XMLRedlineImportHelper::SetProtectionKey(
const Sequence<sal_Int8> & rKey )
{
aProtectionKey = rKey;
}