xref: /AOO41X/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