diff options
Diffstat (limited to 'writerfilter/source/dmapper/StyleSheetTable.cxx')
-rw-r--r-- | writerfilter/source/dmapper/StyleSheetTable.cxx | 1707 |
1 files changed, 1707 insertions, 0 deletions
diff --git a/writerfilter/source/dmapper/StyleSheetTable.cxx b/writerfilter/source/dmapper/StyleSheetTable.cxx new file mode 100644 index 000000000..3a6d540b7 --- /dev/null +++ b/writerfilter/source/dmapper/StyleSheetTable.cxx @@ -0,0 +1,1707 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "StyleSheetTable.hxx" +#include "util.hxx" +#include "ConversionHelper.hxx" +#include "TblStylePrHandler.hxx" +#include "TagLogger.hxx" +#include "BorderHandler.hxx" +#include "LatentStyleHandler.hxx" +#include <ooxml/resourceids.hxx> +#include <vector> +#include <iterator> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <map> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/string.hxx> +#include <comphelper/sequence.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/sorted_vector.hxx> + +using namespace ::com::sun::star; + +namespace writerfilter::dmapper +{ + +StyleSheetEntry::StyleSheetEntry() : + bIsDefaultStyle(false) + ,bAssignedAsChapterNumbering(false) + ,bInvalidHeight(false) + ,bHasUPE(false) + ,nStyleTypeCode(STYLE_TYPE_UNKNOWN) + ,pProperties(new StyleSheetPropertyMap) + ,bAutoRedefine(false) +{ +} + +StyleSheetEntry::~StyleSheetEntry() +{ +} + +TableStyleSheetEntry::TableStyleSheetEntry( StyleSheetEntry const & rEntry ) +{ + bIsDefaultStyle = rEntry.bIsDefaultStyle; + bInvalidHeight = rEntry.bInvalidHeight; + bHasUPE = rEntry.bHasUPE; + nStyleTypeCode = STYLE_TYPE_TABLE; + sBaseStyleIdentifier = rEntry.sBaseStyleIdentifier; + sNextStyleIdentifier = rEntry.sNextStyleIdentifier; + sLinkStyleIdentifier = rEntry.sLinkStyleIdentifier; + sStyleName = rEntry.sStyleName; + sStyleIdentifierD = rEntry.sStyleIdentifierD; +} + +TableStyleSheetEntry::~TableStyleSheetEntry( ) +{ +} + +void TableStyleSheetEntry::AddTblStylePr( TblStyleType nType, const PropertyMapPtr& pProps ) +{ + static const int nTypesProps = 4; + static const TblStyleType pTypesToFix[nTypesProps] = + { + TBL_STYLE_FIRSTROW, + TBL_STYLE_LASTROW, + TBL_STYLE_FIRSTCOL, + TBL_STYLE_LASTCOL + }; + + static const PropertyIds pPropsToCheck[nTypesProps] = + { + PROP_BOTTOM_BORDER, + PROP_TOP_BORDER, + PROP_RIGHT_BORDER, + PROP_LEFT_BORDER + }; + + for (int i=0; i < nTypesProps; ++i ) + { + if ( nType == pTypesToFix[i] ) + { + PropertyIds nChecked = pPropsToCheck[i]; + std::optional<PropertyMap::Property> pChecked = pProps->getProperty(nChecked); + + PropertyIds nInsideProp = ( i < 2 ) ? META_PROP_HORIZONTAL_BORDER : META_PROP_VERTICAL_BORDER; + std::optional<PropertyMap::Property> pInside = pProps->getProperty(nInsideProp); + + if ( pChecked && pInside ) + { + // In this case, remove the inside border + pProps->Erase( nInsideProp ); + } + + break; + } + } + + // Append the tblStylePr + m_aStyles[nType] = pProps; +} + +PropertyMapPtr TableStyleSheetEntry::GetProperties( sal_Int32 nMask ) +{ + PropertyMapPtr pProps( new PropertyMap ); + + // And finally get the mask ones + pProps->InsertProps(GetLocalPropertiesFromMask(nMask)); + + return pProps; +} + +beans::PropertyValues StyleSheetEntry::GetInteropGrabBagSeq() const +{ + return comphelper::containerToSequence(m_aInteropGrabBag); +} + +beans::PropertyValue StyleSheetEntry::GetInteropGrabBag() +{ + beans::PropertyValue aRet; + aRet.Name = sStyleIdentifierD; + + beans::PropertyValues aSeq = GetInteropGrabBagSeq(); + aRet.Value <<= aSeq; + return aRet; +} + +void StyleSheetEntry::AppendInteropGrabBag(const beans::PropertyValue& rValue) +{ + m_aInteropGrabBag.push_back(rValue); +} + +PropertyMapPtr StyleSheetEntry::GetMergedInheritedProperties(const StyleSheetTablePtr& pStyleSheetTable) +{ + PropertyMapPtr pRet; + if ( pStyleSheetTable && !sBaseStyleIdentifier.isEmpty() && sBaseStyleIdentifier != sStyleIdentifierD ) + { + const StyleSheetEntryPtr pParentStyleSheet = pStyleSheetTable->FindStyleSheetByISTD(sBaseStyleIdentifier); + if ( pParentStyleSheet ) + pRet = pParentStyleSheet->GetMergedInheritedProperties(pStyleSheetTable); + } + + if ( !pRet ) + pRet = new PropertyMap; + + pRet->InsertProps(pProperties.get()); + + return pRet; +} + +static void lcl_mergeProps( const PropertyMapPtr& pToFill, const PropertyMapPtr& pToAdd, TblStyleType nStyleId ) +{ + static const PropertyIds pPropsToCheck[] = + { + PROP_BOTTOM_BORDER, + PROP_TOP_BORDER, + PROP_RIGHT_BORDER, + PROP_LEFT_BORDER, + }; + + bool pRemoveInside[] = + { + ( nStyleId == TBL_STYLE_FIRSTROW ), + ( nStyleId == TBL_STYLE_LASTROW ), + ( nStyleId == TBL_STYLE_LASTCOL ), + ( nStyleId == TBL_STYLE_FIRSTCOL ) + }; + + for ( unsigned i = 0 ; i != SAL_N_ELEMENTS(pPropsToCheck); i++ ) + { + PropertyIds nId = pPropsToCheck[i]; + std::optional<PropertyMap::Property> pProp = pToAdd->getProperty(nId); + + if ( pProp ) + { + if ( pRemoveInside[i] ) + { + // Remove the insideH and insideV depending on the cell pos + PropertyIds nInsideProp = ( i < 2 ) ? META_PROP_HORIZONTAL_BORDER : META_PROP_VERTICAL_BORDER; + pToFill->Erase(nInsideProp); + } + } + } + + pToFill->InsertProps(pToAdd); +} + +PropertyMapPtr TableStyleSheetEntry::GetLocalPropertiesFromMask( sal_Int32 nMask ) +{ + // Order from right to left + struct TblStyleTypeAndMask { + sal_Int32 mask; + TblStyleType type; + }; + + static const TblStyleTypeAndMask aOrderedStyleTable[] = + { + { 0x010, TBL_STYLE_BAND2HORZ }, + { 0x020, TBL_STYLE_BAND1HORZ }, + { 0x040, TBL_STYLE_BAND2VERT }, + { 0x080, TBL_STYLE_BAND1VERT }, + { 0x100, TBL_STYLE_LASTCOL }, + { 0x200, TBL_STYLE_FIRSTCOL }, + { 0x400, TBL_STYLE_LASTROW }, + { 0x800, TBL_STYLE_FIRSTROW }, + { 0x001, TBL_STYLE_SWCELL }, + { 0x002, TBL_STYLE_SECELL }, + { 0x004, TBL_STYLE_NWCELL }, + { 0x008, TBL_STYLE_NECELL } + }; + + // Get the properties applying according to the mask + PropertyMapPtr pProps( new PropertyMap( ) ); + for (const TblStyleTypeAndMask & i : aOrderedStyleTable) + { + TblStylePrs::iterator pIt = m_aStyles.find( i.type ); + if ( ( nMask & i.mask ) && ( pIt != m_aStyles.end( ) ) ) + lcl_mergeProps( pProps, pIt->second, i.type ); + } + return pProps; +} + +namespace { + +struct ListCharStylePropertyMap_t +{ + OUString sCharStyleName; + PropertyValueVector_t aPropertyValues; + + ListCharStylePropertyMap_t(const OUString& rCharStyleName, PropertyValueVector_t&& rPropertyValues): + sCharStyleName( rCharStyleName ), + aPropertyValues( std::move(rPropertyValues) ) + {} +}; + +} + +struct StyleSheetTable_Impl +{ + DomainMapper& m_rDMapper; + uno::Reference< text::XTextDocument> m_xTextDocument; + uno::Reference< beans::XPropertySet> m_xTextDefaults; + std::vector< StyleSheetEntryPtr > m_aStyleSheetEntries; + std::map< OUString, StyleSheetEntryPtr > m_aStyleSheetEntriesMap; + StyleSheetEntryPtr m_pCurrentEntry; + PropertyMapPtr m_pDefaultParaProps, m_pDefaultCharProps; + OUString m_sDefaultParaStyleName; //WW8 name + std::vector< ListCharStylePropertyMap_t > m_aListCharStylePropertyVector; + bool m_bHasImportedDefaultParaProps; + bool m_bIsNewDoc; + + StyleSheetTable_Impl(DomainMapper& rDMapper, uno::Reference< text::XTextDocument> const& xTextDocument, bool bIsNewDoc); + + OUString HasListCharStyle( const PropertyValueVector_t& rCharProperties ); + + /// Appends the given key-value pair to the list of latent style properties of the current entry. + void AppendLatentStyleProperty(const OUString& aName, Value const & rValue); + /// Sets all properties of xStyle back to default. + static void SetPropertiesToDefault(const uno::Reference<style::XStyle>& xStyle); +}; + + +StyleSheetTable_Impl::StyleSheetTable_Impl(DomainMapper& rDMapper, + uno::Reference< text::XTextDocument> const& xTextDocument, + bool const bIsNewDoc) + : m_rDMapper( rDMapper ), + m_xTextDocument( xTextDocument ), + m_pDefaultParaProps(new PropertyMap), + m_pDefaultCharProps(new PropertyMap), + m_sDefaultParaStyleName("Normal"), + m_bHasImportedDefaultParaProps(false), + m_bIsNewDoc(bIsNewDoc) +{ + //set font height default to 10pt + uno::Any aVal( 10.0 ); + m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT, aVal ); + m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal ); + m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_COMPLEX, aVal ); + + // See SwDoc::RemoveAllFormatLanguageDependencies(), internal filters + // disable kerning by default, do the same here. + m_pDefaultCharProps->Insert(PROP_CHAR_AUTO_KERNING, uno::Any(false)); +} + + +OUString StyleSheetTable_Impl::HasListCharStyle( const PropertyValueVector_t& rPropValues ) +{ + for( const auto& rListVector : m_aListCharStylePropertyVector ) + { + const auto& rPropertyValues = rListVector.aPropertyValues; + //if size is identical + if( rPropertyValues.size() == rPropValues.size() ) + { + bool bBreak = false; + //then search for all contained properties + for( const auto& rPropVal1 : rPropValues) + { + //find the property + auto aListIter = std::find_if(rPropertyValues.begin(), rPropertyValues.end(), + [&rPropVal1](const css::beans::PropertyValue& rPropVal2) { return rPropVal2.Name == rPropVal1.Name; }); + //set break flag if property hasn't been found + bBreak = (aListIter == rPropertyValues.end()) || (aListIter->Value != rPropVal1.Value); + if( bBreak ) + break; + } + if( !bBreak ) + return rListVector.sCharStyleName; + } + } + return OUString(); +} + +void StyleSheetTable_Impl::AppendLatentStyleProperty(const OUString& aName, Value const & rValue) +{ + beans::PropertyValue aValue; + aValue.Name = aName; + aValue.Value <<= rValue.getString(); + m_pCurrentEntry->aLatentStyles.push_back(aValue); +} + +void StyleSheetTable_Impl::SetPropertiesToDefault(const uno::Reference<style::XStyle>& xStyle) +{ + // See if the existing style has any non-default properties. If so, reset them back to default. + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo(); + const uno::Sequence<beans::Property> aProperties = xPropertySetInfo->getProperties(); + std::vector<OUString> aPropertyNames; + aPropertyNames.reserve(aProperties.getLength()); + std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aPropertyNames), + [](const beans::Property& rProp) { return rProp.Name; }); + + uno::Reference<beans::XPropertyState> xPropertyState(xStyle, uno::UNO_QUERY); + uno::Sequence<beans::PropertyState> aStates = xPropertyState->getPropertyStates(comphelper::containerToSequence(aPropertyNames)); + for (sal_Int32 i = 0; i < aStates.getLength(); ++i) + { + if (aStates[i] == beans::PropertyState_DIRECT_VALUE) + { + try + { + xPropertyState->setPropertyToDefault(aPropertyNames[i]); + } + catch(const uno::Exception&) + { + TOOLS_INFO_EXCEPTION("writerfilter", "setPropertyToDefault(" << aPropertyNames[i] << ") failed"); + } + } + } +} + +StyleSheetTable::StyleSheetTable(DomainMapper& rDMapper, + uno::Reference< text::XTextDocument> const& xTextDocument, + bool const bIsNewDoc) +: LoggedProperties("StyleSheetTable") +, LoggedTable("StyleSheetTable") +, m_pImpl( new StyleSheetTable_Impl(rDMapper, xTextDocument, bIsNewDoc) ) +{ +} + + +StyleSheetTable::~StyleSheetTable() +{ +} + +void StyleSheetTable::SetDefaultParaProps(PropertyIds eId, const css::uno::Any& rAny) +{ + m_pImpl->m_pDefaultParaProps->Insert(eId, rAny, /*bOverwrite=*/false, NO_GRAB_BAG, /*bDocDefault=*/true); +} + +PropertyMapPtr const & StyleSheetTable::GetDefaultParaProps() const +{ + return m_pImpl->m_pDefaultParaProps; +} + +PropertyMapPtr const & StyleSheetTable::GetDefaultCharProps() const +{ + return m_pImpl->m_pDefaultCharProps; +} + +void StyleSheetTable::lcl_attribute(Id Name, Value & val) +{ + OSL_ENSURE( m_pImpl->m_pCurrentEntry, "current entry has to be set here"); + if(!m_pImpl->m_pCurrentEntry) + return ; + int nIntValue = val.getInt(); + OUString sValue = val.getString(); + + // The default type is paragraph, and it needs to be processed first, + // because the NS_ooxml::LN_CT_Style_type handling may set m_pImpl->m_pCurrentEntry + // to point to a different object. + if( m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_UNKNOWN ) + { + if( Name != NS_ooxml::LN_CT_Style_type ) + m_pImpl->m_pCurrentEntry->nStyleTypeCode = STYLE_TYPE_PARA; + } + switch(Name) + { + case NS_ooxml::LN_CT_Style_type: + { + SAL_WARN_IF( m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN, + "writerfilter", "Style type needs to be processed first" ); + StyleType nType(STYLE_TYPE_UNKNOWN); + switch (nIntValue) + { + case NS_ooxml::LN_Value_ST_StyleType_paragraph: + nType = STYLE_TYPE_PARA; + break; + case NS_ooxml::LN_Value_ST_StyleType_character: + nType = STYLE_TYPE_CHAR; + break; + case NS_ooxml::LN_Value_ST_StyleType_table: + nType = STYLE_TYPE_TABLE; + break; + case NS_ooxml::LN_Value_ST_StyleType_numbering: + nType = STYLE_TYPE_LIST; + break; + default: + SAL_WARN("writerfilter", "unknown LN_CT_Style_type " << nType); + [[fallthrough]]; + case 0: // explicit unknown set by tokenizer + break; + + } + if ( nType == STYLE_TYPE_TABLE ) + { + StyleSheetEntryPtr pEntry = m_pImpl->m_pCurrentEntry; + tools::SvRef<TableStyleSheetEntry> pTableEntry( new TableStyleSheetEntry( *pEntry ) ); + m_pImpl->m_pCurrentEntry = pTableEntry.get(); + } + else + m_pImpl->m_pCurrentEntry->nStyleTypeCode = nType; + } + break; + case NS_ooxml::LN_CT_Style_default: + m_pImpl->m_pCurrentEntry->bIsDefaultStyle = (nIntValue != 0); + + if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN) + { + // "If this attribute is specified by multiple styles, then the last instance shall be used." + if (m_pImpl->m_pCurrentEntry->bIsDefaultStyle + && m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_PARA + && !m_pImpl->m_pCurrentEntry->sStyleIdentifierD.isEmpty()) + { + m_pImpl->m_sDefaultParaStyleName = m_pImpl->m_pCurrentEntry->sStyleIdentifierD; + } + + beans::PropertyValue aValue; + aValue.Name = "default"; + aValue.Value <<= m_pImpl->m_pCurrentEntry->bIsDefaultStyle; + m_pImpl->m_pCurrentEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_Style_customStyle: + if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN) + { + beans::PropertyValue aValue; + aValue.Name = "customStyle"; + aValue.Value <<= (nIntValue != 0); + m_pImpl->m_pCurrentEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_Style_styleId: + m_pImpl->m_pCurrentEntry->sStyleIdentifierD = sValue; + if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get()); + beans::PropertyValue aValue; + aValue.Name = "styleId"; + aValue.Value <<= sValue; + pTableEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_TblWidth_w: + break; + case NS_ooxml::LN_CT_TblWidth_type: + break; + case NS_ooxml::LN_CT_LatentStyles_defQFormat: + m_pImpl->AppendLatentStyleProperty("defQFormat", val); + break; + case NS_ooxml::LN_CT_LatentStyles_defUnhideWhenUsed: + m_pImpl->AppendLatentStyleProperty("defUnhideWhenUsed", val); + break; + case NS_ooxml::LN_CT_LatentStyles_defSemiHidden: + m_pImpl->AppendLatentStyleProperty("defSemiHidden", val); + break; + case NS_ooxml::LN_CT_LatentStyles_count: + m_pImpl->AppendLatentStyleProperty("count", val); + break; + case NS_ooxml::LN_CT_LatentStyles_defUIPriority: + m_pImpl->AppendLatentStyleProperty("defUIPriority", val); + break; + case NS_ooxml::LN_CT_LatentStyles_defLockedState: + m_pImpl->AppendLatentStyleProperty("defLockedState", val); + break; + default: + { +#ifdef DBG_UTIL + TagLogger::getInstance().element("unhandled"); +#endif + } + break; + } +} + + +void StyleSheetTable::lcl_sprm(Sprm & rSprm) +{ + sal_uInt32 nSprmId = rSprm.getId(); + Value::Pointer_t pValue = rSprm.getValue(); + sal_Int32 nIntValue = pValue ? pValue->getInt() : 0; + OUString sStringValue = pValue ? pValue->getString() : OUString(); + + switch(nSprmId) + { + case NS_ooxml::LN_CT_Style_name: + //this is only a UI name! + m_pImpl->m_pCurrentEntry->sStyleName = sStringValue; + if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get()); + beans::PropertyValue aValue; + aValue.Name = "name"; + aValue.Value <<= sStringValue; + pTableEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_Style_basedOn: + m_pImpl->m_pCurrentEntry->sBaseStyleIdentifier = sStringValue; + if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get()); + beans::PropertyValue aValue; + aValue.Name = "basedOn"; + aValue.Value <<= sStringValue; + pTableEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_Style_link: + m_pImpl->m_pCurrentEntry->sLinkStyleIdentifier = sStringValue; + break; + case NS_ooxml::LN_CT_Style_next: + m_pImpl->m_pCurrentEntry->sNextStyleIdentifier = sStringValue; + break; + case NS_ooxml::LN_CT_Style_aliases: + case NS_ooxml::LN_CT_Style_hidden: + case NS_ooxml::LN_CT_Style_personal: + case NS_ooxml::LN_CT_Style_personalCompose: + case NS_ooxml::LN_CT_Style_personalReply: + break; + case NS_ooxml::LN_CT_Style_autoRedefine: + m_pImpl->m_pCurrentEntry->bAutoRedefine = nIntValue; + break; + case NS_ooxml::LN_CT_Style_tcPr: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if( pProperties && m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + auto pTblStylePrHandler = std::make_shared<TblStylePrHandler>(m_pImpl->m_rDMapper); + pProperties->resolve(*pTblStylePrHandler); + StyleSheetEntry* pEntry = m_pImpl->m_pCurrentEntry.get(); + TableStyleSheetEntry& rTableEntry = dynamic_cast<TableStyleSheetEntry&>(*pEntry); + rTableEntry.AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tcPr")); + + // This is a <w:tcPr> directly under <w:style>, so it affects the whole table. + rTableEntry.pProperties->InsertProps(pTblStylePrHandler->getProperties()); + } + } + break; + case NS_ooxml::LN_CT_Style_trPr: + break; + case NS_ooxml::LN_CT_Style_rsid: + case NS_ooxml::LN_CT_Style_qFormat: + case NS_ooxml::LN_CT_Style_semiHidden: + case NS_ooxml::LN_CT_Style_unhideWhenUsed: + case NS_ooxml::LN_CT_Style_uiPriority: + case NS_ooxml::LN_CT_Style_locked: + if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN) + { + StyleSheetEntryPtr pEntry = m_pImpl->m_pCurrentEntry; + beans::PropertyValue aValue; + switch (nSprmId) + { + case NS_ooxml::LN_CT_Style_rsid: + { + // We want the rsid as a hex string, but always with the length of 8. + OUStringBuffer aBuf = OUString::number(nIntValue, 16); + OUStringBuffer aStr; + comphelper::string::padToLength(aStr, 8 - aBuf.getLength(), '0'); + aStr.append(aBuf.getStr()); + + aValue.Name = "rsid"; + aValue.Value <<= aStr.makeStringAndClear(); + } + break; + case NS_ooxml::LN_CT_Style_qFormat: + aValue.Name = "qFormat"; + break; + case NS_ooxml::LN_CT_Style_semiHidden: + aValue.Name = "semiHidden"; + break; + case NS_ooxml::LN_CT_Style_unhideWhenUsed: + aValue.Name = "unhideWhenUsed"; + break; + case NS_ooxml::LN_CT_Style_uiPriority: + { + aValue.Name = "uiPriority"; + aValue.Value <<= OUString::number(nIntValue); + } + break; + case NS_ooxml::LN_CT_Style_locked: + aValue.Name = "locked"; + break; + } + pEntry->AppendInteropGrabBag(aValue); + } + break; + case NS_ooxml::LN_CT_Style_tblPr: //contains table properties + case NS_ooxml::LN_CT_Style_tblStylePr: //contains to table properties + case NS_ooxml::LN_CT_TblPrBase_tblInd: //table properties - at least width value and type + case NS_ooxml::LN_EG_RPrBase_rFonts: //table fonts + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if( pProperties ) + { + auto pTblStylePrHandler = std::make_shared<TblStylePrHandler>( m_pImpl->m_rDMapper ); + pProperties->resolve( *pTblStylePrHandler ); + + // Add the properties to the table style + TblStyleType nType = pTblStylePrHandler->getType( ); + PropertyMapPtr pProps = pTblStylePrHandler->getProperties( ); + StyleSheetEntry * pEntry = m_pImpl->m_pCurrentEntry.get(); + + TableStyleSheetEntry * pTableEntry = dynamic_cast<TableStyleSheetEntry*>( pEntry ); + if (nType == TBL_STYLE_UNKNOWN) + { + pEntry->pProperties->InsertProps(pProps); + } + else + { + if (pTableEntry != nullptr) + pTableEntry->AddTblStylePr( nType, pProps ); + } + + if (nSprmId == NS_ooxml::LN_CT_Style_tblPr) + { + if (pTableEntry != nullptr) + pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblPr")); + } + else if (nSprmId == NS_ooxml::LN_CT_Style_tblStylePr) + { + pTblStylePrHandler->appendInteropGrabBag("type", pTblStylePrHandler->getTypeString()); + if (pTableEntry != nullptr) + pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblStylePr")); + } + } + break; + } + case NS_ooxml::LN_CT_PPrDefault_pPr: + case NS_ooxml::LN_CT_DocDefaults_pPrDefault: + if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault) + m_pImpl->m_rDMapper.SetDocDefaultsImport(true); + + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultParaProps ); + resolveSprmProps( m_pImpl->m_rDMapper, rSprm ); + if ( nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault && m_pImpl->m_pDefaultParaProps && + !m_pImpl->m_pDefaultParaProps->isSet( PROP_PARA_TOP_MARGIN ) ) + { + SetDefaultParaProps( PROP_PARA_TOP_MARGIN, uno::Any( sal_Int32(0) ) ); + } + m_pImpl->m_rDMapper.PopStyleSheetProperties(); + applyDefaults( true ); + m_pImpl->m_bHasImportedDefaultParaProps = true; + if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault) + m_pImpl->m_rDMapper.SetDocDefaultsImport(false); + break; + case NS_ooxml::LN_CT_RPrDefault_rPr: + case NS_ooxml::LN_CT_DocDefaults_rPrDefault: + if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault) + m_pImpl->m_rDMapper.SetDocDefaultsImport(true); + + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultCharProps ); + resolveSprmProps( m_pImpl->m_rDMapper, rSprm ); + m_pImpl->m_rDMapper.PopStyleSheetProperties(); + applyDefaults( false ); + if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault) + m_pImpl->m_rDMapper.SetDocDefaultsImport(false); + break; + case NS_ooxml::LN_CT_TblPrBase_jc: //table alignment - row properties! + m_pImpl->m_pCurrentEntry->pProperties->Insert( PROP_HORI_ORIENT, + uno::Any( ConversionHelper::convertTableJustification( nIntValue ))); + break; + case NS_ooxml::LN_CT_TrPrBase_jc: //table alignment - row properties! + break; + case NS_ooxml::LN_CT_TblPrBase_tblBorders: //table borders, might be defined in table style + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if( pProperties ) + { + auto pBorderHandler = std::make_shared<BorderHandler>(m_pImpl->m_rDMapper.IsOOXMLImport()); + pProperties->resolve(*pBorderHandler); + m_pImpl->m_pCurrentEntry->pProperties->InsertProps( + pBorderHandler->getProperties()); + } + } + break; + case NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize: + case NS_ooxml::LN_CT_TblPrBase_tblStyleColBandSize: + break; + case NS_ooxml::LN_CT_TblPrBase_tblCellMar: + //no cell margins in styles + break; + case NS_ooxml::LN_CT_LatentStyles_lsdException: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties) + { + tools::SvRef<LatentStyleHandler> pLatentStyleHandler(new LatentStyleHandler()); + pProperties->resolve(*pLatentStyleHandler); + beans::PropertyValue aValue; + aValue.Name = "lsdException"; + aValue.Value <<= comphelper::containerToSequence(pLatentStyleHandler->getAttributes()); + m_pImpl->m_pCurrentEntry->aLsdExceptions.push_back(aValue); + } + } + break; + case NS_ooxml::LN_CT_Style_pPr: + // no break + case NS_ooxml::LN_CT_Style_rPr: + // no break + default: + { + if (!m_pImpl->m_pCurrentEntry) + break; + + tools::SvRef<TablePropertiesHandler> pTblHandler(new TablePropertiesHandler()); + pTblHandler->SetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() ); + if ( !pTblHandler->sprm( rSprm ) ) + { + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() ); + + PropertyMapPtr pProps(new PropertyMap()); + if (m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + if (nSprmId == NS_ooxml::LN_CT_Style_pPr) + m_pImpl->m_rDMapper.enableInteropGrabBag("pPr"); + else if (nSprmId == NS_ooxml::LN_CT_Style_rPr) + m_pImpl->m_rDMapper.enableInteropGrabBag("rPr"); + } + m_pImpl->m_rDMapper.sprmWithProps( rSprm, pProps ); + if (m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + if (nSprmId == NS_ooxml::LN_CT_Style_pPr || nSprmId == NS_ooxml::LN_CT_Style_rPr) + { + TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get()); + pTableEntry->AppendInteropGrabBag(m_pImpl->m_rDMapper.getInteropGrabBag()); + } + } + + m_pImpl->m_pCurrentEntry->pProperties->InsertProps(pProps); + + m_pImpl->m_rDMapper.PopStyleSheetProperties( ); + } + } + break; +} +} + + +void StyleSheetTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) +{ + //create a new style entry + OSL_ENSURE( !m_pImpl->m_pCurrentEntry, "current entry has to be NULL here"); + StyleSheetEntryPtr pNewEntry( new StyleSheetEntry ); + m_pImpl->m_pCurrentEntry = pNewEntry; + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() ); + ref->resolve(*this); + //append it to the table + m_pImpl->m_rDMapper.PopStyleSheetProperties(); + if( !m_pImpl->m_rDMapper.IsOOXMLImport() || !m_pImpl->m_pCurrentEntry->sStyleName.isEmpty()) + { + m_pImpl->m_pCurrentEntry->sConvertedStyleName = ConvertStyleName( m_pImpl->m_pCurrentEntry->sStyleName ); + m_pImpl->m_aStyleSheetEntries.push_back( m_pImpl->m_pCurrentEntry ); + m_pImpl->m_aStyleSheetEntriesMap.emplace( m_pImpl->m_pCurrentEntry->sStyleIdentifierD, m_pImpl->m_pCurrentEntry ); + } + else + { + //TODO: this entry contains the default settings - they have to be added to the settings + } + + if (!m_pImpl->m_pCurrentEntry->aLatentStyles.empty()) + { + // We have latent styles for this entry, then process them. + std::vector<beans::PropertyValue>& rLatentStyles = m_pImpl->m_pCurrentEntry->aLatentStyles; + + if (!m_pImpl->m_pCurrentEntry->aLsdExceptions.empty()) + { + std::vector<beans::PropertyValue>& rLsdExceptions = m_pImpl->m_pCurrentEntry->aLsdExceptions; + beans::PropertyValue aValue; + aValue.Name = "lsdExceptions"; + aValue.Value <<= comphelper::containerToSequence(rLsdExceptions); + rLatentStyles.push_back(aValue); + } + + uno::Sequence<beans::PropertyValue> aLatentStyles( comphelper::containerToSequence(rLatentStyles) ); + + // We can put all latent style info directly to the document interop + // grab bag, as we can be sure that only a single style entry has + // latent style info. + uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY); + auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(xPropertySet->getPropertyValue("InteropGrabBag").get< uno::Sequence<beans::PropertyValue> >()); + beans::PropertyValue aValue; + aValue.Name = "latentStyles"; + aValue.Value <<= aLatentStyles; + aGrabBag.push_back(aValue); + xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag))); + } + + StyleSheetEntryPtr pEmptyEntry; + m_pImpl->m_pCurrentEntry = pEmptyEntry; +} +/*------------------------------------------------------------------------- + sorting helper + -----------------------------------------------------------------------*/ +namespace { + +class PropValVector +{ + std::vector<beans::PropertyValue> m_aValues; +public: + PropValVector(){} + + void Insert(const beans::PropertyValue& rVal); + uno::Sequence< uno::Any > getValues(); + uno::Sequence< OUString > getNames(); + const std::vector<beans::PropertyValue>& getProperties() const { return m_aValues; }; +}; + +} + +void PropValVector::Insert(const beans::PropertyValue& rVal) +{ + auto aIt = std::find_if(m_aValues.begin(), m_aValues.end(), + [&rVal](beans::PropertyValue& rPropVal) { return rPropVal.Name > rVal.Name; }); + if (aIt != m_aValues.end()) + { + m_aValues.insert( aIt, rVal ); + return; + } + m_aValues.push_back(rVal); +} + +uno::Sequence< uno::Any > PropValVector::getValues() +{ + std::vector<uno::Any> aRet; + std::transform(m_aValues.begin(), m_aValues.end(), std::back_inserter(aRet), [](const beans::PropertyValue& rValue) { return rValue.Value; }); + return comphelper::containerToSequence(aRet); +} + +uno::Sequence< OUString > PropValVector::getNames() +{ + std::vector<OUString> aRet; + std::transform(m_aValues.begin(), m_aValues.end(), std::back_inserter(aRet), [](const beans::PropertyValue& rValue) { return rValue.Name; }); + return comphelper::containerToSequence(aRet); +} + +void StyleSheetTable::ApplyNumberingStyleNameToParaStyles() +{ + try + { + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameContainer> xParaStyles; + xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles; + + if ( !xParaStyles.is() ) + return; + + for ( const auto& pEntry : m_pImpl->m_aStyleSheetEntries ) + { + StyleSheetPropertyMap* pStyleSheetProperties = nullptr; + if ( pEntry->nStyleTypeCode == STYLE_TYPE_PARA && (pStyleSheetProperties = pEntry->pProperties.get()) ) + { + // ListId 0 means turn off numbering - to cancel inheritance - so make sure that can be set. + if (pStyleSheetProperties->GetListId() > -1) + { + uno::Reference< style::XStyle > xStyle; + xParaStyles->getByName( ConvertStyleName(pEntry->sStyleName) ) >>= xStyle; + + if ( !xStyle.is() ) + break; + + uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY_THROW ); + const OUString sNumberingStyleName = m_pImpl->m_rDMapper.GetListStyleName( pStyleSheetProperties->GetListId() ); + if ( !sNumberingStyleName.isEmpty() || !pStyleSheetProperties->GetListId() ) + xPropertySet->setPropertyValue( getPropertyName(PROP_NUMBERING_STYLE_NAME), uno::Any(sNumberingStyleName) ); + + // Word 2010+ (not Word 2003, and Word 2007 is completely broken) + // does something rather strange. It does not allow two paragraph styles + // to share the same listLevel on a numbering rule. + // Consider this style to just be body level if already used previously. + m_pImpl->m_rDMapper.ValidateListLevel(pEntry->sStyleIdentifierD); + } + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying numbering style name to Paragraph styles"); + } +} + +/* Counteract the destructive tendencies of LibreOffice's Chapter Numbering + * + * Any assignment to Chapter Numbering will erase the numbering-like properties of inherited styles. + * So go through the list of styles and any that inherit from a Chapter Numbering style + * should have the Outline Level reapplied. + */ +void StyleSheetTable::ReApplyInheritedOutlineLevelFromChapterNumbering() +{ + try + { + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW); + uno::Reference< lang::XMultiServiceFactory > xDocFactory(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameContainer> xParaStyles; + xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES)) >>= xParaStyles; + + if (!xParaStyles.is()) + return; + + for (const auto& pEntry : m_pImpl->m_aStyleSheetEntries) + { + if (pEntry->nStyleTypeCode != STYLE_TYPE_PARA || pEntry->sBaseStyleIdentifier.isEmpty()) + continue; + + sal_Int16 nOutlineLevel = pEntry->pProperties->GetOutlineLevel(); + if (nOutlineLevel != -1) + continue; + + StyleSheetEntryPtr pParent = FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier); + if (!pParent || !pParent->bAssignedAsChapterNumbering) + continue; + + nOutlineLevel = pParent->pProperties->GetOutlineLevel(); + assert(nOutlineLevel >= WW_OUTLINE_MIN && nOutlineLevel < WW_OUTLINE_MAX); + + // convert MS level to LO equivalent outline level + ++nOutlineLevel; + + uno::Reference< style::XStyle > xStyle; + xParaStyles->getByName(pEntry->sConvertedStyleName) >>= xStyle; + if ( !xStyle.is() ) + break; + + uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY_THROW ); + xPropertySet->setPropertyValue(getPropertyName(PROP_OUTLINE_LEVEL), uno::Any(nOutlineLevel)); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying outlineLevel to Paragraph styles"); + } +} + +void StyleSheetTable::ApplyStyleSheets( const FontTablePtr& rFontTable ) +{ + try + { + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameContainer> xCharStyles; + uno::Reference<container::XNameContainer> xParaStyles; + uno::Reference<container::XNameContainer> xNumberingStyles; + + xStyleFamilies->getByName(getPropertyName( PROP_CHARACTER_STYLES )) >>= xCharStyles; + xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles; + xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles; + if(xCharStyles.is() && xParaStyles.is()) + { + std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingParent; + std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingFollow; + std::vector<std::pair<OUString, uno::Reference<style::XStyle>>> aMissingLink; + std::vector<beans::PropertyValue> aTableStylesVec; + for( auto& pEntry : m_pImpl->m_aStyleSheetEntries ) + { + if( pEntry->nStyleTypeCode == STYLE_TYPE_UNKNOWN && !pEntry->sStyleName.isEmpty() ) + pEntry->nStyleTypeCode = STYLE_TYPE_PARA; // unspecified style types are considered paragraph styles + + if( pEntry->nStyleTypeCode == STYLE_TYPE_CHAR || pEntry->nStyleTypeCode == STYLE_TYPE_PARA || pEntry->nStyleTypeCode == STYLE_TYPE_LIST ) + { + bool bParaStyle = pEntry->nStyleTypeCode == STYLE_TYPE_PARA; + bool bCharStyle = pEntry->nStyleTypeCode == STYLE_TYPE_CHAR; + bool bListStyle = pEntry->nStyleTypeCode == STYLE_TYPE_LIST; + bool bInsert = false; + uno::Reference< container::XNameContainer > xStyles = bParaStyle ? xParaStyles : (bListStyle ? xNumberingStyles : xCharStyles); + uno::Reference< style::XStyle > xStyle; + const OUString sConvertedStyleName = ConvertStyleName( pEntry->sStyleName ); + + if(xStyles->hasByName( sConvertedStyleName )) + { + // When pasting, don't update existing styles. + if (!m_pImpl->m_bIsNewDoc) + { + continue; + } + xStyles->getByName( sConvertedStyleName ) >>= xStyle; + + { + StyleSheetTable_Impl::SetPropertiesToDefault(xStyle); + + // resolve import conflicts with built-in styles (only if defaults have been defined) + if ( m_pImpl->m_bHasImportedDefaultParaProps + && pEntry->sBaseStyleIdentifier.isEmpty() //imported style has no inheritance + && !xStyle->getParentStyle().isEmpty() ) //built-in style has a default inheritance + { + xStyle->setParentStyle( "" ); + } + } + } + else + { + bInsert = true; + xStyle.set(xDocFactory->createInstance( + bParaStyle ? + getPropertyName( PROP_SERVICE_PARA_STYLE ) : + (bListStyle ? OUString("com.sun.star.style.NumberingStyle") : getPropertyName( PROP_SERVICE_CHAR_STYLE ))), + uno::UNO_QUERY_THROW); + + // Numbering styles have to be inserted early, as e.g. the NumberingRules property is only available after insertion. + if (bListStyle) + { + xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle ) ); + xStyle.set(xStyles->getByName(sConvertedStyleName), uno::UNO_QUERY_THROW); + + StyleSheetPropertyMap* pPropertyMap = pEntry->pProperties.get(); + if (pPropertyMap && pPropertyMap->GetListId() == -1) + { + // No properties? Word default is 'none', Writer one is 'arabic', handle this. + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW); + uno::Reference<container::XIndexReplace> xNumberingRules; + xPropertySet->getPropertyValue("NumberingRules") >>= xNumberingRules; + uno::Reference<container::XIndexAccess> xIndexAccess(xNumberingRules, uno::UNO_QUERY_THROW); + for (sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i) + { + uno::Sequence< beans::PropertyValue > aLvlProps{ + comphelper::makePropertyValue( + "NumberingType", style::NumberingType::NUMBER_NONE) + }; + xNumberingRules->replaceByIndex(i, uno::Any(aLvlProps)); + xPropertySet->setPropertyValue("NumberingRules", uno::Any(xNumberingRules)); + } + } + } + } + if( !pEntry->sBaseStyleIdentifier.isEmpty() ) + { + try + { + //TODO: Handle cases where a paragraph <> character style relation is needed + StyleSheetEntryPtr pParent = FindStyleSheetByISTD( pEntry->sBaseStyleIdentifier ); + // Writer core doesn't support numbering styles having a parent style, it seems + if (pParent && !bListStyle) + { + const OUString sParentStyleName = ConvertStyleName( pParent->sStyleName ); + if ( !sParentStyleName.isEmpty() && !xStyles->hasByName( sParentStyleName ) ) + aMissingParent.emplace_back( sParentStyleName, xStyle ); + else + xStyle->setParentStyle( sParentStyleName ); + } + } + catch( const uno::RuntimeException& ) + { + OSL_FAIL( "Styles parent could not be set"); + } + } + else if( bParaStyle ) + { + // Paragraph styles that don't inherit from some parent need to apply the DocDefaults + pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false ); + + //now it's time to set the default parameters - for paragraph styles + //Fonts: Western first entry in font table + //CJK: second entry + //CTL: third entry, if it exists + + sal_uInt32 nFontCount = rFontTable->size(); + if( !m_pImpl->m_rDMapper.IsOOXMLImport() && nFontCount > 2 ) + { + uno::Any aTwoHundredFortyTwip(12.); + + // font size to 240 twip (12 pts) for all if not set + pEntry->pProperties->Insert(PROP_CHAR_HEIGHT, aTwoHundredFortyTwip, false); + + // western font not already set -> apply first font + const FontEntry::Pointer_t pWesternFontEntry(rFontTable->getFontEntry( 0 )); + OUString sWesternFontName = pWesternFontEntry->sFontName; + pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME, uno::Any( sWesternFontName ), false); + + // CJK ... apply second font + const FontEntry::Pointer_t pCJKFontEntry(rFontTable->getFontEntry( 2 )); + pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( pCJKFontEntry->sFontName ), false); + pEntry->pProperties->Insert(PROP_CHAR_HEIGHT_ASIAN, aTwoHundredFortyTwip, false); + + // CTL ... apply third font, if available + if( nFontCount > 3 ) + { + const FontEntry::Pointer_t pCTLFontEntry(rFontTable->getFontEntry( 3 )); + pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( pCTLFontEntry->sFontName ), false); + pEntry->pProperties->Insert(PROP_CHAR_HEIGHT_COMPLEX, aTwoHundredFortyTwip, false); + } + } + } + + auto aPropValues = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pEntry->pProperties->GetPropertyValues()); + + if (bParaStyle || bCharStyle) + { + // delay adding LinkStyle property: all styles need to be created first + if (!pEntry->sLinkStyleIdentifier.isEmpty()) + { + StyleSheetEntryPtr pLinkStyle + = FindStyleSheetByISTD(pEntry->sLinkStyleIdentifier); + if (pLinkStyle && !pLinkStyle->sStyleName.isEmpty()) + aMissingLink.emplace_back(ConvertStyleName(pLinkStyle->sStyleName), + xStyle); + } + } + + if( bParaStyle ) + { + // delay adding FollowStyle property: all styles need to be created first + if ( !pEntry->sNextStyleIdentifier.isEmpty() ) + { + StyleSheetEntryPtr pFollowStyle = FindStyleSheetByISTD( pEntry->sNextStyleIdentifier ); + if ( pFollowStyle && !pFollowStyle->sStyleName.isEmpty() ) + aMissingFollow.emplace_back( ConvertStyleName( pFollowStyle->sStyleName ), xStyle ); + } + + // Set the outline levels + StyleSheetPropertyMap* pStyleSheetProperties = pEntry ? pEntry->pProperties.get() : nullptr; + + if ( pStyleSheetProperties ) + { + sal_Int16 nLvl = pStyleSheetProperties->GetOutlineLevel(); + // convert MS body Level (9) to LO body level (0) and equivalent outline levels + if (nLvl != -1) + { + if (nLvl == WW_OUTLINE_MAX) + nLvl = 0; + else + ++nLvl; + + beans::PropertyValue aLvlVal(getPropertyName(PROP_OUTLINE_LEVEL), 0, + uno::Any(nLvl), + beans::PropertyState_DIRECT_VALUE); + aPropValues.push_back(aLvlVal); + } + } + + uno::Reference< beans::XPropertyState >xState( xStyle, uno::UNO_QUERY_THROW ); + if( sConvertedStyleName == "Contents Heading" || + sConvertedStyleName == "User Index Heading" || + sConvertedStyleName == "Index Heading" ) + { + // remove Left/RightMargin values from TOX heading styles + //left margin is set to NULL by default + xState->setPropertyToDefault(getPropertyName( PROP_PARA_LEFT_MARGIN )); + } + else if ( sConvertedStyleName == "Text body" ) + xState->setPropertyToDefault(getPropertyName( PROP_PARA_BOTTOM_MARGIN )); + else if ( sConvertedStyleName == "Heading 1" || + sConvertedStyleName == "Heading 2" || + sConvertedStyleName == "Heading 3" || + sConvertedStyleName == "Heading 4" || + sConvertedStyleName == "Heading 5" || + sConvertedStyleName == "Heading 6" || + sConvertedStyleName == "Heading 7" || + sConvertedStyleName == "Heading 8" || + sConvertedStyleName == "Heading 9" ) + { + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_ASIAN )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_COMPLEX )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_ASIAN )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_COMPLEX )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_ASIAN )); + xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_COMPLEX)); + + } + } + + if ( !aPropValues.empty() ) + { + PropValVector aSortedPropVals; + for (const beans::PropertyValue& rValue : aPropValues) + { + // Don't add the style name properties + bool bIsParaStyleName = rValue.Name == "ParaStyleName"; + bool bIsCharStyleName = rValue.Name == "CharStyleName"; + if ( !bIsParaStyleName && !bIsCharStyleName ) + { + aSortedPropVals.Insert(rValue); + } + } + + try + { + uno::Reference< beans::XMultiPropertySet > xMultiPropertySet( xStyle, uno::UNO_QUERY_THROW); + try + { + xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() ); + } + catch ( const uno::Exception& ) + { + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW); + for ( const beans::PropertyValue& rValue : aSortedPropVals.getProperties() ) + { + try + { + xPropertySet->setPropertyValue( rValue.Name, rValue.Value ); + } + catch ( const uno::Exception& ) + { + SAL_WARN( "writerfilter", "StyleSheetTable::ApplyStyleSheets could not set property " << rValue.Name ); + } + } + } + // Duplicate MSWord's single footnote reference into Footnote Characters and Footnote anchor + if( pEntry->sStyleName.equalsIgnoreAsciiCase("footnote reference") + || pEntry->sStyleName.equalsIgnoreAsciiCase("endnote reference") ) + { + uno::Reference< style::XStyle > xCopyStyle; + if( pEntry->sStyleName.equalsIgnoreAsciiCase("footnote reference") ) + xStyles->getByName( "Footnote anchor" ) >>= xCopyStyle; + else + xStyles->getByName( "Endnote anchor" ) >>= xCopyStyle; + + xMultiPropertySet.set( xCopyStyle, uno::UNO_QUERY_THROW); + xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() ); + } + } + catch( const lang::WrappedTargetException& rWrapped) + { +#ifdef DBG_UTIL + OUString aMessage("StyleSheetTable::ApplyStyleSheets: Some style properties could not be set"); + beans::UnknownPropertyException aUnknownPropertyException; + + if (rWrapped.TargetException >>= aUnknownPropertyException) + aMessage += ": " + aUnknownPropertyException.Message; + + SAL_WARN("writerfilter", aMessage); +#else + (void) rWrapped; +#endif + } + catch( const uno::Exception& ) + { + OSL_FAIL( "Some style properties could not be set"); + } + } + // Numbering style got inserted earlier. + if(bInsert && !bListStyle) + { + const OUString sParentStyle = xStyle->getParentStyle(); + if( !sParentStyle.isEmpty() && !xStyles->hasByName( sParentStyle ) ) + aMissingParent.emplace_back( sParentStyle, xStyle ); + + xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle) ); + } + + beans::PropertyValues aGrabBag = pEntry->GetInteropGrabBagSeq(); + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY); + if (aGrabBag.hasElements()) + { + xPropertySet->setPropertyValue("StyleInteropGrabBag", uno::Any(aGrabBag)); + } + + // Only paragraph styles support automatic updates. + if (pEntry->bAutoRedefine && bParaStyle) + xPropertySet->setPropertyValue("IsAutoUpdate", uno::Any(true)); + } + else if(pEntry->nStyleTypeCode == STYLE_TYPE_TABLE) + { + // If this is a table style, save its contents as-is for roundtrip purposes. + TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(pEntry.get()); + aTableStylesVec.push_back(pTableEntry->GetInteropGrabBag()); + + // if DocDefaults exist, MS Word includes these in the table style definition. + pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultCharProps, /*bOverwrite=*/false ); + pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false ); + } + } + + // Update the styles that were created before their parents or next-styles + for( auto const & iter : aMissingParent ) + { + iter.second->setParentStyle( iter.first ); + } + + for( auto const & iter : aMissingFollow ) + { + try + { + uno::Reference<beans::XPropertySet> xPropertySet(iter.second, uno::UNO_QUERY); + xPropertySet->setPropertyValue( "FollowStyle", uno::Any(iter.first) ); + } + catch( uno::Exception & ) {} + } + + // Update the styles that were created before their linked styles. + for (auto const& rLinked : aMissingLink) + { + try + { + uno::Reference<beans::XPropertySet> xPropertySet(rLinked.second, + uno::UNO_QUERY); + xPropertySet->setPropertyValue("LinkStyle", uno::Any(rLinked.first)); + } + catch (uno::Exception&) + { + TOOLS_WARN_EXCEPTION( + "writerfilter", + "StyleSheetTable::ApplyStyleSheets: failed to set LinkStyle"); + } + } + + if (!aTableStylesVec.empty()) + { + // If we had any table styles, add a new document-level InteropGrabBag entry for them. + uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY); + uno::Any aAny = xPropertySet->getPropertyValue("InteropGrabBag"); + auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >()); + beans::PropertyValue aValue; + aValue.Name = "tableStyles"; + aValue.Value <<= comphelper::containerToSequence(aTableStylesVec); + aGrabBag.push_back(aValue); + xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag))); + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Styles could not be imported completely"); + } +} + + +StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByISTD(const OUString& sIndex) +{ + auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(sIndex); + if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end()) + return findIt->second; + return StyleSheetEntryPtr(); +} + + +StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByConvertedStyleName(std::u16string_view sIndex) +{ + StyleSheetEntryPtr pRet; + for(const StyleSheetEntryPtr & rpEntry : m_pImpl->m_aStyleSheetEntries) + { + if( rpEntry->sConvertedStyleName == sIndex) + { + pRet = rpEntry; + break; + } + } + return pRet; +} + + +StyleSheetEntryPtr StyleSheetTable::FindDefaultParaStyle() +{ + return FindStyleSheetByISTD( m_pImpl->m_sDefaultParaStyleName ); +} + +const StyleSheetEntryPtr & StyleSheetTable::GetCurrentEntry() const +{ + return m_pImpl->m_pCurrentEntry; +} + +OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExtendedSearch) +{ + OUString sRet( rWWName ); + if( bExtendedSearch ) + { + //search for the rWWName in the IdentifierD of the existing styles and convert the sStyleName member + auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(rWWName); + if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end()) + sRet = findIt->second->sStyleName; + } + + // create a map only once + static const std::map< OUString, OUString> StyleNameMap { + { "Normal", "Standard" }, + { "heading 1", "Heading 1" }, + { "heading 2", "Heading 2" }, + { "heading 3", "Heading 3" }, + { "heading 4", "Heading 4" }, + { "heading 5", "Heading 5" }, + { "heading 6", "Heading 6" }, + { "heading 7", "Heading 7" }, + { "heading 8", "Heading 8" }, + { "heading 9", "Heading 9" }, + { "Heading 1", "Heading 1" }, + { "Heading 2", "Heading 2" }, + { "Heading 3", "Heading 3" }, + { "Heading 4", "Heading 4" }, + { "Heading 5", "Heading 5" }, + { "Heading 6", "Heading 6" }, + { "Heading 7", "Heading 7" }, + { "Heading 8", "Heading 8" }, + { "Heading 9", "Heading 9" }, + { "Index 1", "Index 1" }, + { "Index 2", "Index 2" }, + { "Index 3", "Index 3" }, +// { "Index 4", "" }, +// { "Index 5", "" }, +// { "Index 6", "" }, +// { "Index 7", "" }, +// { "Index 8", "" }, +// { "Index 9", "" }, + { "TOC 1", "Contents 1" }, + { "TOC 2", "Contents 2" }, + { "TOC 3", "Contents 3" }, + { "TOC 4", "Contents 4" }, + { "TOC 5", "Contents 5" }, + { "TOC 6", "Contents 6" }, + { "TOC 7", "Contents 7" }, + { "TOC 8", "Contents 8" }, + { "TOC 9", "Contents 9" }, + { "TOC Heading", "Contents Heading" }, + { "TOCHeading", "Contents Heading" }, + { "toc 1", "Contents 1" }, + { "toc 2", "Contents 2" }, + { "toc 3", "Contents 3" }, + { "toc 4", "Contents 4" }, + { "toc 5", "Contents 5" }, + { "toc 6", "Contents 6" }, + { "toc 7", "Contents 7" }, + { "toc 8", "Contents 8" }, + { "toc 9", "Contents 9" }, + { "TOC1", "Contents 1" }, + { "TOC2", "Contents 2" }, + { "TOC3", "Contents 3" }, + { "TOC4", "Contents 4" }, + { "TOC5", "Contents 5" }, + { "TOC6", "Contents 6" }, + { "TOC7", "Contents 7" }, + { "TOC8", "Contents 8" }, + { "TOC9", "Contents 9" }, +// { "Normal Indent", "" }, + { "footnote text", "Footnote" }, + { "Footnote Text", "Footnote" }, +// { "Annotation Text", "" }, + { "Header", "Header" }, + { "header", "Header" }, + { "Footer", "Footer" }, + { "footer", "Footer" }, + { "Index Heading", "Index Heading" }, +// { "Caption", "" }, +// { "Table of Figures", "" }, + { "Envelope Address", "Addressee" }, + { "Envelope Return", "Sender" }, + { "footnote reference", "Footnote Symbol" }, + { "Footnote Reference", "Footnote Symbol" }, +// { "Annotation Reference", "" }, + { "Line Number", "Line numbering" }, + { "Page Number", "Page Number" }, + { "endnote reference", "Endnote Symbol" }, + { "Endnote Reference", "Endnote Symbol" }, + { "endnote text", "Endnote" }, + { "Endnote Text", "Endnote" }, +// { "Table of Authorities", "" }, +// { "Macro Text", "" }, +// { "TOA Heading", "" }, + { "List", "List" }, +// { "List 2", "" }, +// { "List 3", "" }, +// { "List 4", "" }, +// { "List 5", "" }, +// { "List Bullet", "" }, +// { "List Bullet 2", "" }, +// { "List Bullet 3", "" }, +// { "List Bullet 4", "" }, +// { "List Bullet 5", "" }, +// { "List Number", "" }, +// { "List Number 2", "" }, +// { "List Number 3", "" }, +// { "List Number 4", "" }, +// { "List Number 5", "" }, + { "Title", "Title" }, +// { "Closing", "" }, + { "Signature", "Signature" }, +// { "Default Paragraph Font", "" }, + { "DefaultParagraphFont", "Default Paragraph Font" }, + { "Body Text", "Text body" }, + { "BodyText", "Text body" }, + { "BodyTextIndentItalic", "Text body indent italic" }, + { "Body Text Indent", "Text body indent" }, + { "BodyTextIndent", "Text body indent" }, + { "BodyTextIndent2", "Text body indent2" }, +// { "List Continue", "" }, +// { "List Continue 2", "" }, +// { "List Continue 3", "" }, +// { "List Continue 4", "" }, +// { "List Continue 5", "" }, +// { "Message Header", "" }, + { "Subtitle", "Subtitle" }, +// { "Salutation", "" }, +// { "Date", "" }, + { "Body Text First Indent", "Body Text Indent" }, +// { "Body Text First Indent 2", "" }, +// { "Note Heading", "" }, +// { "Body Text 2", "" }, +// { "Body Text 3", "" }, +// { "Body Text Indent 2", "" }, +// { "Body Text Indent 3", "" }, +// { "Block Text", "" }, + { "Hyperlink", "Internet link" }, + { "FollowedHyperlink", "Visited Internet Link" }, + { "Emphasis", "Emphasis" }, +// { "Document Map", "" }, +// { "Plain Text", "" }, + { "NoList", "No List" }, + { "AbstractHeading", "Abstract Heading" }, + { "AbstractBody", "Abstract Body" }, + { "PageNumber", "page number" }, + { "TableNormal", "Normal Table" }, + { "DocumentMap", "Document Map" }, + }; + + // find style-name using map + if (const auto aIt = StyleNameMap.find(sRet); aIt != StyleNameMap.end()) + { + sRet = aIt->second; + } + else + { + // Style names which should not be used without a " (user)" suffix + static const o3tl::sorted_vector<OUString> ReservedStyleNames = [] { + o3tl::sorted_vector<OUString> set; + for (const auto& pair : StyleNameMap) + set.insert(pair.second); + return set; + }(); + // SwStyleNameMapper doc says: If the UI style name equals a + // programmatic name, then it must append " (user)" to the end. + if (ReservedStyleNames.find(sRet) != ReservedStyleNames.end()) + sRet += " (user)"; + } + + return sRet; +} + +void StyleSheetTable::applyDefaults(bool bParaProperties) +{ + try{ + + if (!m_pImpl->m_bIsNewDoc) + { + // tdf#72942: do not corrupts original styles in master document + // during inserting of text from second document + return; + } + + if(!m_pImpl->m_xTextDefaults.is()) + { + m_pImpl->m_xTextDefaults.set( + m_pImpl->m_rDMapper.GetTextFactory()->createInstance("com.sun.star.text.Defaults"), + uno::UNO_QUERY_THROW ); + } + + // WARNING: these defaults only take effect IF there is a DocDefaults style section. Normally there is, but not always. + if( bParaProperties && m_pImpl->m_pDefaultParaProps) + { + // tdf#87533 LO will have different defaults here, depending on the locale. Import with documented defaults + SetDefaultParaProps(PROP_WRITING_MODE, uno::Any(sal_Int16(text::WritingMode_LR_TB))); + SetDefaultParaProps(PROP_PARA_ADJUST, uno::Any(sal_Int16(style::ParagraphAdjust_LEFT))); + + // Widow/Orphan -> set both to two if not already set + uno::Any aTwo(sal_Int8(2)); + SetDefaultParaProps(PROP_PARA_WIDOWS, aTwo); + SetDefaultParaProps(PROP_PARA_ORPHANS, aTwo); + + uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameAccess> xParagraphStyles; + xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles; + uno::Reference<beans::XPropertySet> xDefault; + // This is the built-in default style that every style inherits from + xParagraphStyles->getByName("Paragraph style") >>= xDefault; + + const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultParaProps->GetPropertyValues(); + for( const auto& rPropValue : aPropValues ) + { + try + { + xDefault->setPropertyValue(rPropValue.Name, rPropValue.Value); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "writerfilter", "setPropertyValue"); + } + } + } + if( !bParaProperties && m_pImpl->m_pDefaultCharProps ) + { + // tdf#108350: Earlier in DomainMapper for DOCX, Calibri/11pt was set to match MSWord 2007+, + // but that is valid only if DocDefaults_rPrDefault is omitted. + // Now that DocDefaults_rPrDefault is known, the defaults should be reset to Times New Roman/10pt. + if ( m_pImpl->m_rDMapper.IsOOXMLImport() ) + m_pImpl->m_xTextDefaults->setPropertyValue( getPropertyName(PROP_CHAR_FONT_NAME), css::uno::Any(OUString("Times New Roman")) ); + + const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultCharProps->GetPropertyValues(); + for( const auto& rPropValue : aPropValues ) + { + try + { + m_pImpl->m_xTextDefaults->setPropertyValue( rPropValue.Name, rPropValue.Value ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "writerfilter", "exception"); + } + } + } + } + catch( const uno::Exception& ) + { + } +} + + +OUString StyleSheetTable::getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate ) +{ + //find out if any of the styles already has the required properties then return its name + OUString sListLabel = m_pImpl->HasListCharStyle(rCharProperties); + // Don't try to reuse an existing character style if requested. + if( !sListLabel.isEmpty() && !bAlwaysCreate) + return sListLabel; + + //create a new one otherwise + const uno::Reference< container::XNameContainer >& xCharStyles = m_pImpl->m_rDMapper.GetCharacterStyles(); + sListLabel = m_pImpl->m_rDMapper.GetUnusedCharacterStyleName(); + uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + try + { + uno::Reference< style::XStyle > xStyle( xDocFactory->createInstance( + getPropertyName( PROP_SERVICE_CHAR_STYLE )), uno::UNO_QUERY_THROW); + uno::Reference< beans::XPropertySet > xStyleProps(xStyle, uno::UNO_QUERY_THROW ); + for( const auto& rCharProp : rCharProperties) + { + try + { + xStyleProps->setPropertyValue( rCharProp.Name, rCharProp.Value ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle - Style::setPropertyValue"); + } + } + xCharStyles->insertByName( sListLabel, uno::Any( xStyle) ); + m_pImpl->m_aListCharStylePropertyVector.emplace_back( sListLabel, std::vector(rCharProperties) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle"); + } + + return sListLabel; +} + +}//namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |