xref: /trunk/main/xmloff/source/text/XMLRedlineExport.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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