tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / xmloff / source / style / xmlexppr.cxx
blob42170c371e4d723f744aea30aa55d961767e52e9
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 <memory>
21 #include <optional>
22 #include <string_view>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/xml/AttributeData.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/beans/XPropertyState.hpp>
27 #include <com/sun/star/beans/XMultiPropertySet.hpp>
28 #include <com/sun/star/beans/XTolerantMultiPropertySet.hpp>
29 #include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
30 #include <comphelper/anycompare.hxx>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <cppuhelper/weakref.hxx>
33 #include <osl/diagnose.h>
34 #include <list>
35 #include <map>
36 #include <o3tl/sorted_vector.hxx>
38 #include <utility>
39 #include <xmloff/xmlexppr.hxx>
40 #include <xmloff/xmltoken.hxx>
41 #include <xmloff/namespacemap.hxx>
42 #include <xmloff/xmlnamespace.hxx>
43 #include <xmloff/xmlexp.hxx>
44 #include <xmloff/xmlprmap.hxx>
45 #include <xmloff/maptype.hxx>
46 #include <xmloff/xmltypes.hxx>
47 #include <xmloff/xmlprhdl.hxx>
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::beans;
51 using namespace ::com::sun::star::uno;
52 using namespace ::xmloff::token;
54 #define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT)
56 namespace {
58 struct XMLPropTokens_Impl
60 sal_uInt16 nType;
61 XMLTokenEnum eToken;
64 const sal_uInt16 MAX_PROP_TYPES =
65 (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) -
66 (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT);
68 XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] =
70 { GET_PROP_TYPE(XML_TYPE_PROP_CHART), XML_CHART_PROPERTIES },
71 { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC), XML_GRAPHIC_PROPERTIES },
72 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE), XML_TABLE_PROPERTIES },
73 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN), XML_TABLE_COLUMN_PROPERTIES },
74 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW), XML_TABLE_ROW_PROPERTIES },
75 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL), XML_TABLE_CELL_PROPERTIES },
76 { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL), XML_LIST_LEVEL_PROPERTIES },
77 { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH), XML_PARAGRAPH_PROPERTIES },
78 { GET_PROP_TYPE(XML_TYPE_PROP_TEXT), XML_TEXT_PROPERTIES },
79 { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE), XML_DRAWING_PAGE_PROPERTIES },
80 { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT), XML_PAGE_LAYOUT_PROPERTIES },
81 { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER), XML_HEADER_FOOTER_PROPERTIES },
82 { GET_PROP_TYPE(XML_TYPE_PROP_RUBY), XML_RUBY_PROPERTIES },
83 { GET_PROP_TYPE(XML_TYPE_PROP_SECTION), XML_SECTION_PROPERTIES }
86 // public methods
88 // Take all properties of the XPropertySet which are also found in the
89 // XMLPropertyMapEntry-array and which are not set to their default-value,
90 // if a state is available.
91 // After that I call the method 'ContextFilter'.
93 struct ComparePropertyState
95 bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs)
97 return lhs.mnIndex < rhs.mnIndex;
100 class XMLPropertyStates_Impl
102 o3tl::sorted_vector<XMLPropertyState, ComparePropertyState> aPropStates;
103 public:
104 XMLPropertyStates_Impl();
105 void AddPropertyState(const XMLPropertyState& rPropState);
106 void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector);
109 XMLPropertyStates_Impl::XMLPropertyStates_Impl()
113 void XMLPropertyStates_Impl::AddPropertyState(
114 const XMLPropertyState& rPropState)
116 aPropStates.insert(rPropState);
119 void XMLPropertyStates_Impl::FillPropertyStateVector(
120 std::vector<XMLPropertyState>& rVector)
122 rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() );
125 class FilterPropertyInfo_Impl
127 OUString msApiName;
128 std::vector<sal_uInt32> maIndexes;
130 public:
132 FilterPropertyInfo_Impl( OUString aApiName,
133 const sal_uInt32 nIndex);
135 const OUString& GetApiName() const { return msApiName; }
136 std::vector<sal_uInt32>& GetIndexes() { return maIndexes; }
138 // for sort
139 bool operator< ( const FilterPropertyInfo_Impl& rArg ) const
141 return (GetApiName() < rArg.GetApiName());
145 FilterPropertyInfo_Impl::FilterPropertyInfo_Impl(
146 OUString aApiName,
147 const sal_uInt32 nIndex ) :
148 msApiName(std::move( aApiName ))
150 maIndexes.push_back(nIndex);
153 typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl;
155 class FilterPropertiesInfo_Impl
157 FilterPropertyInfoList_Impl aPropInfos;
159 std::optional<Sequence<OUString>> mxApiNames;
161 public:
162 FilterPropertiesInfo_Impl();
164 void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex);
165 const uno::Sequence<OUString>& GetApiNames();
166 void FillPropertyStateArray(
167 std::vector< XMLPropertyState >& rPropStates,
168 const Reference< XPropertySet >& xPropSet,
169 const rtl::Reference< XMLPropertySetMapper >& maPropMapper,
170 const bool bDefault);
171 sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); }
174 FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl()
178 void FilterPropertiesInfo_Impl::AddProperty(
179 const OUString& rApiName, const sal_uInt32 nIndex)
181 aPropInfos.emplace_back(rApiName, nIndex);
183 OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" );
184 mxApiNames.reset();
187 const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames()
189 if( !mxApiNames )
191 // we have to do three things:
192 // 1) sort API names,
193 // 2) merge duplicates,
194 // 3) construct sequence
196 // sort names
197 aPropInfos.sort();
199 // merge duplicates
200 if ( aPropInfos.size() > 1 )
202 FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin();
203 FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end();
204 FilterPropertyInfoList_Impl::iterator aCurrent = aOld;
205 ++aCurrent;
207 while ( aCurrent != aEnd )
209 // equal to next element?
210 if ( aOld->GetApiName() == aCurrent->GetApiName() )
212 // if equal: merge index lists
213 std::vector<sal_uInt32> aMerged;
214 std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(),
215 aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(),
216 std::back_inserter(aMerged));
217 aOld->GetIndexes() = std::move(aMerged);
218 aCurrent->GetIndexes().clear();
219 // erase element, and continue with next
220 aCurrent = aPropInfos.erase( aCurrent );
222 else
224 // remember old element and continue with next
225 aOld = aCurrent;
226 ++aCurrent;
231 // construct sequence
232 mxApiNames.emplace( aPropInfos.size() );
233 OUString *pNames = mxApiNames->getArray();
235 for (auto const& propInfo : aPropInfos)
237 *pNames = propInfo.GetApiName();
238 ++pNames;
242 return *mxApiNames;
245 void FilterPropertiesInfo_Impl::FillPropertyStateArray(
246 std::vector< XMLPropertyState >& rPropStates,
247 const Reference< XPropertySet >& rPropSet,
248 const rtl::Reference< XMLPropertySetMapper >& rPropMapper,
249 const bool bDefault )
251 XMLPropertyStates_Impl aPropStates;
253 const uno::Sequence<OUString>& rApiNames = GetApiNames();
255 Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY );
256 if (xTolPropSet.is())
258 if (!bDefault)
260 Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames));
261 sal_Int32 nResultCount(aResults.getLength());
262 if (nResultCount > 0)
264 const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray();
265 FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
266 XMLPropertyState aNewProperty( -1 );
267 while (nResultCount > 0 && aPropIter != aPropInfos.end())
269 if (pResults->Name == aPropIter->GetApiName())
271 aNewProperty.mnIndex = -1;
272 aNewProperty.maValue = pResults->Value;
274 for (auto const& index : aPropIter->GetIndexes())
276 aNewProperty.mnIndex = index;
277 aPropStates.AddPropertyState( aNewProperty );
279 ++pResults;
280 --nResultCount;
282 ++aPropIter;
286 else
288 const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames));
289 OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" );
290 FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
291 XMLPropertyState aNewProperty( -1 );
292 OSL_ENSURE( aPropInfos.size() == static_cast<sal_uInt32>(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" );
293 for( const auto& rResult : aResults )
295 if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) &&
296 ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE)))
298 aNewProperty.mnIndex = -1;
299 aNewProperty.maValue = rResult.Value;
301 for (auto const& index : aPropIter->GetIndexes())
303 aNewProperty.mnIndex = index;
304 aPropStates.AddPropertyState( aNewProperty );
307 ++aPropIter;
311 else
313 Sequence < PropertyState > aStates;
314 const PropertyState *pStates = nullptr;
315 Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY );
316 if( xPropState.is() )
318 aStates = xPropState->getPropertyStates( rApiNames );
319 pStates = aStates.getConstArray();
322 Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY );
323 if( xMultiPropSet.is() && !bDefault )
325 Sequence < Any > aValues;
326 if( pStates )
328 // step 1: get value count
329 sal_uInt32 nValueCount = 0;
331 for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates)
333 if( *pStates == PropertyState_DIRECT_VALUE )
334 nValueCount++;
337 if( nValueCount )
339 // step 2: collect property names
340 Sequence < OUString > aAPINames( nValueCount );
341 OUString *pAPINames = aAPINames.getArray();
343 ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters;
344 aPropIters.reserve( nValueCount );
346 FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
347 OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!");
349 pStates = aStates.getConstArray();
350 sal_uInt32 i = 0;
351 while( i < nValueCount )
353 if( *pStates == PropertyState_DIRECT_VALUE )
355 *pAPINames++ = aItr->GetApiName();
356 aPropIters.push_back( aItr );
357 ++i;
359 ++aItr;
360 ++pStates;
363 aValues = xMultiPropSet->getPropertyValues( aAPINames );
364 const Any *pValues = aValues.getConstArray();
366 ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator
367 pPropIter = aPropIters.begin();
369 XMLPropertyState aNewProperty( -1 );
370 for( i = 0; i < nValueCount; ++i )
372 aNewProperty.mnIndex = -1;
373 aNewProperty.maValue = *pValues;
375 for (auto const& index : (*pPropIter)->GetIndexes())
377 aNewProperty.mnIndex = index;
378 aPropStates.AddPropertyState( aNewProperty );
381 ++pPropIter;
382 ++pValues;
386 else
388 aValues = xMultiPropSet->getPropertyValues( rApiNames );
389 const Any *pValues = aValues.getConstArray();
391 FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
392 for (size_t i = 0; i < aPropInfos.size(); ++i)
394 // The value is stored in the PropertySet itself, add to list.
395 XMLPropertyState aNewProperty( -1 );
396 aNewProperty.maValue = *pValues;
397 ++pValues;
398 for (auto const& index : aItr->GetIndexes())
400 aNewProperty.mnIndex = index;
401 aPropStates.AddPropertyState( aNewProperty );
403 ++aItr;
407 else
409 FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
410 for (size_t i = 0; i < aPropInfos.size(); ++i)
412 bool bDirectValue =
413 !pStates || *pStates == PropertyState_DIRECT_VALUE;
414 if( bDirectValue || bDefault )
416 // The value is stored in the PropertySet itself, add to list.
417 bool bGotValue = false;
418 XMLPropertyState aNewProperty( -1 );
419 for (auto const& index : aItr->GetIndexes())
421 if( bDirectValue ||
422 (rPropMapper->GetEntryFlags(index) &
423 MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 )
427 if( !bGotValue )
429 aNewProperty.maValue =
430 rPropSet->getPropertyValue( aItr->GetApiName() );
431 bGotValue = true;
433 aNewProperty.mnIndex = index;
434 aPropStates.AddPropertyState( aNewProperty );
436 catch( UnknownPropertyException& )
438 // might be a problem of getImplementationId
439 TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyValue" );
446 ++aItr;
447 if( pStates )
448 ++pStates;
452 aPropStates.FillPropertyStateVector(rPropStates);
457 struct SvXMLExportPropertyMapper::Impl
459 typedef std::map<css::uno::Reference<css::beans::XPropertySetInfo>, std::unique_ptr<FilterPropertiesInfo_Impl>> CacheType;
460 CacheType maCache;
462 rtl::Reference<SvXMLExportPropertyMapper> mxNextMapper;
463 rtl::Reference<XMLPropertySetMapper> mxPropMapper;
465 OUString maStyleName;
468 // ctor/dtor , class SvXMLExportPropertyMapper
470 SvXMLExportPropertyMapper::SvXMLExportPropertyMapper(
471 const rtl::Reference< XMLPropertySetMapper >& rMapper ) :
472 mpImpl(new Impl)
474 mpImpl->mxPropMapper = rMapper;
477 SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper()
481 void SvXMLExportPropertyMapper::ChainExportMapper(
482 const rtl::Reference< SvXMLExportPropertyMapper>& rMapper )
484 // add map entries from rMapper to current map
485 mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() );
486 // rMapper uses the same map as 'this'
487 rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper;
489 // set rMapper as last mapper in current chain
490 rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper;
491 if( xNext.is())
493 while (xNext->mpImpl->mxNextMapper.is())
494 xNext = xNext->mpImpl->mxNextMapper;
495 xNext->mpImpl->mxNextMapper = rMapper;
497 else
498 mpImpl->mxNextMapper = rMapper;
500 // if rMapper was already chained, correct
501 // map pointer of successors
502 xNext = rMapper;
504 while (xNext->mpImpl->mxNextMapper.is())
506 xNext = xNext->mpImpl->mxNextMapper;
507 xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper;
511 std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter(
512 SvXMLExport const& rExport,
513 const uno::Reference<beans::XPropertySet>& rPropSet, bool bEnableFoFontFamily ) const
515 return Filter_(rExport, rPropSet, false, bEnableFoFontFamily);
518 std::vector<XMLPropertyState> SvXMLExportPropertyMapper::FilterDefaults(
519 SvXMLExport const& rExport,
520 const uno::Reference<beans::XPropertySet>& rPropSet ) const
522 return Filter_(rExport, rPropSet, true, false/*bEnableFoFontFamily*/);
525 std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter_(
526 SvXMLExport const& rExport,
527 const Reference<XPropertySet>& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const
529 std::vector< XMLPropertyState > aPropStateArray;
531 // Retrieve XPropertySetInfo and XPropertyState
532 Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
533 if( !xInfo.is() )
534 return aPropStateArray;
536 sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount();
538 FilterPropertiesInfo_Impl *pFilterInfo = nullptr;
540 Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo);
541 if (aIter != mpImpl->maCache.end())
542 pFilterInfo = (*aIter).second.get();
544 bool bDelInfo = false;
545 if( !pFilterInfo )
547 assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN);
548 const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion());
549 pFilterInfo = new FilterPropertiesInfo_Impl;
550 for( sal_Int32 i=0; i < nProps; i++ )
552 // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..)
553 // Does the PropertySet contain name of mpEntries-array ?
554 const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i );
555 const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i );
556 if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) &&
557 ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) ||
558 xInfo->hasPropertyByName( rAPIName ) ) )
560 const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport(
561 mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i));
562 // note: only standard ODF versions are allowed here,
563 // only exception is the unknown future
564 assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0
565 || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
566 static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
567 /// standard ODF namespaces for elements and attributes
568 static sal_uInt16 s_OdfNs[] = {
569 XML_NAMESPACE_OFFICE,
570 XML_NAMESPACE_STYLE,
571 XML_NAMESPACE_TEXT,
572 XML_NAMESPACE_TABLE,
573 XML_NAMESPACE_DRAW,
574 XML_NAMESPACE_FO,
575 XML_NAMESPACE_XLINK,
576 XML_NAMESPACE_DC,
577 XML_NAMESPACE_META,
578 XML_NAMESPACE_NUMBER,
579 XML_NAMESPACE_PRESENTATION,
580 XML_NAMESPACE_SVG,
581 XML_NAMESPACE_CHART,
582 XML_NAMESPACE_DR3D,
583 XML_NAMESPACE_MATH,
584 XML_NAMESPACE_FORM,
585 XML_NAMESPACE_SCRIPT,
586 XML_NAMESPACE_CONFIG,
587 XML_NAMESPACE_DB,
588 XML_NAMESPACE_XFORMS,
589 XML_NAMESPACE_SMIL,
590 XML_NAMESPACE_ANIMATION,
591 XML_NAMESPACE_XML,
592 XML_NAMESPACE_XHTML,
593 XML_NAMESPACE_GRDDL,
595 static bool s_Assert(false);
596 if (!s_Assert)
598 assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
599 s_Assert = true;
601 //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
602 auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i));
603 auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs),
604 ns));
605 bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns
606 // FIXME: very special hack to suppress style:hyperlink
607 || (ns == XML_NAMESPACE_STYLE
608 && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK)));
609 if (isExtension
610 ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED)
611 // if it's in standard ODF, don't export extension
612 && (nCurrentVersion < nEarliestODFVersionForExport))
613 : (nEarliestODFVersionForExport <= nCurrentVersion))
615 pFilterInfo->AddProperty(rAPIName, i);
620 // Check whether the property set info is destroyed if it is assigned to
621 // a weak reference only; If it is destroyed, then every instance of
622 // getPropertySetInfo returns a new object; such property set infos must
623 // not be cached:
624 WeakReference < XPropertySetInfo > xWeakInfo( xInfo );
625 xInfo.clear();
626 xInfo = xWeakInfo;
627 if( xInfo.is() )
629 mpImpl->maCache.emplace(xInfo, std::unique_ptr<FilterPropertiesInfo_Impl>(pFilterInfo));
631 else
632 bDelInfo = true;
635 if( pFilterInfo->GetPropertyCount() )
639 pFilterInfo->FillPropertyStateArray(
640 aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault);
642 catch( UnknownPropertyException& )
644 // might be a problem of getImplementationId
645 TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyStates" );
649 // Call context-filter
650 if( !aPropStateArray.empty() )
651 ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet);
653 // Have to do if we change from a vector to a list or something like that
655 if( bDelInfo )
656 delete pFilterInfo;
658 return aPropStateArray;
661 void SvXMLExportPropertyMapper::ContextFilter(
662 bool bEnableFoFontFamily,
663 std::vector< XMLPropertyState >& rProperties,
664 const Reference< XPropertySet >& rPropSet ) const
666 // Derived class could implement this.
667 if (mpImpl->mxNextMapper.is())
668 mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet);
671 // Compares two Sequences of XMLPropertyState:
672 // 1.Number of elements equal ?
673 // 2.Index of each element equal ? (So I know whether the propertynames are the same)
674 // 3.Value of each element equal ?
675 bool SvXMLExportPropertyMapper::Equals(
676 const std::vector< XMLPropertyState >& aProperties1,
677 const std::vector< XMLPropertyState >& aProperties2 ) const
679 if (aProperties1.size() < aProperties2.size())
680 return true;
681 if (aProperties1.size() > aProperties2.size())
682 return false;
684 sal_uInt32 nCount = aProperties1.size();
686 for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
688 const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
689 const XMLPropertyState& rProp2 = aProperties2[ nIndex ];
691 // Compare index. If equal, compare value
692 if( rProp1.mnIndex < rProp2.mnIndex )
693 return true;
694 if( rProp1.mnIndex > rProp2.mnIndex )
695 return false;
697 if( rProp1.mnIndex != -1 )
699 // Now compare values
700 if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
701 XML_TYPE_BUILDIN_CMP ) != 0 )
703 // simple type ( binary compare )
704 if ( rProp1.maValue != rProp2.maValue)
705 return false;
707 else
709 // complex type ( ask for compare-function )
710 if (!mpImpl->mxPropMapper->GetPropertyHandler(
711 rProp1.mnIndex )->equals( rProp1.maValue,
712 rProp2.maValue ))
713 return false;
718 return true;
721 // Compares two Sequences of XMLPropertyState:
722 // 1.Number of elements equal ?
723 // 2.Index of each element equal ? (So I know whether the propertynames are the same)
724 // 3.Value of each element equal ?
725 bool SvXMLExportPropertyMapper::LessPartial(
726 const std::vector< XMLPropertyState >& aProperties1,
727 const std::vector< XMLPropertyState >& aProperties2 ) const
729 if (aProperties1.size() < aProperties2.size())
730 return true;
731 if (aProperties1.size() > aProperties2.size())
732 return false;
734 sal_uInt32 nCount = aProperties1.size();
736 for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
738 const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
739 const XMLPropertyState& rProp2 = aProperties2[ nIndex ];
741 // Compare index. If equal, compare value
742 if( rProp1.mnIndex < rProp2.mnIndex )
743 return true;
744 if( rProp1.mnIndex > rProp2.mnIndex )
745 return false;
747 if( rProp1.mnIndex != -1 )
749 // Now compare values
750 if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
751 XML_TYPE_BUILDIN_CMP ) != 0 )
753 // simple type ( binary compare )
754 if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) )
755 return true;
756 if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) )
757 return false;
762 return false;
765 /** fills the given attribute list with the items in the given set
766 void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
767 const ::std::vector< XMLPropertyState >& rProperties,
768 const SvXMLUnitConverter& rUnitConverter,
769 const SvXMLNamespaceMap& rNamespaceMap,
770 sal_uInt16 nFlags ) const
772 _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
773 nFlags, 0, -1, -1 );
776 void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
777 const ::std::vector< XMLPropertyState >& rProperties,
778 const SvXMLUnitConverter& rUnitConverter,
779 const SvXMLNamespaceMap& rNamespaceMap,
780 sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
781 sal_uInt16 nFlags ) const
783 _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
784 nFlags, 0, nPropMapStartIdx, nPropMapEndIdx );
788 void SvXMLExportPropertyMapper::exportXML(
789 SvXMLExport& rExport,
790 const ::std::vector< XMLPropertyState >& rProperties,
791 SvXmlExportFlags nFlags,
792 bool bUseExtensionNamespaceForGraphicProperties) const
794 exportXML(rExport, rProperties, -1, -1, nFlags, bUseExtensionNamespaceForGraphicProperties);
798 void SvXMLExportPropertyMapper::exportXML(
799 SvXMLExport& rExport,
800 const ::std::vector< XMLPropertyState >& rProperties,
801 sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
802 SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const
804 sal_uInt16 nPropTypeFlags = 0;
805 for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i )
807 sal_uInt16 nPropType = aPropTokens[i].nType;
808 if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 )
810 sal_uInt16 nNamespace = XML_NAMESPACE_STYLE;
811 if (bUseExtensionNamespaceForGraphicProperties &&
812 aPropTokens[i].eToken == xmloff::token::XML_GRAPHIC_PROPERTIES)
814 nNamespace = XML_NAMESPACE_LO_EXT;
815 if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
817 continue; // don't write for ODF <= 1.2
821 std::vector<sal_uInt16> aIndexArray;
823 _exportXML( nPropType, nPropTypeFlags,
824 rExport.GetAttrList(), rProperties,
825 rExport.GetMM100UnitConverter(),
826 rExport.GetNamespaceMap(),
827 &aIndexArray,
828 nPropMapStartIdx, nPropMapEndIdx );
830 if( rExport.GetAttrList().getLength() > 0 ||
831 !aIndexArray.empty() )
833 SvXMLElementExport aElem( rExport, nNamespace,
834 aPropTokens[i].eToken,
835 bool(nFlags & SvXmlExportFlags::IGN_WS),
836 false );
838 exportElementItems( rExport, rProperties, nFlags, aIndexArray );
844 /** this method is called for every item that has the
845 MID_FLAG_SPECIAL_ITEM_EXPORT flag set */
846 void SvXMLExportPropertyMapper::handleSpecialItem(
847 comphelper::AttributeList& rAttrList,
848 const XMLPropertyState& rProperty,
849 const SvXMLUnitConverter& rUnitConverter,
850 const SvXMLNamespaceMap& rNamespaceMap,
851 const ::std::vector< XMLPropertyState > *pProperties,
852 sal_uInt32 nIdx ) const
854 OSL_ENSURE(mpImpl->mxNextMapper.is(), "special item not handled in xml export");
855 if (mpImpl->mxNextMapper.is())
856 mpImpl->mxNextMapper->handleSpecialItem(
857 rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx);
860 /** this method is called for every item that has the
861 MID_FLAG_ELEMENT_EXPORT flag set */
862 void SvXMLExportPropertyMapper::handleElementItem(
863 SvXMLExport& rExport,
864 const XMLPropertyState& rProperty,
865 SvXmlExportFlags nFlags,
866 const ::std::vector< XMLPropertyState > *pProperties,
867 sal_uInt32 nIdx ) const
869 OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export");
870 if (mpImpl->mxNextMapper.is())
871 mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx);
874 // protected methods
876 /** fills the given attribute list with the items in the given set */
877 void SvXMLExportPropertyMapper::_exportXML(
878 sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags,
879 comphelper::AttributeList& rAttrList,
880 const ::std::vector< XMLPropertyState >& rProperties,
881 const SvXMLUnitConverter& rUnitConverter,
882 const SvXMLNamespaceMap& rNamespaceMap,
883 std::vector<sal_uInt16>* pIndexArray,
884 sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const
886 const sal_uInt32 nCount = rProperties.size();
887 sal_uInt32 nIndex = 0;
889 if( -1 == nPropMapStartIdx )
890 nPropMapStartIdx = 0;
891 if( -1 == nPropMapEndIdx )
892 nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount();
894 while( nIndex < nCount )
896 sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex;
897 if( nPropMapIdx >= nPropMapStartIdx &&
898 nPropMapIdx < nPropMapEndIdx )// valid entry?
900 sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx);
901 sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags);
902 OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT),
903 "no prop type specified");
904 rPropTypeFlags |= (1 << nEPType);
905 if( nEPType == nPropType )
907 // we have a valid map entry here, so let's use it...
908 if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 )
910 // element items do not add any properties,
911 // we export it later
912 if( pIndexArray )
914 pIndexArray->push_back( static_cast<sal_uInt16>(nIndex) );
917 else
919 _exportXML( rAttrList, rProperties[nIndex], rUnitConverter,
920 rNamespaceMap, &rProperties, nIndex );
925 nIndex++;
929 namespace
931 // -1 = Attribute needs extended namespace, but current ODF version is strict.
932 // 1 = Attribute needs extended namespace and current ODF version allows it.
933 // 0 = Attribute does not need extended namespace
934 sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue,
935 const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion)
937 if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE)
938 && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90)))
939 return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
940 else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL)
941 && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM)
942 || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP)))
943 return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
944 return 0;
948 void SvXMLExportPropertyMapper::_exportXML(
949 comphelper::AttributeList& rAttrList,
950 const XMLPropertyState& rProperty,
951 const SvXMLUnitConverter& rUnitConverter,
952 const SvXMLNamespaceMap& rNamespaceMap,
953 const ::std::vector< XMLPropertyState > *pProperties,
954 sal_uInt32 nIdx ) const
956 if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0)
958 uno::Reference< container::XNameContainer > xAttrContainer;
959 if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() )
961 std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap;
962 const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap;
964 const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() );
966 xml::AttributeData aData;
967 for( const auto& rAttribName : aAttribNames )
969 xAttrContainer->getByName( rAttribName ) >>= aData;
970 OUString sAttribName( rAttribName );
972 // extract namespace prefix from attribute name if it exists
973 OUString sPrefix;
974 const sal_Int32 nColonPos =
975 rAttribName.indexOf( ':' );
976 if( nColonPos != -1 )
977 sPrefix = rAttribName.copy( 0, nColonPos );
979 if( !sPrefix.isEmpty() )
981 OUString sNamespace( aData.Namespace );
983 // if the prefix isn't defined yet or has another meaning,
984 // we have to redefine it now.
985 sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
986 if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace )
988 bool bAddNamespace = false;
989 if( USHRT_MAX == nKey )
991 // The prefix is unused, so it is sufficient
992 // to add it to the namespace map.
993 bAddNamespace = true;
995 else
997 // check if there is a prefix registered for the
998 // namespace URI
999 nKey = pNamespaceMap->GetKeyByName( sNamespace );
1000 if( XML_NAMESPACE_UNKNOWN == nKey )
1002 // There is no prefix for the namespace, so
1003 // we have to generate one and have to add it.
1004 sal_Int32 n=0;
1005 OUString sOrigPrefix( sPrefix );
1008 sPrefix = sOrigPrefix + OUString::number( ++n );
1009 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
1011 while( nKey != USHRT_MAX );
1013 bAddNamespace = true;
1015 else
1017 // If there is a prefix for the namespace,
1018 // we reuse that.
1019 sPrefix = pNamespaceMap->GetPrefixByKey( nKey );
1021 // In any case, the attribute name has to be adapted.
1022 sAttribName = sPrefix + ":" + rAttribName.subView(nColonPos+1);
1025 if( bAddNamespace )
1027 if( !pNewNamespaceMap )
1029 pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap ));
1030 pNamespaceMap = pNewNamespaceMap.get();
1032 pNewNamespaceMap->Add( sPrefix, sNamespace );
1033 OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix;
1034 rAttrList.AddAttribute( sAttr, sNamespace );
1038 OUString sOldValue( rAttrList.getValueByName( sAttribName ) );
1039 OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" );
1040 OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out");
1041 if( sOldValue.isEmpty() )
1042 rAttrList.AddAttribute( sAttribName, aData.Value );
1045 else
1047 handleSpecialItem( rAttrList, rProperty, rUnitConverter,
1048 rNamespaceMap, pProperties, nIdx );
1051 else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0)
1053 OUString aValue;
1054 OUString sName = rNamespaceMap.GetQNameByKey(
1055 mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex),
1056 mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));
1058 bool bRemove = false;
1059 if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0)
1061 aValue = rAttrList.getValueByName( sName );
1062 bRemove = true;
1065 if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter))
1067 if( bRemove )
1068 rAttrList.RemoveAttribute( sName );
1070 // We don't seem to have a generic mechanism to write an attribute in the extension
1071 // namespace in case of certain attribute values only, so do this manually.
1072 sal_Int8 nExtendedStatus
1073 = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex),
1074 aValue, rUnitConverter.getSaneDefaultVersion());
1075 if (nExtendedStatus == -1)
1076 return;
1077 if (nExtendedStatus == 1)
1078 sName = rNamespaceMap.GetQNameByKey(
1079 XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));
1080 rAttrList.AddAttribute( sName, aValue );
1085 void SvXMLExportPropertyMapper::exportElementItems(
1086 SvXMLExport& rExport,
1087 const ::std::vector< XMLPropertyState >& rProperties,
1088 SvXmlExportFlags nFlags,
1089 const std::vector<sal_uInt16>& rIndexArray ) const
1091 bool bItemsExported = false;
1092 for (const sal_uInt16 nElement : rIndexArray)
1094 OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags(
1095 rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT),
1096 "wrong mid flag!" );
1098 rExport.IgnorableWhitespace();
1099 handleElementItem( rExport, rProperties[nElement],
1100 nFlags, &rProperties, nElement );
1101 bItemsExported = true;
1104 if( bItemsExported )
1105 rExport.IgnorableWhitespace();
1108 const rtl::Reference<XMLPropertySetMapper>& SvXMLExportPropertyMapper::getPropertySetMapper() const
1110 return mpImpl->mxPropMapper;
1113 void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName )
1115 mpImpl->maStyleName = rStyleName;
1118 const OUString& SvXMLExportPropertyMapper::GetStyleName() const
1120 return mpImpl->maStyleName;
1123 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */