1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_xmloff.hxx" 30*cdf0e10cSrcweir #include "XMLRedlineExport.hxx" 31*cdf0e10cSrcweir #include <tools/debug.hxx> 32*cdf0e10cSrcweir #include <rtl/ustring.hxx> 33*cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 34*cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 35*cdf0e10cSrcweir #include <com/sun/star/beans/UnknownPropertyException.hpp> 36*cdf0e10cSrcweir #include <com/sun/star/container/XEnumerationAccess.hpp> 37*cdf0e10cSrcweir 38*cdf0e10cSrcweir #include <com/sun/star/container/XEnumeration.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/document/XRedlinesSupplier.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/text/XText.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/text/XTextContent.hpp> 42*cdf0e10cSrcweir #include <com/sun/star/text/XTextSection.hpp> 43*cdf0e10cSrcweir #include <com/sun/star/util/DateTime.hpp> 44*cdf0e10cSrcweir #include <xmloff/xmltoken.hxx> 45*cdf0e10cSrcweir #include "xmloff/xmlnmspe.hxx" 46*cdf0e10cSrcweir #include <xmloff/xmlexp.hxx> 47*cdf0e10cSrcweir #include <xmloff/xmluconv.hxx> 48*cdf0e10cSrcweir 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir using namespace ::com::sun::star; 51*cdf0e10cSrcweir using namespace ::xmloff::token; 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir using ::com::sun::star::beans::PropertyValue; 54*cdf0e10cSrcweir using ::com::sun::star::beans::XPropertySet; 55*cdf0e10cSrcweir using ::com::sun::star::beans::UnknownPropertyException; 56*cdf0e10cSrcweir using ::com::sun::star::document::XRedlinesSupplier; 57*cdf0e10cSrcweir using ::com::sun::star::container::XEnumerationAccess; 58*cdf0e10cSrcweir using ::com::sun::star::container::XEnumeration; 59*cdf0e10cSrcweir using ::com::sun::star::text::XText; 60*cdf0e10cSrcweir using ::com::sun::star::text::XTextContent; 61*cdf0e10cSrcweir using ::com::sun::star::text::XTextSection; 62*cdf0e10cSrcweir using ::com::sun::star::uno::Any; 63*cdf0e10cSrcweir using ::com::sun::star::uno::Reference; 64*cdf0e10cSrcweir using ::com::sun::star::uno::Sequence; 65*cdf0e10cSrcweir using ::com::sun::star::util::DateTime; 66*cdf0e10cSrcweir using ::rtl::OUString; 67*cdf0e10cSrcweir using ::rtl::OUStringBuffer; 68*cdf0e10cSrcweir using ::std::list; 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir XMLRedlineExport::XMLRedlineExport(SvXMLExport& rExp) 72*cdf0e10cSrcweir : sDelete(RTL_CONSTASCII_USTRINGPARAM("Delete")) 73*cdf0e10cSrcweir , sDeletion(GetXMLToken(XML_DELETION)) 74*cdf0e10cSrcweir , sFormat(RTL_CONSTASCII_USTRINGPARAM("Format")) 75*cdf0e10cSrcweir , sFormatChange(GetXMLToken(XML_FORMAT_CHANGE)) 76*cdf0e10cSrcweir , sInsert(RTL_CONSTASCII_USTRINGPARAM("Insert")) 77*cdf0e10cSrcweir , sInsertion(GetXMLToken(XML_INSERTION)) 78*cdf0e10cSrcweir , sIsCollapsed(RTL_CONSTASCII_USTRINGPARAM("IsCollapsed")) 79*cdf0e10cSrcweir , sIsStart(RTL_CONSTASCII_USTRINGPARAM("IsStart")) 80*cdf0e10cSrcweir , sRedlineAuthor(RTL_CONSTASCII_USTRINGPARAM("RedlineAuthor")) 81*cdf0e10cSrcweir , sRedlineComment(RTL_CONSTASCII_USTRINGPARAM("RedlineComment")) 82*cdf0e10cSrcweir , sRedlineDateTime(RTL_CONSTASCII_USTRINGPARAM("RedlineDateTime")) 83*cdf0e10cSrcweir , sRedlineSuccessorData(RTL_CONSTASCII_USTRINGPARAM("RedlineSuccessorData")) 84*cdf0e10cSrcweir , sRedlineText(RTL_CONSTASCII_USTRINGPARAM("RedlineText")) 85*cdf0e10cSrcweir , sRedlineType(RTL_CONSTASCII_USTRINGPARAM("RedlineType")) 86*cdf0e10cSrcweir , sStyle(RTL_CONSTASCII_USTRINGPARAM("Style")) 87*cdf0e10cSrcweir , sTextTable(RTL_CONSTASCII_USTRINGPARAM("TextTable")) 88*cdf0e10cSrcweir , sUnknownChange(RTL_CONSTASCII_USTRINGPARAM("UnknownChange")) 89*cdf0e10cSrcweir , sStartRedline(RTL_CONSTASCII_USTRINGPARAM("StartRedline")) 90*cdf0e10cSrcweir , sEndRedline(RTL_CONSTASCII_USTRINGPARAM("EndRedline")) 91*cdf0e10cSrcweir , sRedlineIdentifier(RTL_CONSTASCII_USTRINGPARAM("RedlineIdentifier")) 92*cdf0e10cSrcweir , sIsInHeaderFooter(RTL_CONSTASCII_USTRINGPARAM("IsInHeaderFooter")) 93*cdf0e10cSrcweir , sRedlineProtectionKey(RTL_CONSTASCII_USTRINGPARAM("RedlineProtectionKey")) 94*cdf0e10cSrcweir , sRecordChanges(RTL_CONSTASCII_USTRINGPARAM("RecordChanges")) 95*cdf0e10cSrcweir , sMergeLastPara(RTL_CONSTASCII_USTRINGPARAM("MergeLastPara")) 96*cdf0e10cSrcweir , sChangePrefix(RTL_CONSTASCII_USTRINGPARAM("ct")) 97*cdf0e10cSrcweir , rExport(rExp) 98*cdf0e10cSrcweir , pCurrentChangesList(NULL) 99*cdf0e10cSrcweir { 100*cdf0e10cSrcweir } 101*cdf0e10cSrcweir 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir XMLRedlineExport::~XMLRedlineExport() 104*cdf0e10cSrcweir { 105*cdf0e10cSrcweir // delete changes lists 106*cdf0e10cSrcweir for( ChangesMapType::iterator aIter = aChangeMap.begin(); 107*cdf0e10cSrcweir aIter != aChangeMap.end(); 108*cdf0e10cSrcweir aIter++ ) 109*cdf0e10cSrcweir { 110*cdf0e10cSrcweir delete aIter->second; 111*cdf0e10cSrcweir } 112*cdf0e10cSrcweir aChangeMap.clear(); 113*cdf0e10cSrcweir } 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir 116*cdf0e10cSrcweir void XMLRedlineExport::ExportChange( 117*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet, 118*cdf0e10cSrcweir sal_Bool bAutoStyle) 119*cdf0e10cSrcweir { 120*cdf0e10cSrcweir if (bAutoStyle) 121*cdf0e10cSrcweir { 122*cdf0e10cSrcweir // For the headers/footers, we have to collect the autostyles 123*cdf0e10cSrcweir // here. For the general case, however, it's better to collet 124*cdf0e10cSrcweir // the autostyles by iterating over the global redline 125*cdf0e10cSrcweir // list. So that's what we do: Here, we collect autostyles 126*cdf0e10cSrcweir // only if we have no current list of changes. For the 127*cdf0e10cSrcweir // main-document case, the autostyles are collected in 128*cdf0e10cSrcweir // ExportChangesListAutoStyles(). 129*cdf0e10cSrcweir if (pCurrentChangesList != NULL) 130*cdf0e10cSrcweir ExportChangeAutoStyle(rPropSet); 131*cdf0e10cSrcweir } 132*cdf0e10cSrcweir else 133*cdf0e10cSrcweir { 134*cdf0e10cSrcweir ExportChangeInline(rPropSet); 135*cdf0e10cSrcweir } 136*cdf0e10cSrcweir } 137*cdf0e10cSrcweir 138*cdf0e10cSrcweir 139*cdf0e10cSrcweir void XMLRedlineExport::ExportChangesList(sal_Bool bAutoStyles) 140*cdf0e10cSrcweir { 141*cdf0e10cSrcweir if (bAutoStyles) 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir ExportChangesListAutoStyles(); 144*cdf0e10cSrcweir } 145*cdf0e10cSrcweir else 146*cdf0e10cSrcweir { 147*cdf0e10cSrcweir ExportChangesListElements(); 148*cdf0e10cSrcweir } 149*cdf0e10cSrcweir } 150*cdf0e10cSrcweir 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir void XMLRedlineExport::ExportChangesList( 153*cdf0e10cSrcweir const Reference<XText> & rText, 154*cdf0e10cSrcweir sal_Bool bAutoStyles) 155*cdf0e10cSrcweir { 156*cdf0e10cSrcweir // in the header/footer case, auto styles are collected from the 157*cdf0e10cSrcweir // inline change elements. 158*cdf0e10cSrcweir if (bAutoStyles) 159*cdf0e10cSrcweir return; 160*cdf0e10cSrcweir 161*cdf0e10cSrcweir // look for changes list for this XText 162*cdf0e10cSrcweir ChangesMapType::iterator aFind = aChangeMap.find(rText); 163*cdf0e10cSrcweir if (aFind != aChangeMap.end()) 164*cdf0e10cSrcweir { 165*cdf0e10cSrcweir ChangesListType* pChangesList = aFind->second; 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir // export only if changes are found 168*cdf0e10cSrcweir if (pChangesList->size() > 0) 169*cdf0e10cSrcweir { 170*cdf0e10cSrcweir // changes container element 171*cdf0e10cSrcweir SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, 172*cdf0e10cSrcweir XML_TRACKED_CHANGES, 173*cdf0e10cSrcweir sal_True, sal_True); 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir // iterate over changes list 176*cdf0e10cSrcweir for( ChangesListType::iterator aIter = pChangesList->begin(); 177*cdf0e10cSrcweir aIter != pChangesList->end(); 178*cdf0e10cSrcweir aIter++ ) 179*cdf0e10cSrcweir { 180*cdf0e10cSrcweir ExportChangedRegion( *aIter ); 181*cdf0e10cSrcweir } 182*cdf0e10cSrcweir } 183*cdf0e10cSrcweir // else: changes list empty -> ignore 184*cdf0e10cSrcweir } 185*cdf0e10cSrcweir // else: no changes list found -> empty 186*cdf0e10cSrcweir } 187*cdf0e10cSrcweir 188*cdf0e10cSrcweir void XMLRedlineExport::SetCurrentXText( 189*cdf0e10cSrcweir const Reference<XText> & rText) 190*cdf0e10cSrcweir { 191*cdf0e10cSrcweir if (rText.is()) 192*cdf0e10cSrcweir { 193*cdf0e10cSrcweir // look for appropriate list in map; use the found one, or create new 194*cdf0e10cSrcweir ChangesMapType::iterator aIter = aChangeMap.find(rText); 195*cdf0e10cSrcweir if (aIter == aChangeMap.end()) 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir ChangesListType* pList = new ChangesListType; 198*cdf0e10cSrcweir aChangeMap[rText] = pList; 199*cdf0e10cSrcweir pCurrentChangesList = pList; 200*cdf0e10cSrcweir } 201*cdf0e10cSrcweir else 202*cdf0e10cSrcweir pCurrentChangesList = aIter->second; 203*cdf0e10cSrcweir } 204*cdf0e10cSrcweir else 205*cdf0e10cSrcweir { 206*cdf0e10cSrcweir // don't record changes 207*cdf0e10cSrcweir SetCurrentXText(); 208*cdf0e10cSrcweir } 209*cdf0e10cSrcweir } 210*cdf0e10cSrcweir 211*cdf0e10cSrcweir void XMLRedlineExport::SetCurrentXText() 212*cdf0e10cSrcweir { 213*cdf0e10cSrcweir pCurrentChangesList = NULL; 214*cdf0e10cSrcweir } 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir 217*cdf0e10cSrcweir void XMLRedlineExport::ExportChangesListElements() 218*cdf0e10cSrcweir { 219*cdf0e10cSrcweir // get redlines (aka tracked changes) from the model 220*cdf0e10cSrcweir Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY); 221*cdf0e10cSrcweir if (xSupplier.is()) 222*cdf0e10cSrcweir { 223*cdf0e10cSrcweir Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines(); 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir // redline protection key 226*cdf0e10cSrcweir Reference<XPropertySet> aDocPropertySet( rExport.GetModel(), 227*cdf0e10cSrcweir uno::UNO_QUERY ); 228*cdf0e10cSrcweir // redlining enabled? 229*cdf0e10cSrcweir sal_Bool bEnabled = *(sal_Bool*)aDocPropertySet->getPropertyValue( 230*cdf0e10cSrcweir sRecordChanges ).getValue(); 231*cdf0e10cSrcweir 232*cdf0e10cSrcweir // only export if we have redlines or attributes 233*cdf0e10cSrcweir if ( aEnumAccess->hasElements() || bEnabled ) 234*cdf0e10cSrcweir { 235*cdf0e10cSrcweir 236*cdf0e10cSrcweir // export only if we have changes, but tracking is not enabled 237*cdf0e10cSrcweir if ( !bEnabled != !aEnumAccess->hasElements() ) 238*cdf0e10cSrcweir { 239*cdf0e10cSrcweir rExport.AddAttribute( 240*cdf0e10cSrcweir XML_NAMESPACE_TEXT, XML_TRACK_CHANGES, 241*cdf0e10cSrcweir bEnabled ? XML_TRUE : XML_FALSE ); 242*cdf0e10cSrcweir } 243*cdf0e10cSrcweir 244*cdf0e10cSrcweir // changes container element 245*cdf0e10cSrcweir SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, 246*cdf0e10cSrcweir XML_TRACKED_CHANGES, 247*cdf0e10cSrcweir sal_True, sal_True); 248*cdf0e10cSrcweir 249*cdf0e10cSrcweir // get enumeration and iterate over elements 250*cdf0e10cSrcweir Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration(); 251*cdf0e10cSrcweir while (aEnum->hasMoreElements()) 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir Any aAny = aEnum->nextElement(); 254*cdf0e10cSrcweir Reference<XPropertySet> xPropSet; 255*cdf0e10cSrcweir aAny >>= xPropSet; 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir DBG_ASSERT(xPropSet.is(), 258*cdf0e10cSrcweir "can't get XPropertySet; skipping Redline"); 259*cdf0e10cSrcweir if (xPropSet.is()) 260*cdf0e10cSrcweir { 261*cdf0e10cSrcweir // export only if not in header or footer 262*cdf0e10cSrcweir // (those must be exported with their XText) 263*cdf0e10cSrcweir aAny = xPropSet->getPropertyValue(sIsInHeaderFooter); 264*cdf0e10cSrcweir if (! *(sal_Bool*)aAny.getValue()) 265*cdf0e10cSrcweir { 266*cdf0e10cSrcweir // and finally, export change 267*cdf0e10cSrcweir ExportChangedRegion(xPropSet); 268*cdf0e10cSrcweir } 269*cdf0e10cSrcweir } 270*cdf0e10cSrcweir // else: no XPropertySet -> no export 271*cdf0e10cSrcweir } 272*cdf0e10cSrcweir } 273*cdf0e10cSrcweir // else: no redlines -> no export 274*cdf0e10cSrcweir } 275*cdf0e10cSrcweir // else: no XRedlineSupplier -> no export 276*cdf0e10cSrcweir } 277*cdf0e10cSrcweir 278*cdf0e10cSrcweir void XMLRedlineExport::ExportChangeAutoStyle( 279*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet) 280*cdf0e10cSrcweir { 281*cdf0e10cSrcweir // record change (if changes should be recorded) 282*cdf0e10cSrcweir if (NULL != pCurrentChangesList) 283*cdf0e10cSrcweir { 284*cdf0e10cSrcweir // put redline in list if it's collapsed or the redline start 285*cdf0e10cSrcweir Any aIsStart = rPropSet->getPropertyValue(sIsStart); 286*cdf0e10cSrcweir Any aIsCollapsed = rPropSet->getPropertyValue(sIsCollapsed); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if ( *(sal_Bool*)aIsStart.getValue() || 289*cdf0e10cSrcweir *(sal_Bool*)aIsCollapsed.getValue() ) 290*cdf0e10cSrcweir pCurrentChangesList->push_back(rPropSet); 291*cdf0e10cSrcweir } 292*cdf0e10cSrcweir 293*cdf0e10cSrcweir // get XText for export of redline auto styles 294*cdf0e10cSrcweir Any aAny = rPropSet->getPropertyValue(sRedlineText); 295*cdf0e10cSrcweir Reference<XText> xText; 296*cdf0e10cSrcweir aAny >>= xText; 297*cdf0e10cSrcweir if (xText.is()) 298*cdf0e10cSrcweir { 299*cdf0e10cSrcweir // export the auto styles 300*cdf0e10cSrcweir rExport.GetTextParagraphExport()->collectTextAutoStyles(xText); 301*cdf0e10cSrcweir } 302*cdf0e10cSrcweir } 303*cdf0e10cSrcweir 304*cdf0e10cSrcweir void XMLRedlineExport::ExportChangesListAutoStyles() 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir // get redlines (aka tracked changes) from the model 307*cdf0e10cSrcweir Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY); 308*cdf0e10cSrcweir if (xSupplier.is()) 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines(); 311*cdf0e10cSrcweir 312*cdf0e10cSrcweir // only export if we actually have redlines 313*cdf0e10cSrcweir if (aEnumAccess->hasElements()) 314*cdf0e10cSrcweir { 315*cdf0e10cSrcweir // get enumeration and iterate over elements 316*cdf0e10cSrcweir Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration(); 317*cdf0e10cSrcweir while (aEnum->hasMoreElements()) 318*cdf0e10cSrcweir { 319*cdf0e10cSrcweir Any aAny = aEnum->nextElement(); 320*cdf0e10cSrcweir Reference<XPropertySet> xPropSet; 321*cdf0e10cSrcweir aAny >>= xPropSet; 322*cdf0e10cSrcweir 323*cdf0e10cSrcweir DBG_ASSERT(xPropSet.is(), 324*cdf0e10cSrcweir "can't get XPropertySet; skipping Redline"); 325*cdf0e10cSrcweir if (xPropSet.is()) 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir 328*cdf0e10cSrcweir // export only if not in header or footer 329*cdf0e10cSrcweir // (those must be exported with their XText) 330*cdf0e10cSrcweir aAny = xPropSet->getPropertyValue(sIsInHeaderFooter); 331*cdf0e10cSrcweir if (! *(sal_Bool*)aAny.getValue()) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir ExportChangeAutoStyle(xPropSet); 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir } 337*cdf0e10cSrcweir } 338*cdf0e10cSrcweir } 339*cdf0e10cSrcweir } 340*cdf0e10cSrcweir 341*cdf0e10cSrcweir void XMLRedlineExport::ExportChangeInline( 342*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet) 343*cdf0e10cSrcweir { 344*cdf0e10cSrcweir // determine element name (depending on collapsed, start/end) 345*cdf0e10cSrcweir enum XMLTokenEnum eElement = XML_TOKEN_INVALID; 346*cdf0e10cSrcweir Any aAny = rPropSet->getPropertyValue(sIsCollapsed); 347*cdf0e10cSrcweir sal_Bool bCollapsed = *(sal_Bool *)aAny.getValue(); 348*cdf0e10cSrcweir sal_Bool bStart = sal_True; // ignored if bCollapsed = sal_True 349*cdf0e10cSrcweir if (bCollapsed) 350*cdf0e10cSrcweir { 351*cdf0e10cSrcweir eElement = XML_CHANGE; 352*cdf0e10cSrcweir } 353*cdf0e10cSrcweir else 354*cdf0e10cSrcweir { 355*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sIsStart); 356*cdf0e10cSrcweir bStart = *(sal_Bool *)aAny.getValue(); 357*cdf0e10cSrcweir eElement = bStart ? XML_CHANGE_START : XML_CHANGE_END; 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir if (XML_TOKEN_INVALID != eElement) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir // we always need the ID 363*cdf0e10cSrcweir rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, 364*cdf0e10cSrcweir GetRedlineID(rPropSet)); 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir // export the element (no whitespace because we're in the text body) 367*cdf0e10cSrcweir SvXMLElementExport aChangeElem(rExport, XML_NAMESPACE_TEXT, 368*cdf0e10cSrcweir eElement, sal_False, sal_False); 369*cdf0e10cSrcweir } 370*cdf0e10cSrcweir } 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir void XMLRedlineExport::ExportChangedRegion( 374*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet) 375*cdf0e10cSrcweir { 376*cdf0e10cSrcweir // Redline-ID 377*cdf0e10cSrcweir rExport.AddAttributeIdLegacy(XML_NAMESPACE_TEXT, GetRedlineID(rPropSet)); 378*cdf0e10cSrcweir 379*cdf0e10cSrcweir // merge-last-paragraph 380*cdf0e10cSrcweir Any aAny = rPropSet->getPropertyValue(sMergeLastPara); 381*cdf0e10cSrcweir if( ! *(sal_Bool*)aAny.getValue() ) 382*cdf0e10cSrcweir rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_MERGE_LAST_PARAGRAPH, 383*cdf0e10cSrcweir XML_FALSE); 384*cdf0e10cSrcweir 385*cdf0e10cSrcweir // export change region element 386*cdf0e10cSrcweir SvXMLElementExport aChangedRegion(rExport, XML_NAMESPACE_TEXT, 387*cdf0e10cSrcweir XML_CHANGED_REGION, sal_True, sal_True); 388*cdf0e10cSrcweir 389*cdf0e10cSrcweir 390*cdf0e10cSrcweir // scope for (first) change element 391*cdf0e10cSrcweir { 392*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sRedlineType); 393*cdf0e10cSrcweir OUString sType; 394*cdf0e10cSrcweir aAny >>= sType; 395*cdf0e10cSrcweir SvXMLElementExport aChange(rExport, XML_NAMESPACE_TEXT, 396*cdf0e10cSrcweir ConvertTypeName(sType), sal_True, sal_True); 397*cdf0e10cSrcweir 398*cdf0e10cSrcweir ExportChangeInfo(rPropSet); 399*cdf0e10cSrcweir 400*cdf0e10cSrcweir // get XText from the redline and export (if the XText exists) 401*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sRedlineText); 402*cdf0e10cSrcweir Reference<XText> xText; 403*cdf0e10cSrcweir aAny >>= xText; 404*cdf0e10cSrcweir if (xText.is()) 405*cdf0e10cSrcweir { 406*cdf0e10cSrcweir rExport.GetTextParagraphExport()->exportText(xText); 407*cdf0e10cSrcweir // default parameters: bProgress, bExportParagraph ??? 408*cdf0e10cSrcweir } 409*cdf0e10cSrcweir // else: no text interface -> content is inline and will 410*cdf0e10cSrcweir // be exported there 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir 413*cdf0e10cSrcweir // changed change? Hierarchical changes can onl be two levels 414*cdf0e10cSrcweir // deep. Here we check for the second level. 415*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sRedlineSuccessorData); 416*cdf0e10cSrcweir Sequence<PropertyValue> aSuccessorData; 417*cdf0e10cSrcweir aAny >>= aSuccessorData; 418*cdf0e10cSrcweir 419*cdf0e10cSrcweir // if we actually got a hierarchical change, make element and 420*cdf0e10cSrcweir // process change info 421*cdf0e10cSrcweir if (aSuccessorData.getLength() > 0) 422*cdf0e10cSrcweir { 423*cdf0e10cSrcweir // The only change that can be "undone" is an insertion - 424*cdf0e10cSrcweir // after all, you can't re-insert an deletion, but you can 425*cdf0e10cSrcweir // delete an insertion. This assumption is asserted in 426*cdf0e10cSrcweir // ExportChangeInfo(Sequence<PropertyValue>&). 427*cdf0e10cSrcweir SvXMLElementExport aSecondChangeElem( 428*cdf0e10cSrcweir rExport, XML_NAMESPACE_TEXT, XML_INSERTION, 429*cdf0e10cSrcweir sal_True, sal_True); 430*cdf0e10cSrcweir 431*cdf0e10cSrcweir ExportChangeInfo(aSuccessorData); 432*cdf0e10cSrcweir } 433*cdf0e10cSrcweir // else: no hierarchical change 434*cdf0e10cSrcweir } 435*cdf0e10cSrcweir 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir const OUString XMLRedlineExport::ConvertTypeName( 438*cdf0e10cSrcweir const OUString& sApiName) 439*cdf0e10cSrcweir { 440*cdf0e10cSrcweir if (sApiName == sDelete) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir return sDeletion; 443*cdf0e10cSrcweir } 444*cdf0e10cSrcweir else if (sApiName == sInsert) 445*cdf0e10cSrcweir { 446*cdf0e10cSrcweir return sInsertion; 447*cdf0e10cSrcweir } 448*cdf0e10cSrcweir else if (sApiName == sFormat) 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir return sFormatChange; 451*cdf0e10cSrcweir } 452*cdf0e10cSrcweir else 453*cdf0e10cSrcweir { 454*cdf0e10cSrcweir DBG_ERROR("unknown redline type"); 455*cdf0e10cSrcweir return sUnknownChange; 456*cdf0e10cSrcweir } 457*cdf0e10cSrcweir } 458*cdf0e10cSrcweir 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir /** Create a Redline-ID */ 461*cdf0e10cSrcweir const OUString XMLRedlineExport::GetRedlineID( 462*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet) 463*cdf0e10cSrcweir { 464*cdf0e10cSrcweir Any aAny = rPropSet->getPropertyValue(sRedlineIdentifier); 465*cdf0e10cSrcweir OUString sTmp; 466*cdf0e10cSrcweir aAny >>= sTmp; 467*cdf0e10cSrcweir 468*cdf0e10cSrcweir OUStringBuffer sBuf(sChangePrefix); 469*cdf0e10cSrcweir sBuf.append(sTmp); 470*cdf0e10cSrcweir return sBuf.makeStringAndClear(); 471*cdf0e10cSrcweir } 472*cdf0e10cSrcweir 473*cdf0e10cSrcweir 474*cdf0e10cSrcweir void XMLRedlineExport::ExportChangeInfo( 475*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet) 476*cdf0e10cSrcweir { 477*cdf0e10cSrcweir 478*cdf0e10cSrcweir SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, 479*cdf0e10cSrcweir XML_CHANGE_INFO, sal_True, sal_True); 480*cdf0e10cSrcweir 481*cdf0e10cSrcweir Any aAny = rPropSet->getPropertyValue(sRedlineAuthor); 482*cdf0e10cSrcweir OUString sTmp; 483*cdf0e10cSrcweir aAny >>= sTmp; 484*cdf0e10cSrcweir if (sTmp.getLength() > 0) 485*cdf0e10cSrcweir { 486*cdf0e10cSrcweir SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, 487*cdf0e10cSrcweir XML_CREATOR, sal_True, 488*cdf0e10cSrcweir sal_False ); 489*cdf0e10cSrcweir rExport.Characters(sTmp); 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sRedlineDateTime); 493*cdf0e10cSrcweir util::DateTime aDateTime; 494*cdf0e10cSrcweir aAny >>= aDateTime; 495*cdf0e10cSrcweir { 496*cdf0e10cSrcweir OUStringBuffer sBuf; 497*cdf0e10cSrcweir rExport.GetMM100UnitConverter().convertDateTime(sBuf, aDateTime); 498*cdf0e10cSrcweir SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, 499*cdf0e10cSrcweir XML_DATE, sal_True, 500*cdf0e10cSrcweir sal_False ); 501*cdf0e10cSrcweir rExport.Characters(sBuf.makeStringAndClear()); 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir // comment as <text:p> sequence 505*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(sRedlineComment); 506*cdf0e10cSrcweir aAny >>= sTmp; 507*cdf0e10cSrcweir WriteComment( sTmp ); 508*cdf0e10cSrcweir } 509*cdf0e10cSrcweir 510*cdf0e10cSrcweir void XMLRedlineExport::ExportChangeInfo( 511*cdf0e10cSrcweir const Sequence<PropertyValue> & rPropertyValues) 512*cdf0e10cSrcweir { 513*cdf0e10cSrcweir OUString sComment; 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir sal_Int32 nCount = rPropertyValues.getLength(); 516*cdf0e10cSrcweir for(sal_Int32 i = 0; i < nCount; i++) 517*cdf0e10cSrcweir { 518*cdf0e10cSrcweir const PropertyValue& rVal = rPropertyValues[i]; 519*cdf0e10cSrcweir 520*cdf0e10cSrcweir if( rVal.Name.equals(sRedlineAuthor) ) 521*cdf0e10cSrcweir { 522*cdf0e10cSrcweir OUString sTmp; 523*cdf0e10cSrcweir rVal.Value >>= sTmp; 524*cdf0e10cSrcweir if (sTmp.getLength() > 0) 525*cdf0e10cSrcweir { 526*cdf0e10cSrcweir rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_AUTHOR, sTmp); 527*cdf0e10cSrcweir } 528*cdf0e10cSrcweir } 529*cdf0e10cSrcweir else if( rVal.Name.equals(sRedlineComment) ) 530*cdf0e10cSrcweir { 531*cdf0e10cSrcweir rVal.Value >>= sComment; 532*cdf0e10cSrcweir } 533*cdf0e10cSrcweir else if( rVal.Name.equals(sRedlineDateTime) ) 534*cdf0e10cSrcweir { 535*cdf0e10cSrcweir util::DateTime aDateTime; 536*cdf0e10cSrcweir rVal.Value >>= aDateTime; 537*cdf0e10cSrcweir OUStringBuffer sBuf; 538*cdf0e10cSrcweir rExport.GetMM100UnitConverter().convertDateTime(sBuf, aDateTime); 539*cdf0e10cSrcweir rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME, 540*cdf0e10cSrcweir sBuf.makeStringAndClear()); 541*cdf0e10cSrcweir } 542*cdf0e10cSrcweir else if( rVal.Name.equals(sRedlineType) ) 543*cdf0e10cSrcweir { 544*cdf0e10cSrcweir // check if this is an insertion; cf. comment at calling location 545*cdf0e10cSrcweir OUString sTmp; 546*cdf0e10cSrcweir rVal.Value >>= sTmp; 547*cdf0e10cSrcweir DBG_ASSERT(sTmp.equals(sInsert), 548*cdf0e10cSrcweir "hierarchical change must be insertion"); 549*cdf0e10cSrcweir } 550*cdf0e10cSrcweir // else: unknown value -> ignore 551*cdf0e10cSrcweir } 552*cdf0e10cSrcweir 553*cdf0e10cSrcweir // finally write element 554*cdf0e10cSrcweir SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, 555*cdf0e10cSrcweir XML_CHANGE_INFO, sal_True, sal_True); 556*cdf0e10cSrcweir 557*cdf0e10cSrcweir WriteComment( sComment ); 558*cdf0e10cSrcweir } 559*cdf0e10cSrcweir 560*cdf0e10cSrcweir void XMLRedlineExport::ExportStartOrEndRedline( 561*cdf0e10cSrcweir const Reference<XPropertySet> & rPropSet, 562*cdf0e10cSrcweir sal_Bool bStart) 563*cdf0e10cSrcweir { 564*cdf0e10cSrcweir if( ! rPropSet.is() ) 565*cdf0e10cSrcweir return; 566*cdf0e10cSrcweir 567*cdf0e10cSrcweir // get appropriate (start or end) property 568*cdf0e10cSrcweir Any aAny; 569*cdf0e10cSrcweir try 570*cdf0e10cSrcweir { 571*cdf0e10cSrcweir aAny = rPropSet->getPropertyValue(bStart ? sStartRedline : sEndRedline); 572*cdf0e10cSrcweir } 573*cdf0e10cSrcweir catch( UnknownPropertyException e ) 574*cdf0e10cSrcweir { 575*cdf0e10cSrcweir // If we don't have the property, there's nothing to do. 576*cdf0e10cSrcweir return; 577*cdf0e10cSrcweir } 578*cdf0e10cSrcweir 579*cdf0e10cSrcweir Sequence<PropertyValue> aValues; 580*cdf0e10cSrcweir aAny >>= aValues; 581*cdf0e10cSrcweir const PropertyValue* pValues = aValues.getConstArray(); 582*cdf0e10cSrcweir 583*cdf0e10cSrcweir // seek for redline properties 584*cdf0e10cSrcweir sal_Bool bIsCollapsed = sal_False; 585*cdf0e10cSrcweir sal_Bool bIsStart = sal_True; 586*cdf0e10cSrcweir OUString sId; 587*cdf0e10cSrcweir sal_Bool bIdOK = sal_False; // have we seen an ID? 588*cdf0e10cSrcweir sal_Int32 nLength = aValues.getLength(); 589*cdf0e10cSrcweir for(sal_Int32 i = 0; i < nLength; i++) 590*cdf0e10cSrcweir { 591*cdf0e10cSrcweir if (sRedlineIdentifier.equals(pValues[i].Name)) 592*cdf0e10cSrcweir { 593*cdf0e10cSrcweir pValues[i].Value >>= sId; 594*cdf0e10cSrcweir bIdOK = sal_True; 595*cdf0e10cSrcweir } 596*cdf0e10cSrcweir else if (sIsCollapsed.equals(pValues[i].Name)) 597*cdf0e10cSrcweir { 598*cdf0e10cSrcweir bIsCollapsed = *(sal_Bool*)pValues[i].Value.getValue(); 599*cdf0e10cSrcweir } 600*cdf0e10cSrcweir else if (sIsStart.equals(pValues[i].Name)) 601*cdf0e10cSrcweir { 602*cdf0e10cSrcweir bIsStart = *(sal_Bool*)pValues[i].Value.getValue(); 603*cdf0e10cSrcweir } 604*cdf0e10cSrcweir } 605*cdf0e10cSrcweir 606*cdf0e10cSrcweir if( bIdOK ) 607*cdf0e10cSrcweir { 608*cdf0e10cSrcweir DBG_ASSERT( sId.getLength() > 0, "Redlines must have IDs" ); 609*cdf0e10cSrcweir 610*cdf0e10cSrcweir // TODO: use GetRedlineID or elimiate that function 611*cdf0e10cSrcweir OUStringBuffer sBuffer(sChangePrefix); 612*cdf0e10cSrcweir sBuffer.append(sId); 613*cdf0e10cSrcweir 614*cdf0e10cSrcweir rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, 615*cdf0e10cSrcweir sBuffer.makeStringAndClear()); 616*cdf0e10cSrcweir 617*cdf0e10cSrcweir // export the element 618*cdf0e10cSrcweir // (whitespace because we're not inside paragraphs) 619*cdf0e10cSrcweir SvXMLElementExport aChangeElem( 620*cdf0e10cSrcweir rExport, XML_NAMESPACE_TEXT, 621*cdf0e10cSrcweir bIsCollapsed ? XML_CHANGE : 622*cdf0e10cSrcweir ( bIsStart ? XML_CHANGE_START : XML_CHANGE_END ), 623*cdf0e10cSrcweir sal_True, sal_True); 624*cdf0e10cSrcweir } 625*cdf0e10cSrcweir } 626*cdf0e10cSrcweir 627*cdf0e10cSrcweir void XMLRedlineExport::ExportStartOrEndRedline( 628*cdf0e10cSrcweir const Reference<XTextContent> & rContent, 629*cdf0e10cSrcweir sal_Bool bStart) 630*cdf0e10cSrcweir { 631*cdf0e10cSrcweir Reference<XPropertySet> xPropSet(rContent, uno::UNO_QUERY); 632*cdf0e10cSrcweir if (xPropSet.is()) 633*cdf0e10cSrcweir { 634*cdf0e10cSrcweir ExportStartOrEndRedline(xPropSet, bStart); 635*cdf0e10cSrcweir } 636*cdf0e10cSrcweir else 637*cdf0e10cSrcweir { 638*cdf0e10cSrcweir DBG_ERROR("XPropertySet expected"); 639*cdf0e10cSrcweir } 640*cdf0e10cSrcweir } 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir void XMLRedlineExport::ExportStartOrEndRedline( 643*cdf0e10cSrcweir const Reference<XTextSection> & rSection, 644*cdf0e10cSrcweir sal_Bool bStart) 645*cdf0e10cSrcweir { 646*cdf0e10cSrcweir Reference<XPropertySet> xPropSet(rSection, uno::UNO_QUERY); 647*cdf0e10cSrcweir if (xPropSet.is()) 648*cdf0e10cSrcweir { 649*cdf0e10cSrcweir ExportStartOrEndRedline(xPropSet, bStart); 650*cdf0e10cSrcweir } 651*cdf0e10cSrcweir else 652*cdf0e10cSrcweir { 653*cdf0e10cSrcweir DBG_ERROR("XPropertySet expected"); 654*cdf0e10cSrcweir } 655*cdf0e10cSrcweir } 656*cdf0e10cSrcweir 657*cdf0e10cSrcweir void XMLRedlineExport::WriteComment(const OUString& rComment) 658*cdf0e10cSrcweir { 659*cdf0e10cSrcweir if (rComment.getLength() > 0) 660*cdf0e10cSrcweir { 661*cdf0e10cSrcweir // iterate over all string-pieces separated by return (0x0a) and 662*cdf0e10cSrcweir // put each inside a paragraph element. 663*cdf0e10cSrcweir SvXMLTokenEnumerator aEnumerator(rComment, sal_Char(0x0a)); 664*cdf0e10cSrcweir OUString aSubString; 665*cdf0e10cSrcweir while (aEnumerator.getNextToken(aSubString)) 666*cdf0e10cSrcweir { 667*cdf0e10cSrcweir SvXMLElementExport aParagraph( 668*cdf0e10cSrcweir rExport, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_False); 669*cdf0e10cSrcweir rExport.Characters(aSubString); 670*cdf0e10cSrcweir } 671*cdf0e10cSrcweir } 672*cdf0e10cSrcweir } 673