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