Clean up uses of Any::getValue() in sw
[LibreOffice.git] / sw / source / filter / xml / wrtxml.cxx
blobd62880228987065c9d58a2042ba206ed93954576
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/embed/XStorage.hpp>
21 #include <com/sun/star/embed/ElementModes.hpp>
22 #include <com/sun/star/container/XIndexContainer.hpp>
23 #include <com/sun/star/beans/PropertyAttribute.hpp>
24 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
25 #include <com/sun/star/io/XActiveDataSource.hpp>
26 #include <com/sun/star/xml/sax/Writer.hpp>
27 #include <com/sun/star/document/XExporter.hpp>
28 #include <com/sun/star/document/XFilter.hpp>
29 #include <com/sun/star/frame/XModule.hpp>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/genericpropertyset.hxx>
32 #include <o3tl/any.hxx>
33 #include <unotools/streamwrap.hxx>
34 #include <svx/xmlgrhlp.hxx>
35 #include <svx/xmleohlp.hxx>
36 #include <unotools/saveopt.hxx>
37 #include <svl/stritem.hxx>
38 #include <sfx2/frame.hxx>
39 #include <sfx2/docfile.hxx>
40 #include <pam.hxx>
41 #include <doc.hxx>
42 #include <docfunc.hxx>
43 #include <IDocumentRedlineAccess.hxx>
44 #include <IDocumentStatistics.hxx>
45 #include <IDocumentLayoutAccess.hxx>
46 #include <docstat.hxx>
47 #include <docsh.hxx>
49 #include <unotools/ucbstreamhelper.hxx>
50 #include <swerror.h>
51 #include <wrtxml.hxx>
52 #include <statstr.hrc>
54 #include <comphelper/documentconstants.hxx>
55 #include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::container;
60 using namespace ::com::sun::star::document;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::lang;
64 SwXMLWriter::SwXMLWriter( const OUString& rBaseURL )
66 SetBaseURL( rBaseURL );
69 SwXMLWriter::~SwXMLWriter()
73 sal_uInt32 SwXMLWriter::Write_( const uno::Reference < task::XStatusIndicator >& xStatusIndicator,
74 const OUString& aDocHierarchicalName )
76 // Get service factory
77 uno::Reference< uno::XComponentContext > xContext =
78 comphelper::getProcessComponentContext();
80 // Get data sink ...
81 uno::Reference< io::XOutputStream > xOut;
82 tools::SvRef<SotStorageStream> xDocStream;
83 uno::Reference< document::XGraphicObjectResolver > xGraphicResolver;
84 SvXMLGraphicHelper *pGraphicHelper = nullptr;
85 uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
86 SvXMLEmbeddedObjectHelper *pObjectHelper = nullptr;
88 OSL_ENSURE( xStg.is(), "Where is my storage?" );
89 pGraphicHelper = SvXMLGraphicHelper::Create( xStg,
90 GRAPHICHELPER_MODE_WRITE,
91 false );
92 xGraphicResolver = pGraphicHelper;
94 SfxObjectShell *pPersist = pDoc->GetPersist();
95 if( pPersist )
97 pObjectHelper = SvXMLEmbeddedObjectHelper::Create(
98 xStg, *pPersist,
99 EMBEDDEDOBJECTHELPER_MODE_WRITE,
100 false );
101 xObjectResolver = pObjectHelper;
104 // create and prepare the XPropertySet that gets passed through
105 // the components, and the XStatusIndicator that shows progress to
106 // the user.
108 // create XPropertySet with three properties for status indicator
109 comphelper::PropertyMapEntry const aInfoMap[] =
111 { OUString("ProgressRange"), 0,
112 ::cppu::UnoType<sal_Int32>::get(),
113 beans::PropertyAttribute::MAYBEVOID, 0},
114 { OUString("ProgressMax"), 0,
115 ::cppu::UnoType<sal_Int32>::get(),
116 beans::PropertyAttribute::MAYBEVOID, 0},
117 { OUString("ProgressCurrent"), 0,
118 ::cppu::UnoType<sal_Int32>::get(),
119 beans::PropertyAttribute::MAYBEVOID, 0},
120 { OUString("WrittenNumberStyles"), 0,
121 cppu::UnoType<uno::Sequence<sal_Int32>>::get(),
122 beans::PropertyAttribute::MAYBEVOID, 0},
123 { OUString("UsePrettyPrinting"), 0,
124 cppu::UnoType<bool>::get(),
125 beans::PropertyAttribute::MAYBEVOID, 0},
126 { OUString("ShowChanges"), 0,
127 cppu::UnoType<bool>::get(),
128 beans::PropertyAttribute::MAYBEVOID, 0 },
129 { OUString("RedlineProtectionKey"), 0,
130 cppu::UnoType<Sequence<sal_Int8>>::get(),
131 beans::PropertyAttribute::MAYBEVOID, 0 },
132 { OUString("BaseURI"), 0,
133 ::cppu::UnoType<OUString>::get(),
134 beans::PropertyAttribute::MAYBEVOID, 0 },
135 { OUString("StreamRelPath"), 0,
136 ::cppu::UnoType<OUString>::get(),
137 beans::PropertyAttribute::MAYBEVOID, 0 },
138 { OUString("StreamName"), 0,
139 ::cppu::UnoType<OUString>::get(),
140 beans::PropertyAttribute::MAYBEVOID, 0 },
141 { OUString("AutoTextMode"), 0,
142 cppu::UnoType<bool>::get(),
143 beans::PropertyAttribute::MAYBEVOID, 0 },
144 { OUString("StyleNames"), 0,
145 cppu::UnoType<Sequence<OUString>>::get(),
146 beans::PropertyAttribute::MAYBEVOID, 0 },
147 { OUString("StyleFamilies"), 0,
148 cppu::UnoType<Sequence<sal_Int32>>::get(),
149 beans::PropertyAttribute::MAYBEVOID, 0 },
150 // #i69627#
151 { OUString("OutlineStyleAsNormalListStyle"), 0,
152 cppu::UnoType<bool>::get(),
153 beans::PropertyAttribute::MAYBEVOID, 0 },
154 { OUString("TargetStorage"),0, cppu::UnoType<embed::XStorage>::get(),
155 css::beans::PropertyAttribute::MAYBEVOID, 0 },
156 { OUString(), 0, css::uno::Type(), 0, 0 }
158 uno::Reference< beans::XPropertySet > xInfoSet(
159 comphelper::GenericPropertySet_CreateInstance(
160 new comphelper::PropertySetInfo( aInfoMap ) ) );
162 xInfoSet->setPropertyValue( "TargetStorage", Any( xStg ) );
164 uno::Any aAny;
165 if (bShowProgress)
167 // set progress range and start status indicator
168 sal_Int32 nProgressRange(1000000);
169 if (xStatusIndicator.is())
171 xStatusIndicator->start(SW_RESSTR( STR_STATSTR_SWGWRITE),
172 nProgressRange);
174 xInfoSet->setPropertyValue("ProgressRange", Any(nProgressRange));
176 xInfoSet->setPropertyValue("ProgressMax", Any(static_cast < sal_Int32 >( -1 )));
179 SvtSaveOptions aSaveOpt;
180 xInfoSet->setPropertyValue( "UsePrettyPrinting", makeAny(aSaveOpt.IsPrettyPrinting()) );
182 // save show redline mode ...
183 const OUString sShowChanges("ShowChanges");
184 sal_uInt16 nRedlineMode = pDoc->getIDocumentRedlineAccess().GetRedlineMode();
185 xInfoSet->setPropertyValue( sShowChanges,
186 makeAny( IDocumentRedlineAccess::IsShowChanges( nRedlineMode ) ) );
187 // ... and hide redlines for export
188 nRedlineMode &= ~nsRedlineMode_t::REDLINE_SHOW_MASK;
189 nRedlineMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT;
190 pDoc->getIDocumentRedlineAccess().SetRedlineMode((RedlineMode_t)( nRedlineMode ));
192 // Set base URI
193 xInfoSet->setPropertyValue( "BaseURI", makeAny( GetBaseURL() ) );
195 if( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocShell()->GetCreateMode() )
197 const OUString aName( !aDocHierarchicalName.isEmpty()
198 ? aDocHierarchicalName
199 : OUString( "dummyObjectName" ) );
201 xInfoSet->setPropertyValue( "StreamRelPath", makeAny( aName ) );
204 if( bBlock )
206 xInfoSet->setPropertyValue( "AutoTextMode", makeAny(true) );
209 // #i69627#
210 const bool bOASIS = ( SotStorage::GetVersion( xStg ) > SOFFICE_FILEFORMAT_60 );
211 if ( bOASIS &&
212 docfunc::HasOutlineStyleToBeWrittenAsNormalListStyle( *pDoc ) )
214 xInfoSet->setPropertyValue( "OutlineStyleAsNormalListStyle", makeAny( true ) );
217 // filter arguments
218 // - graphics + object resolver for styles + content
219 // - status indicator
220 // - info property set
221 // - else empty
222 sal_Int32 nArgs = 1;
223 if( xStatusIndicator.is() )
224 nArgs++;
226 Sequence < Any > aEmptyArgs( nArgs );
227 Any *pArgs = aEmptyArgs.getArray();
228 *pArgs++ <<= xInfoSet;
229 if( xStatusIndicator.is() )
230 *pArgs++ <<= xStatusIndicator;
232 if( xGraphicResolver.is() )
233 nArgs++;
234 if( xObjectResolver.is() )
235 nArgs++;
237 Sequence < Any > aFilterArgs( nArgs );
238 pArgs = aFilterArgs.getArray();
239 *pArgs++ <<= xInfoSet;
240 if( xGraphicResolver.is() )
241 *pArgs++ <<= xGraphicResolver;
242 if( xObjectResolver.is() )
243 *pArgs++ <<= xObjectResolver;
244 if( xStatusIndicator.is() )
245 *pArgs++ <<= xStatusIndicator;
247 //Get model
248 uno::Reference< lang::XComponent > xModelComp(
249 pDoc->GetDocShell()->GetModel(), UNO_QUERY );
250 OSL_ENSURE( xModelComp.is(), "XMLWriter::Write: got no model" );
251 if( !xModelComp.is() )
252 return ERR_SWG_WRITE_ERROR;
254 PutNumFormatFontsInAttrPool();
255 PutEditEngFontsInAttrPool();
257 // properties
258 Sequence < PropertyValue > aProps( pOrigFileName ? 1 : 0 );
259 if( pOrigFileName )
261 PropertyValue *pProps = aProps.getArray();
262 pProps->Name = "FileName";
263 pProps->Value <<= *pOrigFileName;
266 // export sub streams for package, else full stream into a file
267 bool bWarn = false;
269 // RDF metadata: export if ODF >= 1.2
270 // N.B.: embedded documents have their own manifest.rdf!
271 if ( bOASIS )
273 const uno::Reference<beans::XPropertySet> xPropSet(xStg,
274 uno::UNO_QUERY_THROW);
277 OUString Version;
278 // ODF >= 1.2
279 if ((xPropSet->getPropertyValue("Version") >>= Version)
280 && Version != ODFVER_010_TEXT
281 && Version != ODFVER_011_TEXT)
283 const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(
284 xModelComp, uno::UNO_QUERY_THROW);
285 xDMA->storeMetadataToStorage(xStg);
288 catch (beans::UnknownPropertyException &)
289 { /* ignore */ }
290 catch (uno::Exception &)
292 bWarn = true;
296 bool bStoreMeta = ( SfxObjectCreateMode::EMBEDDED != pDoc->GetDocShell()->GetCreateMode() );
297 if ( !bStoreMeta )
301 Reference< frame::XModule > xModule( xModelComp, UNO_QUERY );
302 if ( xModule.is() )
304 const OUString aModuleID = xModule->getIdentifier();
305 bStoreMeta = !aModuleID.isEmpty() &&
306 ( aModuleID == "com.sun.star.sdb.FormDesign" ||
307 aModuleID == "com.sun.star.sdb.TextReportDesign" );
310 catch( uno::Exception& )
314 OUString sWarnFile;
315 if( !bOrganizerMode && !bBlock && bStoreMeta )
317 if( !WriteThroughComponent(
318 xModelComp, "meta.xml", xContext,
319 (bOASIS ? "com.sun.star.comp.Writer.XMLOasisMetaExporter"
320 : "com.sun.star.comp.Writer.XMLMetaExporter"),
321 aEmptyArgs, aProps ) )
323 bWarn = true;
324 sWarnFile = "meta.xml";
328 if( !bBlock )
330 if( !WriteThroughComponent(
331 xModelComp, "settings.xml", xContext,
332 (bOASIS ? "com.sun.star.comp.Writer.XMLOasisSettingsExporter"
333 : "com.sun.star.comp.Writer.XMLSettingsExporter"),
334 aEmptyArgs, aProps ) )
336 if( !bWarn )
338 bWarn = true;
339 sWarnFile = "settings.xml";
344 bool bErr = false;
346 OUString sErrFile;
347 if( !WriteThroughComponent(
348 xModelComp, "styles.xml", xContext,
349 (bOASIS ? "com.sun.star.comp.Writer.XMLOasisStylesExporter"
350 : "com.sun.star.comp.Writer.XMLStylesExporter"),
351 aFilterArgs, aProps ) )
353 bErr = true;
354 sErrFile = "styles.xml";
357 if( !bOrganizerMode && !bErr )
359 if( !WriteThroughComponent(
360 xModelComp, "content.xml", xContext,
361 (bOASIS ? "com.sun.star.comp.Writer.XMLOasisContentExporter"
362 : "com.sun.star.comp.Writer.XMLContentExporter"),
363 aFilterArgs, aProps ) )
365 bErr = true;
366 sErrFile = "content.xml";
370 if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && pDoc->getIDocumentStatistics().GetDocStat().nPage > 1 &&
371 !(bOrganizerMode || bBlock || bErr) )
375 uno::Reference < io::XStream > xStm = xStg->openStreamElement( "layout-cache", embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
376 SvStream* pStream = utl::UcbStreamHelper::CreateStream( xStm );
377 if( !pStream->GetError() )
379 uno::Reference < beans::XPropertySet > xSet( xStm, UNO_QUERY );
380 uno::Any aAny2;
381 aAny2 <<= OUString("application/binary");
382 xSet->setPropertyValue("MediaType", aAny2 );
383 pDoc->WriteLayoutCache( *pStream );
386 delete pStream;
388 catch ( uno::Exception& )
393 if( pGraphicHelper )
394 SvXMLGraphicHelper::Destroy( pGraphicHelper );
395 xGraphicResolver = nullptr;
397 if( pObjectHelper )
398 SvXMLEmbeddedObjectHelper::Destroy( pObjectHelper );
399 xObjectResolver = nullptr;
401 // restore redline mode
402 aAny = xInfoSet->getPropertyValue( sShowChanges );
403 nRedlineMode = pDoc->getIDocumentRedlineAccess().GetRedlineMode();
404 nRedlineMode &= ~nsRedlineMode_t::REDLINE_SHOW_MASK;
405 nRedlineMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT;
406 if ( *o3tl::doAccess<bool>(aAny) )
407 nRedlineMode |= nsRedlineMode_t::REDLINE_SHOW_DELETE;
408 pDoc->getIDocumentRedlineAccess().SetRedlineMode((RedlineMode_t)( nRedlineMode ));
410 if (xStatusIndicator.is())
412 xStatusIndicator->end();
415 if( bErr )
417 if( !sErrFile.isEmpty() )
418 return *new StringErrorInfo( ERR_WRITE_ERROR_FILE, sErrFile,
419 ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR );
420 return ERR_SWG_WRITE_ERROR;
422 else if( bWarn )
424 if( !sWarnFile.isEmpty() )
425 return *new StringErrorInfo( WARN_WRITE_ERROR_FILE, sWarnFile,
426 ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR );
427 return WARN_SWG_FEATURES_LOST;
430 return 0;
433 sal_uLong SwXMLWriter::WriteStorage()
435 return Write_( uno::Reference < task::XStatusIndicator >(), OUString() );
438 sal_uLong SwXMLWriter::WriteMedium( SfxMedium& aTargetMedium )
440 uno::Reference < task::XStatusIndicator > xStatusIndicator;
441 OUString aName;
442 const SfxUnoAnyItem* pStatusBarItem = static_cast<const SfxUnoAnyItem*>(
443 aTargetMedium.GetItemSet()->GetItem(SID_PROGRESS_STATUSBAR_CONTROL) );
444 if ( pStatusBarItem )
445 pStatusBarItem->GetValue() >>= xStatusIndicator;
446 const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
447 aTargetMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
448 if ( pDocHierarchItem )
449 aName = pDocHierarchItem->GetValue();
451 return Write_( xStatusIndicator, aName );
454 sal_uLong SwXMLWriter::Write( SwPaM& rPaM, SfxMedium& rMed,
455 const OUString* pFileName )
457 return IsStgWriter()
458 ? static_cast<StgWriter *>(this)->Write( rPaM, rMed.GetOutputStorage(), pFileName, &rMed )
459 : static_cast<Writer *>(this)->Write( rPaM, *rMed.GetOutStream(), pFileName );
462 bool SwXMLWriter::WriteThroughComponent(
463 const uno::Reference<XComponent> & xComponent,
464 const sal_Char* pStreamName,
465 const uno::Reference<uno::XComponentContext> & rxContext,
466 const sal_Char* pServiceName,
467 const Sequence<Any> & rArguments,
468 const Sequence<beans::PropertyValue> & rMediaDesc )
470 OSL_ENSURE( xStg.is(), "Need storage!" );
471 OSL_ENSURE( nullptr != pStreamName, "Need stream name!" );
472 OSL_ENSURE( nullptr != pServiceName, "Need service name!" );
474 SAL_INFO( "sw.filter", "SwXMLWriter::WriteThroughComponent : stream " << pStreamName );
475 // open stream
476 bool bRet = false;
479 const OUString sStreamName = OUString::createFromAscii( pStreamName );
480 uno::Reference<io::XStream> xStream =
481 xStg->openStreamElement( sStreamName,
482 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
484 uno::Reference <beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
485 if( !xSet.is() )
486 return false;
488 xSet->setPropertyValue("MediaType", Any(OUString("text/xml")) );
490 // even plain stream should be encrypted in encrypted documents
491 xSet->setPropertyValue( "UseCommonStoragePasswordEncryption", makeAny(true) );
493 // set buffer and create outputstream
494 uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
496 // set Base URL
497 uno::Reference< beans::XPropertySet > xInfoSet;
498 if( rArguments.getLength() > 0 )
499 rArguments.getConstArray()[0] >>= xInfoSet;
500 OSL_ENSURE( xInfoSet.is(), "missing property set" );
501 if( xInfoSet.is() )
503 xInfoSet->setPropertyValue( "StreamName", makeAny( sStreamName ) );
506 // write the stuff
507 bRet = WriteThroughComponent(
508 xOutputStream, xComponent, rxContext,
509 pServiceName, rArguments, rMediaDesc );
511 catch ( uno::Exception& )
515 return bRet;
519 bool SwXMLWriter::WriteThroughComponent(
520 const uno::Reference<io::XOutputStream> & xOutputStream,
521 const uno::Reference<XComponent> & xComponent,
522 const uno::Reference<XComponentContext> & rxContext,
523 const sal_Char* pServiceName,
524 const Sequence<Any> & rArguments,
525 const Sequence<PropertyValue> & rMediaDesc )
527 OSL_ENSURE( xOutputStream.is(), "I really need an output stream!" );
528 OSL_ENSURE( xComponent.is(), "Need component!" );
529 OSL_ENSURE( nullptr != pServiceName, "Need component name!" );
531 // get component
532 uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(rxContext);
533 SAL_INFO( "sw.filter", "SAX-Writer created" );
534 // connect XML writer to output stream
535 xSaxWriter->setOutputStream( xOutputStream );
537 // prepare arguments (prepend doc handler to given arguments)
538 uno::Reference<xml::sax::XDocumentHandler> xDocHandler( xSaxWriter,UNO_QUERY);
539 Sequence<Any> aArgs( 1 + rArguments.getLength() );
540 aArgs[0] <<= xDocHandler;
541 for(sal_Int32 i = 0; i < rArguments.getLength(); i++)
542 aArgs[i+1] = rArguments[i];
544 // get filter component
545 uno::Reference< document::XExporter > xExporter(
546 rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
547 OUString::createFromAscii(pServiceName), aArgs, rxContext), UNO_QUERY);
548 OSL_ENSURE( xExporter.is(),
549 "can't instantiate export filter component" );
550 if( !xExporter.is() )
551 return false;
552 SAL_INFO( "sw.filter", pServiceName << " instantiated." );
553 // connect model and filter
554 xExporter->setSourceDocument( xComponent );
556 // filter!
557 SAL_INFO( "sw.filter", "call filter()" );
558 uno::Reference<XFilter> xFilter( xExporter, UNO_QUERY );
559 return xFilter->filter( rMediaDesc );
562 void GetXMLWriter( const OUString& /*rName*/, const OUString& rBaseURL, WriterRef& xRet )
564 xRet = new SwXMLWriter( rBaseURL );
567 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */