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