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 144 : XMLRedlineExport::XMLRedlineExport(SvXMLExport& rExp)
62 : : sDelete("Delete")
63 144 : , sDeletion(GetXMLToken(XML_DELETION))
64 : , sFormat("Format")
65 144 : , sFormatChange(GetXMLToken(XML_FORMAT_CHANGE))
66 : , sInsert("Insert")
67 144 : , 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 576 : , pCurrentChangesList(NULL)
86 : {
87 144 : }
88 :
89 :
90 288 : XMLRedlineExport::~XMLRedlineExport()
91 : {
92 : // delete changes lists
93 501 : for( ChangesMapType::iterator aIter = aChangeMap.begin();
94 334 : aIter != aChangeMap.end();
95 : ++aIter )
96 : {
97 23 : delete aIter->second;
98 : }
99 144 : aChangeMap.clear();
100 144 : }
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 146 : void XMLRedlineExport::ExportChangesList(bool bAutoStyles)
127 : {
128 146 : if (bAutoStyles)
129 : {
130 73 : ExportChangesListAutoStyles();
131 : }
132 : else
133 : {
134 73 : ExportChangesListElements();
135 : }
136 146 : }
137 :
138 :
139 46 : 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 46 : if (bAutoStyles)
146 69 : return;
147 :
148 : // look for changes list for this XText
149 23 : ChangesMapType::iterator aFind = aChangeMap.find(rText);
150 23 : if (aFind != aChangeMap.end())
151 : {
152 23 : ChangesListType* pChangesList = aFind->second;
153 :
154 : // export only if changes are found
155 23 : 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 46 : void XMLRedlineExport::SetCurrentXText(
176 : const Reference<XText> & rText)
177 : {
178 46 : if (rText.is())
179 : {
180 : // look for appropriate list in map; use the found one, or create new
181 46 : ChangesMapType::iterator aIter = aChangeMap.find(rText);
182 46 : if (aIter == aChangeMap.end())
183 : {
184 23 : ChangesListType* pList = new ChangesListType;
185 23 : aChangeMap[rText] = pList;
186 23 : pCurrentChangesList = pList;
187 : }
188 : else
189 23 : pCurrentChangesList = aIter->second;
190 : }
191 : else
192 : {
193 : // don't record changes
194 0 : SetCurrentXText();
195 : }
196 46 : }
197 :
198 46 : void XMLRedlineExport::SetCurrentXText()
199 : {
200 46 : pCurrentChangesList = NULL;
201 46 : }
202 :
203 :
204 73 : void XMLRedlineExport::ExportChangesListElements()
205 : {
206 : // get redlines (aka tracked changes) from the model
207 73 : Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY);
208 73 : if (xSupplier.is())
209 : {
210 73 : Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines();
211 :
212 : // redline protection key
213 73 : Reference<XPropertySet> aDocPropertySet( rExport.GetModel(),
214 146 : uno::UNO_QUERY );
215 : // redlining enabled?
216 73 : bool bEnabled = *static_cast<sal_Bool const *>(aDocPropertySet->getPropertyValue(
217 73 : sRecordChanges ).getValue());
218 :
219 : // only export if we have redlines or attributes
220 73 : 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 (! *static_cast<sal_Bool const *>(aAny.getValue()))
252 : {
253 : // and finally, export change
254 0 : ExportChangedRegion(xPropSet);
255 : }
256 : }
257 : // else: no XPropertySet -> no export
258 0 : }
259 73 : }
260 : // else: no redlines -> no export
261 73 : }
262 : // else: no XRedlineSupplier -> no export
263 73 : }
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 ( *static_cast<sal_Bool const *>(aIsStart.getValue()) ||
276 0 : *static_cast<sal_Bool const *>(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 73 : void XMLRedlineExport::ExportChangesListAutoStyles()
292 : {
293 : // get redlines (aka tracked changes) from the model
294 73 : Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY);
295 73 : if (xSupplier.is())
296 : {
297 73 : Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines();
298 :
299 : // only export if we actually have redlines
300 73 : 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 (! *static_cast<sal_Bool const *>(aAny.getValue()))
319 : {
320 0 : ExportChangeAutoStyle(xPropSet);
321 : }
322 : }
323 0 : }
324 73 : }
325 73 : }
326 73 : }
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 = *static_cast<sal_Bool const *>(aAny.getValue());
335 0 : if (bCollapsed)
336 : {
337 0 : eElement = XML_CHANGE;
338 : }
339 : else
340 : {
341 0 : aAny = rPropSet->getPropertyValue(sIsStart);
342 0 : const bool bStart = *static_cast<sal_Bool const *>(aAny.getValue());
343 0 : eElement = bStart ? XML_CHANGE_START : XML_CHANGE_END;
344 : }
345 :
346 0 : if (XML_TOKEN_INVALID != eElement)
347 : {
348 : // we always need the ID
349 : rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID,
350 0 : GetRedlineID(rPropSet));
351 :
352 : // export the element (no whitespace because we're in the text body)
353 : SvXMLElementExport aChangeElem(rExport, XML_NAMESPACE_TEXT,
354 0 : eElement, false, false);
355 0 : }
356 0 : }
357 :
358 :
359 0 : void XMLRedlineExport::ExportChangedRegion(
360 : const Reference<XPropertySet> & rPropSet)
361 : {
362 : // Redline-ID
363 0 : rExport.AddAttributeIdLegacy(XML_NAMESPACE_TEXT, GetRedlineID(rPropSet));
364 :
365 : // merge-last-paragraph
366 0 : Any aAny = rPropSet->getPropertyValue(sMergeLastPara);
367 0 : if( ! *static_cast<sal_Bool const *>(aAny.getValue()) )
368 : rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_MERGE_LAST_PARAGRAPH,
369 0 : XML_FALSE);
370 :
371 : // export change region element
372 : SvXMLElementExport aChangedRegion(rExport, XML_NAMESPACE_TEXT,
373 0 : XML_CHANGED_REGION, true, true);
374 :
375 :
376 : // scope for (first) change element
377 : {
378 0 : aAny = rPropSet->getPropertyValue(sRedlineType);
379 0 : OUString sType;
380 0 : aAny >>= sType;
381 : SvXMLElementExport aChange(rExport, XML_NAMESPACE_TEXT,
382 0 : ConvertTypeName(sType), true, true);
383 :
384 0 : ExportChangeInfo(rPropSet);
385 :
386 : // get XText from the redline and export (if the XText exists)
387 0 : aAny = rPropSet->getPropertyValue(sRedlineText);
388 0 : Reference<XText> xText;
389 0 : aAny >>= xText;
390 0 : if (xText.is())
391 : {
392 0 : rExport.GetTextParagraphExport()->exportText(xText);
393 : // default parameters: bProgress, bExportParagraph ???
394 0 : }
395 : // else: no text interface -> content is inline and will
396 : // be exported there
397 : }
398 :
399 : // changed change? Hierarchical changes can onl be two levels
400 : // deep. Here we check for the second level.
401 0 : aAny = rPropSet->getPropertyValue(sRedlineSuccessorData);
402 0 : Sequence<PropertyValue> aSuccessorData;
403 0 : aAny >>= aSuccessorData;
404 :
405 : // if we actually got a hierarchical change, make element and
406 : // process change info
407 0 : if (aSuccessorData.getLength() > 0)
408 : {
409 : // The only change that can be "undone" is an insertion -
410 : // after all, you can't re-insert an deletion, but you can
411 : // delete an insertion. This assumption is asserted in
412 : // ExportChangeInfo(Sequence<PropertyValue>&).
413 : SvXMLElementExport aSecondChangeElem(
414 : rExport, XML_NAMESPACE_TEXT, XML_INSERTION,
415 0 : true, true);
416 :
417 0 : ExportChangeInfo(aSuccessorData);
418 0 : }
419 : // else: no hierarchical change
420 0 : }
421 :
422 :
423 0 : const OUString XMLRedlineExport::ConvertTypeName(
424 : const OUString& sApiName)
425 : {
426 0 : if (sApiName == sDelete)
427 : {
428 0 : return sDeletion;
429 : }
430 0 : else if (sApiName == sInsert)
431 : {
432 0 : return sInsertion;
433 : }
434 0 : else if (sApiName == sFormat)
435 : {
436 0 : return sFormatChange;
437 : }
438 : else
439 : {
440 : OSL_FAIL("unknown redline type");
441 0 : return sUnknownChange;
442 : }
443 : }
444 :
445 :
446 : /** Create a Redline-ID */
447 0 : const OUString XMLRedlineExport::GetRedlineID(
448 : const Reference<XPropertySet> & rPropSet)
449 : {
450 0 : Any aAny = rPropSet->getPropertyValue(sRedlineIdentifier);
451 0 : OUString sTmp;
452 0 : aAny >>= sTmp;
453 :
454 0 : OUStringBuffer sBuf(sChangePrefix);
455 0 : sBuf.append(sTmp);
456 0 : return sBuf.makeStringAndClear();
457 : }
458 :
459 :
460 0 : void XMLRedlineExport::ExportChangeInfo(
461 : const Reference<XPropertySet> & rPropSet)
462 : {
463 :
464 : SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE,
465 0 : XML_CHANGE_INFO, true, true);
466 :
467 0 : Any aAny = rPropSet->getPropertyValue(sRedlineAuthor);
468 0 : OUString sTmp;
469 0 : aAny >>= sTmp;
470 0 : if (!sTmp.isEmpty())
471 : {
472 : SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC,
473 : XML_CREATOR, true,
474 0 : false );
475 0 : rExport.Characters(sTmp);
476 : }
477 :
478 0 : aAny = rPropSet->getPropertyValue(sRedlineDateTime);
479 0 : util::DateTime aDateTime;
480 0 : aAny >>= aDateTime;
481 : {
482 0 : OUStringBuffer sBuf;
483 0 : ::sax::Converter::convertDateTime(sBuf, aDateTime, 0);
484 : SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC,
485 : XML_DATE, true,
486 0 : false );
487 0 : rExport.Characters(sBuf.makeStringAndClear());
488 : }
489 :
490 : // comment as <text:p> sequence
491 0 : aAny = rPropSet->getPropertyValue(sRedlineComment);
492 0 : aAny >>= sTmp;
493 0 : WriteComment( sTmp );
494 0 : }
495 :
496 0 : void XMLRedlineExport::ExportChangeInfo(
497 : const Sequence<PropertyValue> & rPropertyValues)
498 : {
499 0 : OUString sComment;
500 :
501 0 : sal_Int32 nCount = rPropertyValues.getLength();
502 0 : for(sal_Int32 i = 0; i < nCount; i++)
503 : {
504 0 : const PropertyValue& rVal = rPropertyValues[i];
505 :
506 0 : if( rVal.Name.equals(sRedlineAuthor) )
507 : {
508 0 : OUString sTmp;
509 0 : rVal.Value >>= sTmp;
510 0 : if (!sTmp.isEmpty())
511 : {
512 0 : rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_AUTHOR, sTmp);
513 0 : }
514 : }
515 0 : else if( rVal.Name.equals(sRedlineComment) )
516 : {
517 0 : rVal.Value >>= sComment;
518 : }
519 0 : else if( rVal.Name.equals(sRedlineDateTime) )
520 : {
521 0 : util::DateTime aDateTime;
522 0 : rVal.Value >>= aDateTime;
523 0 : OUStringBuffer sBuf;
524 0 : ::sax::Converter::convertDateTime(sBuf, aDateTime, 0);
525 : rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME,
526 0 : sBuf.makeStringAndClear());
527 : }
528 0 : else if( rVal.Name.equals(sRedlineType) )
529 : {
530 : // check if this is an insertion; cf. comment at calling location
531 0 : OUString sTmp;
532 0 : rVal.Value >>= sTmp;
533 : DBG_ASSERT(sTmp.equals(sInsert),
534 0 : "hierarchical change must be insertion");
535 : }
536 : // else: unknown value -> ignore
537 : }
538 :
539 : // finally write element
540 : SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE,
541 0 : XML_CHANGE_INFO, true, true);
542 :
543 0 : WriteComment( sComment );
544 0 : }
545 :
546 822 : void XMLRedlineExport::ExportStartOrEndRedline(
547 : const Reference<XPropertySet> & rPropSet,
548 : bool bStart)
549 : {
550 822 : if( ! rPropSet.is() )
551 70 : return;
552 :
553 : // get appropriate (start or end) property
554 822 : Any aAny;
555 : try
556 : {
557 822 : aAny = rPropSet->getPropertyValue(bStart ? sStartRedline : sEndRedline);
558 : }
559 140 : catch(const UnknownPropertyException&)
560 : {
561 : // If we don't have the property, there's nothing to do.
562 70 : return;
563 : }
564 :
565 1504 : Sequence<PropertyValue> aValues;
566 752 : aAny >>= aValues;
567 752 : const PropertyValue* pValues = aValues.getConstArray();
568 :
569 : // seek for redline properties
570 752 : bool bIsCollapsed = false;
571 752 : bool bIsStart = true;
572 1504 : OUString sId;
573 752 : bool bIdOK = false; // have we seen an ID?
574 752 : sal_Int32 nLength = aValues.getLength();
575 752 : for(sal_Int32 i = 0; i < nLength; i++)
576 : {
577 0 : if (sRedlineIdentifier.equals(pValues[i].Name))
578 : {
579 0 : pValues[i].Value >>= sId;
580 0 : bIdOK = true;
581 : }
582 0 : else if (sIsCollapsed.equals(pValues[i].Name))
583 : {
584 0 : bIsCollapsed = *static_cast<sal_Bool const *>(pValues[i].Value.getValue());
585 : }
586 0 : else if (sIsStart.equals(pValues[i].Name))
587 : {
588 0 : bIsStart = *static_cast<sal_Bool const *>(pValues[i].Value.getValue());
589 : }
590 : }
591 :
592 752 : if( bIdOK )
593 : {
594 : DBG_ASSERT( !sId.isEmpty(), "Redlines must have IDs" );
595 :
596 : // TODO: use GetRedlineID or elimiate that function
597 0 : OUStringBuffer sBuffer(sChangePrefix);
598 0 : sBuffer.append(sId);
599 :
600 : rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID,
601 0 : sBuffer.makeStringAndClear());
602 :
603 : // export the element
604 : // (whitespace because we're not inside paragraphs)
605 : SvXMLElementExport aChangeElem(
606 : rExport, XML_NAMESPACE_TEXT,
607 : bIsCollapsed ? XML_CHANGE :
608 : ( bIsStart ? XML_CHANGE_START : XML_CHANGE_END ),
609 0 : true, true);
610 752 : }
611 : }
612 :
613 24 : void XMLRedlineExport::ExportStartOrEndRedline(
614 : const Reference<XTextContent> & rContent,
615 : bool bStart)
616 : {
617 24 : Reference<XPropertySet> xPropSet(rContent, uno::UNO_QUERY);
618 24 : if (xPropSet.is())
619 : {
620 24 : ExportStartOrEndRedline(xPropSet, bStart);
621 : }
622 : else
623 : {
624 : OSL_FAIL("XPropertySet expected");
625 24 : }
626 24 : }
627 :
628 76 : void XMLRedlineExport::ExportStartOrEndRedline(
629 : const Reference<XTextSection> & rSection,
630 : bool bStart)
631 : {
632 76 : Reference<XPropertySet> xPropSet(rSection, uno::UNO_QUERY);
633 76 : if (xPropSet.is())
634 : {
635 76 : ExportStartOrEndRedline(xPropSet, bStart);
636 : }
637 : else
638 : {
639 : OSL_FAIL("XPropertySet expected");
640 76 : }
641 76 : }
642 :
643 0 : void XMLRedlineExport::WriteComment(const OUString& rComment)
644 : {
645 0 : if (!rComment.isEmpty())
646 : {
647 : // iterate over all string-pieces separated by return (0x0a) and
648 : // put each inside a paragraph element.
649 0 : SvXMLTokenEnumerator aEnumerator(rComment, sal_Char(0x0a));
650 0 : OUString aSubString;
651 0 : while (aEnumerator.getNextToken(aSubString))
652 : {
653 : SvXMLElementExport aParagraph(
654 0 : rExport, XML_NAMESPACE_TEXT, XML_P, true, false);
655 0 : rExport.Characters(aSubString);
656 0 : }
657 : }
658 0 : }
659 :
660 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|