diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/unocore | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/unocore')
37 files changed, 56397 insertions, 0 deletions
diff --git a/sw/source/core/unocore/SwXTextDefaults.cxx b/sw/source/core/unocore/SwXTextDefaults.cxx new file mode 100644 index 0000000000..a74808141d --- /dev/null +++ b/sw/source/core/unocore/SwXTextDefaults.cxx @@ -0,0 +1,235 @@ +/* -*- 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 <com/sun/star/beans/PropertyAttribute.hpp> + +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> +#include <svl/itemprop.hxx> + +#include <SwXTextDefaults.hxx> +#include <SwStyleNameMapper.hxx> +#include <fchrfmt.hxx> +#include <charfmt.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <docstyle.hxx> +#include <doc.hxx> +#include <docsh.hxx> +#include <unomap.hxx> +#include <unomid.h> +#include <paratr.hxx> +#include <unocrsrhelper.hxx> +#include <hintids.hxx> +#include <fmtpdsc.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +SwXTextDefaults::SwXTextDefaults ( SwDoc * pNewDoc ) : + m_pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_DEFAULT ) ), + m_pDoc ( pNewDoc ) +{ +} + +SwXTextDefaults::~SwXTextDefaults () +{ +} + +uno::Reference< XPropertySetInfo > SAL_CALL SwXTextDefaults::getPropertySetInfo( ) +{ + static uno::Reference < XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SAL_CALL SwXTextDefaults::setPropertyValue( const OUString& rPropertyName, const Any& aValue ) +{ + SolarMutexGuard aGuard; + if (!m_pDoc) + throw RuntimeException(); + const SfxItemPropertyMapEntry *pMap = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if (!pMap) + throw UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + if ( pMap->nFlags & PropertyAttribute::READONLY) + throw PropertyVetoException ( "Property is read-only: " + rPropertyName, getXWeak() ); + + const SfxPoolItem& rItem = m_pDoc->GetDefault(pMap->nWID); + if (RES_PAGEDESC == pMap->nWID && MID_PAGEDESC_PAGEDESCNAME == pMap->nMemberId) + { + SfxItemSetFixed<RES_PAGEDESC, RES_PAGEDESC> aSet( m_pDoc->GetAttrPool() ); + aSet.Put(rItem); + SwUnoCursorHelper::SetPageDesc( aValue, *m_pDoc, aSet ); + m_pDoc->SetDefault(aSet.Get(RES_PAGEDESC)); + } + else if ((RES_PARATR_DROP == pMap->nWID && MID_DROPCAP_CHAR_STYLE_NAME == pMap->nMemberId) || + (RES_TXTATR_CHARFMT == pMap->nWID)) + { + OUString uStyle; + if(!(aValue >>= uStyle)) + throw lang::IllegalArgumentException(); + + OUString sStyle; + SwStyleNameMapper::FillUIName(uStyle, sStyle, SwGetPoolIdFromName::ChrFmt ); + SwDocStyleSheet* pStyle = + static_cast<SwDocStyleSheet*>(m_pDoc->GetDocShell()->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char)); + std::unique_ptr<SwFormatDrop> pDrop; + std::unique_ptr<SwFormatCharFormat> pCharFormat; + if(!pStyle) + throw lang::IllegalArgumentException(); + + rtl::Reference< SwDocStyleSheet > xStyle( new SwDocStyleSheet( *pStyle ) ); + if (xStyle->GetCharFormat() == m_pDoc->GetDfltCharFormat()) + return; // don't SetCharFormat with formats from mpDfltCharFormat + + if (RES_PARATR_DROP == pMap->nWID) + { + pDrop.reset(static_cast<SwFormatDrop*>(rItem.Clone())); // because rItem is const... + pDrop->SetCharFormat(xStyle->GetCharFormat()); + m_pDoc->SetDefault(*pDrop); + } + else // RES_TXTATR_CHARFMT == pMap->nWID + { + pCharFormat.reset(static_cast<SwFormatCharFormat*>(rItem.Clone())); // because rItem is const... + pCharFormat->SetCharFormat(xStyle->GetCharFormat()); + m_pDoc->SetDefault(*pCharFormat); + } + } + else + { + std::unique_ptr<SfxPoolItem> pNewItem(rItem.Clone()); + pNewItem->PutValue( aValue, pMap->nMemberId); + m_pDoc->SetDefault(*pNewItem); + } +} + +Any SAL_CALL SwXTextDefaults::getPropertyValue( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + if (!m_pDoc) + throw RuntimeException(); + const SfxItemPropertyMapEntry *pMap = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if (!pMap) + throw UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + Any aRet; + const SfxPoolItem& rItem = m_pDoc->GetDefault(pMap->nWID); + rItem.QueryValue( aRet, pMap->nMemberId ); + return aRet; +} + +void SAL_CALL SwXTextDefaults::addPropertyChangeListener( const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL ( "not implemented" ); +} + +void SAL_CALL SwXTextDefaults::removePropertyChangeListener( const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL ( "not implemented" ); +} + +void SAL_CALL SwXTextDefaults::addVetoableChangeListener( const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ ) +{ + OSL_FAIL ( "not implemented" ); +} + +void SAL_CALL SwXTextDefaults::removeVetoableChangeListener( const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ ) +{ + OSL_FAIL ( "not implemented" ); +} + +// XPropertyState +PropertyState SAL_CALL SwXTextDefaults::getPropertyState( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + PropertyState eRet = PropertyState_DIRECT_VALUE; + if (!m_pDoc) + throw RuntimeException(); + const SfxItemPropertyMapEntry *pMap = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if (!pMap) + throw UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + + const SfxPoolItem& rItem = m_pDoc->GetDefault(pMap->nWID); + if (IsStaticDefaultItem ( &rItem ) ) + eRet = PropertyState_DEFAULT_VALUE; + return eRet; +} + +Sequence< PropertyState > SAL_CALL SwXTextDefaults::getPropertyStates( const Sequence< OUString >& rPropertyNames ) +{ + const sal_Int32 nCount = rPropertyNames.getLength(); + Sequence < PropertyState > aRet ( nCount ); + + std::transform(rPropertyNames.begin(), rPropertyNames.end(), aRet.getArray(), + [this](const OUString& rName) -> PropertyState { return getPropertyState(rName); }); + + return aRet; +} + +void SAL_CALL SwXTextDefaults::setPropertyToDefault( const OUString& rPropertyName ) +{ + if (!m_pDoc) + throw RuntimeException(); + const SfxItemPropertyMapEntry *pMap = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if (!pMap) + throw UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + if ( pMap->nFlags & PropertyAttribute::READONLY) + throw RuntimeException( "setPropertyToDefault: property is read-only: " + rPropertyName, getXWeak() ); + SfxItemPool& rSet (m_pDoc->GetAttrPool()); + rSet.ResetPoolDefaultItem ( pMap->nWID ); +} + +Any SAL_CALL SwXTextDefaults::getPropertyDefault( const OUString& rPropertyName ) +{ + if (!m_pDoc) + throw RuntimeException(); + const SfxItemPropertyMapEntry *pMap = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if (!pMap) + throw UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + Any aRet; + SfxItemPool& rSet (m_pDoc->GetAttrPool()); + SfxPoolItem const*const pItem = rSet.GetPoolDefaultItem(pMap->nWID); + if (pItem) + { + pItem->QueryValue( aRet, pMap->nMemberId ); + } + return aRet; +} + +OUString SAL_CALL SwXTextDefaults::getImplementationName( ) +{ + return "SwXTextDefaults"; +} + +sal_Bool SAL_CALL SwXTextDefaults::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwXTextDefaults::getSupportedServiceNames( ) +{ + return { "com.sun.star.text.Defaults", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/TextCursorHelper.cxx b/sw/source/core/unocore/TextCursorHelper.cxx new file mode 100644 index 0000000000..fad4ebe0ab --- /dev/null +++ b/sw/source/core/unocore/TextCursorHelper.cxx @@ -0,0 +1,25 @@ +/* -*- 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 <TextCursorHelper.hxx> +#include <comphelper/servicehelper.hxx> + +OTextCursorHelper::~OTextCursorHelper() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/XMLRangeHelper.cxx b/sw/source/core/unocore/XMLRangeHelper.cxx new file mode 100644 index 0000000000..6464543d51 --- /dev/null +++ b/sw/source/core/unocore/XMLRangeHelper.cxx @@ -0,0 +1,387 @@ +/* -*- 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 "XMLRangeHelper.hxx" +#include <rtl/character.hxx> +#include <rtl/ustrbuf.hxx> +#include <o3tl/string_view.hxx> +#include <algorithm> + +namespace +{ +/** unary function that escapes backslashes and single quotes in a sal_Unicode + array (which you can get from an OUString with getStr()) and puts the result + into the OUStringBuffer given in the CTOR + */ +class lcl_Escape +{ +public: + explicit lcl_Escape( OUStringBuffer & aResultBuffer ) : m_aResultBuffer( aResultBuffer ) {} + void operator() ( sal_Unicode aChar ) + { + static const sal_Unicode s_aQuote( '\'' ); + static const sal_Unicode s_aBackslash( '\\' ); + + if( aChar == s_aQuote || + aChar == s_aBackslash ) + m_aResultBuffer.append( s_aBackslash ); + m_aResultBuffer.append( aChar ); + } + +private: + OUStringBuffer & m_aResultBuffer; +}; + +/** unary function that removes backslash escapes in a sal_Unicode array (which + you can get from an OUString with getStr()) and puts the result into the + OUStringBuffer given in the CTOR + */ +class lcl_UnEscape +{ +public: + explicit lcl_UnEscape( OUStringBuffer & aResultBuffer ) : m_aResultBuffer( aResultBuffer ) {} + void operator() ( sal_Unicode aChar ) + { + static const sal_Unicode s_aBackslash( '\\' ); + + if( aChar != s_aBackslash ) + m_aResultBuffer.append( aChar ); + } + +private: + OUStringBuffer & m_aResultBuffer; +}; + +void lcl_getXMLStringForCell( const /*::chart::*/XMLRangeHelper::Cell & rCell, OUStringBuffer * output ) +{ + assert(output != nullptr); + + if( rCell.empty()) + return; + + sal_Int32 nCol = rCell.nColumn; + output->append( '.' ); + if( ! rCell.bRelativeColumn ) + output->append( '$' ); + + // get A, B, C, ..., AA, AB, ... representation of column number + if( nCol < 26 ) + output->append( static_cast<sal_Unicode>('A' + nCol) ); + else if( nCol < 702 ) + { + output->append( static_cast<sal_Unicode>('A' + nCol / 26 - 1 )); + output->append( static_cast<sal_Unicode>('A' + nCol % 26) ); + } + else // works for nCol <= 18,278 + { + output->append( static_cast<sal_Unicode>('A' + nCol / 702 - 1 )); + output->append( static_cast<sal_Unicode>('A' + (nCol % 702) / 26 )); + output->append( static_cast<sal_Unicode>('A' + nCol % 26) ); + } + + // write row number as number + if( ! rCell.bRelativeRow ) + output->append( '$' ); + output->append( rCell.nRow + sal_Int32(1) ); +} + +void lcl_getSingleCellAddressFromXMLString( + std::u16string_view rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + /*::chart::*/XMLRangeHelper::Cell & rOutCell ) +{ + // expect "\$?[a-zA-Z]+\$?[1-9][0-9]*" + static const sal_Unicode aDollar( '$' ); + static const sal_Unicode aLetterA( 'A' ); + + OUString aCellStr = OUString(rXMLString.substr( nStartPos, nEndPos - nStartPos + 1 )).toAsciiUpperCase(); + const sal_Unicode* pStrArray = aCellStr.getStr(); + sal_Int32 nLength = aCellStr.getLength(); + sal_Int32 i = nLength - 1, nColumn = 0; + + // parse number for row + while( rtl::isAsciiDigit( pStrArray[ i ] ) && i >= 0 ) + i--; + rOutCell.nRow = (o3tl::toInt32(aCellStr.subView( i + 1 ))) - 1; + // a dollar in XML means absolute (whereas in UI it means relative) + if( pStrArray[ i ] == aDollar ) + { + i--; + rOutCell.bRelativeRow = false; + } + else + rOutCell.bRelativeRow = true; + + // parse rest for column + sal_Int32 nPower = 1; + while( rtl::isAsciiAlpha( pStrArray[ i ] )) + { + nColumn += (pStrArray[ i ] - aLetterA + 1) * nPower; + i--; + nPower *= 26; + } + rOutCell.nColumn = nColumn - 1; + + rOutCell.bRelativeColumn = true; + if( i >= 0 && + pStrArray[ i ] == aDollar ) + rOutCell.bRelativeColumn = false; + rOutCell.bIsEmpty = false; +} + +bool lcl_getCellAddressFromXMLString( + const OUString& rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + /*::chart::*/XMLRangeHelper::Cell & rOutCell, + OUString& rOutTableName ) +{ + static const sal_Unicode aDot( '.' ); + static const sal_Unicode aQuote( '\'' ); + static const sal_Unicode aBackslash( '\\' ); + + sal_Int32 nNextDelimiterPos = nStartPos; + + sal_Int32 nDelimiterPos = nStartPos; + bool bInQuotation = false; + // parse table name + while( nDelimiterPos < nEndPos && + ( bInQuotation || rXMLString[ nDelimiterPos ] != aDot )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nDelimiterPos ] == aBackslash ) + ++nDelimiterPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nDelimiterPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nDelimiterPos; + } + + if( nDelimiterPos == -1 || + nDelimiterPos >= nEndPos ) + { + return false; + } + if( nDelimiterPos > nStartPos ) + { + // there is a table name before the address + + OUStringBuffer aTableNameBuffer; + const sal_Unicode * pTableName = rXMLString.getStr(); + + // remove escapes from table name + std::for_each( pTableName + nStartPos, + pTableName + nDelimiterPos, + lcl_UnEscape( aTableNameBuffer )); + + // unquote quoted table name + const sal_Unicode * pBuf = aTableNameBuffer.getStr(); + if( pBuf[ 0 ] == aQuote && + pBuf[ aTableNameBuffer.getLength() - 1 ] == aQuote ) + { + OUString aName = aTableNameBuffer.makeStringAndClear(); + rOutTableName = aName.copy( 1, aName.getLength() - 2 ); + } + else + rOutTableName = aTableNameBuffer.makeStringAndClear(); + } + + for( sal_Int32 i = 0; + nNextDelimiterPos < nEndPos; + nDelimiterPos = nNextDelimiterPos, i++ ) + { + nNextDelimiterPos = rXMLString.indexOf( aDot, nDelimiterPos + 1 ); + if( nNextDelimiterPos == -1 || + nNextDelimiterPos > nEndPos ) + nNextDelimiterPos = nEndPos + 1; + + if( i==0 ) + // only take first cell + lcl_getSingleCellAddressFromXMLString( + rXMLString, nDelimiterPos + 1, nNextDelimiterPos - 1, rOutCell ); + } + + return true; +} + +bool lcl_getCellRangeAddressFromXMLString( + const OUString& rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + /*::chart::*/XMLRangeHelper::CellRange & rOutRange ) +{ + bool bResult = true; + static const sal_Unicode aColon( ':' ); + static const sal_Unicode aQuote( '\'' ); + static const sal_Unicode aBackslash( '\\' ); + + sal_Int32 nDelimiterPos = nStartPos; + bool bInQuotation = false; + // parse table name + while( nDelimiterPos < nEndPos && + ( bInQuotation || rXMLString[ nDelimiterPos ] != aColon )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nDelimiterPos ] == aBackslash ) + ++nDelimiterPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nDelimiterPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nDelimiterPos; + } + + if( nDelimiterPos == nEndPos ) + { + // only one cell + bResult = lcl_getCellAddressFromXMLString( rXMLString, nStartPos, nEndPos, + rOutRange.aUpperLeft, + rOutRange.aTableName ); + } + else + { + // range (separated by a colon) + bResult = lcl_getCellAddressFromXMLString( rXMLString, nStartPos, nDelimiterPos - 1, + rOutRange.aUpperLeft, + rOutRange.aTableName ); + OUString sTableSecondName; + if( bResult ) + { + bResult = lcl_getCellAddressFromXMLString( rXMLString, nDelimiterPos + 1, nEndPos, + rOutRange.aLowerRight, + sTableSecondName ); + } + if( bResult && + !sTableSecondName.isEmpty() && + sTableSecondName != rOutRange.aTableName ) + bResult = false; + } + + return bResult; +} + +} // anonymous namespace + +namespace XMLRangeHelper +{ + +CellRange getCellRangeFromXMLString( const OUString & rXMLString ) +{ + static const sal_Unicode aSpace( ' ' ); + static const sal_Unicode aQuote( '\'' ); + static const sal_Unicode aDollar( '$' ); + static const sal_Unicode aBackslash( '\\' ); + + sal_Int32 nStartPos = 0; + sal_Int32 nEndPos = nStartPos; + const sal_Int32 nLength = rXMLString.getLength(); + + // reset + CellRange aResult; + + // iterate over different ranges + for( sal_Int32 i = 0; + nEndPos < nLength; + nStartPos = ++nEndPos, i++ ) + { + // find start point of next range + + // ignore leading '$' + if( rXMLString[ nEndPos ] == aDollar) + nEndPos++; + + bool bInQuotation = false; + // parse range + while( nEndPos < nLength && + ( bInQuotation || rXMLString[ nEndPos ] != aSpace )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nEndPos ] == aBackslash ) + ++nEndPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nEndPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nEndPos; + } + + if( ! lcl_getCellRangeAddressFromXMLString( + rXMLString, + nStartPos, nEndPos - 1, + aResult )) + { + // if an error occurred, bail out + return CellRange(); + } + } + + return aResult; +} + +OUString getXMLStringFromCellRange( const CellRange & rRange ) +{ + static const sal_Unicode aSpace( ' ' ); + static const sal_Unicode aQuote( '\'' ); + + OUStringBuffer aBuffer; + + if( !rRange.aTableName.isEmpty()) + { + bool bNeedsEscaping = ( rRange.aTableName.indexOf( aQuote ) > -1 ); + bool bNeedsQuoting = bNeedsEscaping || ( rRange.aTableName.indexOf( aSpace ) > -1 ); + + // quote table name if it contains spaces or quotes + if( bNeedsQuoting ) + { + // leading quote + aBuffer.append( aQuote ); + + // escape existing quotes + if( bNeedsEscaping ) + { + const sal_Unicode * pTableNameBeg = rRange.aTableName.getStr(); + + // append the quoted string at the buffer + std::for_each( pTableNameBeg, + pTableNameBeg + rRange.aTableName.getLength(), + lcl_Escape( aBuffer ) ); + } + else + aBuffer.append( rRange.aTableName ); + + // final quote + aBuffer.append( aQuote ); + } + else + aBuffer.append( rRange.aTableName ); + } + lcl_getXMLStringForCell( rRange.aUpperLeft, &aBuffer ); + + if( ! rRange.aLowerRight.empty()) + { + // we have a range (not a single cell) + aBuffer.append( ':' ); + lcl_getXMLStringForCell( rRange.aLowerRight, &aBuffer ); + } + + return aBuffer.makeStringAndClear(); +} + +} // namespace XMLRangeHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/XMLRangeHelper.hxx b/sw/source/core/unocore/XMLRangeHelper.hxx new file mode 100644 index 0000000000..51966860fb --- /dev/null +++ b/sw/source/core/unocore/XMLRangeHelper.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +//!! +//!! This file is an exact copy of the same file in chart2 project +//!! + +#ifndef INCLUDED_SW_SOURCE_CORE_UNOCORE_XMLRANGEHELPER_HXX +#define INCLUDED_SW_SOURCE_CORE_UNOCORE_XMLRANGEHELPER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +namespace XMLRangeHelper +{ + +struct Cell +{ + sal_Int32 nColumn; + sal_Int32 nRow; + bool bRelativeColumn; + bool bRelativeRow; + bool bIsEmpty; + + Cell() : + nColumn(0), + nRow(0), + bRelativeColumn(false), + bRelativeRow(false), + bIsEmpty(true) + {} + + bool empty() const { return bIsEmpty; } +}; + +struct CellRange +{ + Cell aUpperLeft; + Cell aLowerRight; + OUString aTableName; +}; + +CellRange getCellRangeFromXMLString( const OUString & rXMLString ); + +OUString getXMLStringFromCellRange( const CellRange & rRange ); + +} // namespace XMLRangeHelper + +// INCLUDED_SW_SOURCE_CORE_UNOCORE_XMLRANGEHELPER_HXX +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/swunohelper.cxx b/sw/source/core/unocore/swunohelper.cxx new file mode 100644 index 0000000000..0aab2a681a --- /dev/null +++ b/sw/source/core/unocore/swunohelper.cxx @@ -0,0 +1,337 @@ +/* -*- 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 <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> +#include <com/sun/star/ucb/XContentIdentifier.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/extract.hxx> +#include <o3tl/any.hxx> +#include <tools/urlobj.hxx> +#include <tools/datetime.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> +#include <ucbhelper/contentidentifier.hxx> +#include <ucbhelper/content.hxx> +#include <swunohelper.hxx> +#include <svx/xdef.hxx> +#include <svx/xfillit0.hxx> +#include <editeng/memberids.h> +#include <svl/itemset.hxx> + +using namespace com::sun::star; + +namespace SWUnoHelper +{ + +sal_Int32 GetEnumAsInt32( const css::uno::Any& rVal ) +{ + sal_Int32 nReturn = 0; + if (! ::cppu::enum2int(nReturn,rVal) ) + OSL_FAIL( "can't get EnumAsInt32" ); + return nReturn; +} + +// methods for UCB actions +bool UCB_DeleteFile( const OUString& rURL ) +{ + bool bRemoved; + try + { + ucbhelper::Content aTempContent( rURL, + css::uno::Reference< css::ucb::XCommandEnvironment >(), + comphelper::getProcessComponentContext() ); + aTempContent.executeCommand("delete", css::uno::Any( true ) ); + bRemoved = true; + } + catch( css::uno::Exception& ) + { + bRemoved = false; + TOOLS_WARN_EXCEPTION( "sw", "Exception from executeCommand( delete )" ); + } + return bRemoved; +} + +bool UCB_MoveFile( const OUString& rURL, std::u16string_view rNewURL ) +{ + bool bCopyCompleted = true; + try + { + INetURLObject aURL( rNewURL ); + const OUString sName(aURL.GetLastName()); + aURL.removeSegment(); + const OUString sMainURL( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE) ); + + ucbhelper::Content aTempContent( sMainURL, + css::uno::Reference< css::ucb::XCommandEnvironment >(), + comphelper::getProcessComponentContext() ); + + css::ucb::TransferInfo aInfo; + aInfo.NameClash = css::ucb::NameClash::ERROR; + aInfo.NewTitle = sName; + aInfo.SourceURL = rURL; + aInfo.MoveData = true; + aTempContent.executeCommand( "transfer", uno::Any(aInfo) ); + } + catch( css::uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "sw", "Exception from executeCommand( transfer )" ); + bCopyCompleted = false; + } + return bCopyCompleted; +} + +bool UCB_IsCaseSensitiveFileName( std::u16string_view rURL ) +{ + bool bCaseSensitive; + try + { + INetURLObject aTempObj( rURL ); + aTempObj.SetBase( aTempObj.GetBase().toAsciiLowerCase() ); + css::uno::Reference< css::ucb::XContentIdentifier > xRef1 = new + ucbhelper::ContentIdentifier( aTempObj.GetMainURL( INetURLObject::DecodeMechanism::NONE )); + + aTempObj.SetBase(aTempObj.GetBase().toAsciiUpperCase()); + css::uno::Reference< css::ucb::XContentIdentifier > xRef2 = new + ucbhelper::ContentIdentifier( aTempObj.GetMainURL( INetURLObject::DecodeMechanism::NONE )); + + css::uno::Reference< css::ucb::XUniversalContentBroker > xUcb = + css::ucb::UniversalContentBroker::create(comphelper::getProcessComponentContext()); + + sal_Int32 nCompare = xUcb->compareContentIds( xRef1, xRef2 ); + bCaseSensitive = 0 != nCompare; + } + catch( css::uno::Exception& ) + { + bCaseSensitive = false; + TOOLS_WARN_EXCEPTION( "sw", "compareContentIds()" ); + } + return bCaseSensitive; +} + +bool UCB_IsReadOnlyFileName( const OUString& rURL ) +{ + bool bIsReadOnly = false; + try + { + ucbhelper::Content aCnt( rURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + css::uno::Any aAny = aCnt.getPropertyValue("IsReadOnly"); + if(aAny.hasValue()) + bIsReadOnly = *o3tl::doAccess<bool>(aAny); + } + catch( css::uno::Exception& ) + { + bIsReadOnly = false; + } + return bIsReadOnly; +} + +bool UCB_IsFile( const OUString& rURL ) +{ + bool bExists = false; + try + { + ::ucbhelper::Content aContent( rURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + bExists = aContent.isDocument(); + } + catch (css::uno::Exception &) + { + } + return bExists; +} + +bool UCB_IsDirectory( const OUString& rURL ) +{ + bool bExists = false; + try + { + ::ucbhelper::Content aContent( rURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + bExists = aContent.isFolder(); + } + catch (css::uno::Exception &) + { + } + return bExists; +} + + // get a list of files from the folder of the URL + // options: pExtension = 0 -> all, else this specific extension + // pDateTime != 0 -> returns also the modified date/time of + // the files in a std::vector<OUString> --> + // !! objects must be deleted from the caller!! +bool UCB_GetFileListOfFolder( const OUString& rURL, + std::vector<OUString>& rList, + const OUString* pExtension, + std::vector< ::DateTime >* pDateTimeList ) +{ + bool bOk = false; + try + { + ucbhelper::Content aCnt( rURL, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + css::uno::Reference< css::sdbc::XResultSet > xResultSet; + + const sal_Int32 nSeqSize = pDateTimeList ? 2 : 1; + css::uno::Sequence < OUString > aProps( nSeqSize ); + OUString* pProps = aProps.getArray(); + pProps[ 0 ] = "Title"; + if( pDateTimeList ) + pProps[ 1 ] = "DateModified"; + + try + { + xResultSet = aCnt.createCursor( aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ); + } + catch( css::uno::Exception& ) + { + OSL_FAIL( "create cursor failed!" ); + } + + if( xResultSet.is() ) + { + css::uno::Reference< css::sdbc::XRow > xRow( xResultSet, css::uno::UNO_QUERY ); + const sal_Int32 nExtLen = pExtension ? pExtension->getLength() : 0; + try + { + if( xResultSet->first() ) + { + do { + const OUString sTitle( xRow->getString( 1 ) ); + if( !nExtLen || + ( sTitle.getLength() > nExtLen && + sTitle.endsWith( *pExtension )) ) + { + rList.push_back( sTitle ); + + if( pDateTimeList ) + { + css::util::DateTime aStamp = xRow->getTimestamp(2); + ::DateTime aDateTime( + ::Date( aStamp.Day, + aStamp.Month, + aStamp.Year ), + ::tools::Time( aStamp.Hours, + aStamp.Minutes, + aStamp.Seconds, + aStamp.NanoSeconds )); + pDateTimeList->push_back( aDateTime ); + } + } + + } while( xResultSet->next() ); + } + bOk = true; + } + catch( css::uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "sw", "" ); + } + } + } + catch( css::uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "sw", "" ); + bOk = false; + } + return bOk; +} + +bool needToMapFillItemsToSvxBrushItemTypes(const SfxItemSet& rSet, + sal_uInt16 const nMID) +{ + const XFillStyleItem* pXFillStyleItem(rSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE, false)); + + if(!pXFillStyleItem) + { + return false; + } + + // here different FillStyles can be excluded for export; it will depend on the + // quality these fallbacks can reach. That again is done in getSvxBrushItemFromSourceSet, + // take a look there how the superset of DrawObject FillStyles is mapped to SvxBrushItem. + const drawing::FillStyle eFill = pXFillStyleItem->GetValue(); + switch (eFill) + { + case drawing::FillStyle_NONE: + // claim that BackColor and BackTransparent are available so that + // fo:background="transparent" attribute is exported to override + // the parent style in case it is != NONE + switch (nMID) + { + case MID_BACK_COLOR: + case MID_BACK_COLOR_R_G_B: + case MID_GRAPHIC_TRANSPARENT: // this is *BackTransparent + return true; + default: + return false; + } + break; + case drawing::FillStyle_SOLID: + case drawing::FillStyle_GRADIENT: // gradient and hatch don't exist in + case drawing::FillStyle_HATCH: // SvxBrushItem so average color is emulated + switch (nMID) + { + case MID_BACK_COLOR: + case MID_GRAPHIC_TRANSPARENT: // this is *BackTransparent + // Gradient/Hatch always have emulated color + return (drawing::FillStyle_SOLID != eFill) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLCOLOR) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLTRANSPARENCE) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE); + case MID_BACK_COLOR_R_G_B: + // Gradient/Hatch always have emulated color + return (drawing::FillStyle_SOLID != eFill) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLCOLOR); + case MID_BACK_COLOR_TRANSPARENCY: + return SfxItemState::SET == rSet.GetItemState(XATTR_FILLTRANSPARENCE) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE); + } + break; + case drawing::FillStyle_BITMAP: + switch (nMID) + { + case MID_GRAPHIC: + return SfxItemState::SET == rSet.GetItemState(XATTR_FILLBITMAP); + case MID_GRAPHIC_POSITION: + return SfxItemState::SET == rSet.GetItemState(XATTR_FILLBMP_STRETCH) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLBMP_TILE) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLBMP_POS); + case MID_GRAPHIC_TRANSPARENT: + case MID_GRAPHIC_TRANSPARENCY: + return SfxItemState::SET == rSet.GetItemState(XATTR_FILLTRANSPARENCE) + || SfxItemState::SET == rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE); + } + break; + default: + assert(false); + } + + + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx new file mode 100644 index 0000000000..81818a13d0 --- /dev/null +++ b/sw/source/core/unocore/unobkm.cxx @@ -0,0 +1,863 @@ +/* -*- 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 <unobookmark.hxx> + +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svl/itemprop.hxx> +#include <svl/listener.hxx> +#include <vcl/svapp.hxx> +#include <xmloff/odffields.hxx> + +#include <TextCursorHelper.hxx> +#include <unotextrange.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <IMark.hxx> +#include <crossrefbookmark.hxx> +#include <doc.hxx> +#include <docsh.hxx> + +using namespace ::sw::mark; +using namespace ::com::sun::star; + +class SwXBookmark::Impl + : public SvtListener +{ +public: + unotools::WeakReference<SwXBookmark> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper3 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + SwDoc* m_pDoc; + ::sw::mark::IMark* m_pRegisteredBookmark; + OUString m_sMarkName; + bool m_bHidden; + OUString m_HideCondition; + + Impl( SwDoc *const pDoc ) + : m_pDoc(pDoc) + , m_pRegisteredBookmark(nullptr) + , m_bHidden(false) + { + // DO NOT registerInMark here! (because SetXBookmark would delete rThis) + } + + void registerInMark(SwXBookmark & rThis, ::sw::mark::IMark *const pBkmk); +protected: + virtual void Notify(const SfxHint&) override; + +}; + +void SwXBookmark::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pRegisteredBookmark = nullptr; + m_pDoc = nullptr; + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); + } +} + +void SwXBookmark::Impl::registerInMark(SwXBookmark& rThis, + ::sw::mark::IMark* const pBkmk) +{ + const rtl::Reference<SwXBookmark> xBookmark(&rThis); + if (pBkmk) + { + EndListeningAll(); + StartListening(pBkmk->GetNotifier()); + ::sw::mark::MarkBase *const pMarkBase(dynamic_cast< ::sw::mark::MarkBase * >(pBkmk)); + OSL_ENSURE(pMarkBase, "registerInMark: no MarkBase?"); + if (pMarkBase) + { + pMarkBase->SetXBookmark(xBookmark); + } + assert(m_pDoc == nullptr || m_pDoc == &pBkmk->GetMarkPos().GetDoc()); + m_pDoc = &pBkmk->GetMarkPos().GetDoc(); + } + else if (m_pRegisteredBookmark) + { + m_sMarkName = m_pRegisteredBookmark->GetName(); + + // the following applies only to bookmarks (not to fieldmarks) + IBookmark* pBookmark = dynamic_cast<IBookmark*>(m_pRegisteredBookmark); + if (pBookmark) + { + m_bHidden = pBookmark->IsHidden(); + m_HideCondition = pBookmark->GetHideCondition(); + } + EndListeningAll(); + } + m_pRegisteredBookmark = pBkmk; + // need a permanent Reference to initialize m_wThis + m_wThis = xBookmark.get(); +} + +void SwXBookmark::registerInMark(SwXBookmark & rThis, + ::sw::mark::IMark *const pBkmk) +{ + m_pImpl->registerInMark( rThis, pBkmk ); +} + +::sw::mark::IMark* SwXBookmark::GetBookmark() const +{ + return m_pImpl->m_pRegisteredBookmark; +} + +IDocumentMarkAccess* SwXBookmark::GetIDocumentMarkAccess() +{ + return m_pImpl->m_pDoc->getIDocumentMarkAccess(); +} + +SwDoc * SwXBookmark::GetDoc() +{ + return m_pImpl->m_pDoc; +} + +SwXBookmark::SwXBookmark(SwDoc *const pDoc) + : m_pImpl( new SwXBookmark::Impl(pDoc) ) +{ +} + +SwXBookmark::SwXBookmark() + : m_pImpl( new SwXBookmark::Impl(nullptr) ) +{ +} + +SwXBookmark::~SwXBookmark() +{ +} + +rtl::Reference<SwXBookmark> SwXBookmark::CreateXBookmark( + SwDoc & rDoc, + ::sw::mark::IMark *const pBookmark) +{ + // #i105557#: do not iterate over the registered clients: race condition + ::sw::mark::MarkBase *const pMarkBase(dynamic_cast< ::sw::mark::MarkBase * >(pBookmark)); + OSL_ENSURE(!pBookmark || pMarkBase, "CreateXBookmark: no MarkBase?"); + rtl::Reference<SwXBookmark> xBookmark; + if (pMarkBase) + { + xBookmark = pMarkBase->GetXBookmark(); + } + if (!xBookmark.is()) + { + OSL_ENSURE(!pBookmark || + dynamic_cast< ::sw::mark::IBookmark* >(pBookmark) || + IDocumentMarkAccess::GetType(*pBookmark) == IDocumentMarkAccess::MarkType::ANNOTATIONMARK, + "<SwXBookmark::GetObject(..)>" + "SwXBookmark requested for non-bookmark mark and non-annotation mark."); + SwXBookmark *const pXBookmark = + pBookmark ? new SwXBookmark(&rDoc) : new SwXBookmark; + xBookmark.set(pXBookmark); + pXBookmark->m_pImpl->registerInMark(*pXBookmark, pMarkBase); + } + return xBookmark; +} + +::sw::mark::IMark const* SwXBookmark::GetBookmarkInDoc(SwDoc const*const pDoc, + const uno::Reference<uno::XInterface> & xUT) +{ + SwXBookmark *const pXBkm = dynamic_cast<SwXBookmark*>(xUT.get()); + if (pXBkm && (pDoc == pXBkm->m_pImpl->m_pDoc)) + { + return pXBkm->m_pImpl->m_pRegisteredBookmark; + } + return nullptr; +} + +void SwXBookmark::attachToRangeEx( + const uno::Reference< text::XTextRange > & xTextRange, + IDocumentMarkAccess::MarkType eType, + bool const isFieldmarkSeparatorAtStart) +{ + if (m_pImpl->m_pRegisteredBookmark) + { + throw uno::RuntimeException(); + } + + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwDoc *const pDoc = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDoc) + { + throw lang::IllegalArgumentException(); + } + + m_pImpl->m_pDoc = pDoc; + SwUnoInternalPaM aPam(*m_pImpl->m_pDoc); + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + UnoActionContext aCont(m_pImpl->m_pDoc); + if (m_pImpl->m_sMarkName.isEmpty()) + { + m_pImpl->m_sMarkName = "Bookmark"; + } + if ((eType == IDocumentMarkAccess::MarkType::BOOKMARK) && + ::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_pImpl->m_sMarkName)) + { + eType = IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK; + } + else if ((eType == IDocumentMarkAccess::MarkType::BOOKMARK) && + ::sw::mark::CrossRefHeadingBookmark::IsLegalName(m_pImpl->m_sMarkName) && + IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( aPam ) ) + { + eType = IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK; + } + m_pImpl->registerInMark(*this, + m_pImpl->m_pDoc->getIDocumentMarkAccess()->makeMark( + aPam, m_pImpl->m_sMarkName, eType, ::sw::mark::InsertMode::New, + // note: aPam will be moved fwd by inserting start char, so sep + // will be directly following start + isFieldmarkSeparatorAtStart ? aPam.Start() : nullptr)); + // #i81002# + // Check, if bookmark has been created. + // E.g., the creation of a cross-reference bookmark is suppress, + // if the PaM isn't a valid one for cross-reference bookmarks. + if (!m_pImpl->m_pRegisteredBookmark) + { + OSL_FAIL("<SwXBookmark::attachToRange(..)>" + " - could not create Mark."); + throw lang::IllegalArgumentException(); + } +} + +void SwXBookmark::attachToRange( const uno::Reference< text::XTextRange > & xTextRange ) +{ + attachToRangeEx(xTextRange, IDocumentMarkAccess::MarkType::BOOKMARK); +} + +void SAL_CALL SwXBookmark::attach( const uno::Reference< text::XTextRange > & xTextRange ) +{ + SolarMutexGuard aGuard; + attachToRange( xTextRange ); +} + +uno::Reference< text::XTextRange > SAL_CALL SwXBookmark::getAnchor() +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_pRegisteredBookmark) + { + throw uno::RuntimeException(); + } + return SwXTextRange::CreateXTextRange( + *m_pImpl->m_pDoc, + m_pImpl->m_pRegisteredBookmark->GetMarkPos(), + (m_pImpl->m_pRegisteredBookmark->IsExpanded()) + ? &m_pImpl->m_pRegisteredBookmark->GetOtherMarkPos() : nullptr); +} + +void SAL_CALL SwXBookmark::dispose() +{ + SolarMutexGuard aGuard; + if (m_pImpl->m_pRegisteredBookmark) + { + m_pImpl->m_pDoc->getIDocumentMarkAccess()->deleteMark( m_pImpl->m_pRegisteredBookmark ); + } +} + +void SAL_CALL SwXBookmark::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXBookmark::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +OUString SAL_CALL SwXBookmark::getName() +{ + SolarMutexGuard aGuard; + + return (m_pImpl->m_pRegisteredBookmark) + ? m_pImpl->m_pRegisteredBookmark->GetName() + : m_pImpl->m_sMarkName; +} + +void SAL_CALL SwXBookmark::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_pRegisteredBookmark) + { + m_pImpl->m_sMarkName = rName; + } + if (!m_pImpl->m_pRegisteredBookmark || (getName() == rName)) + { + return; + } + IDocumentMarkAccess *const pMarkAccess = + m_pImpl->m_pDoc->getIDocumentMarkAccess(); + if(pMarkAccess->findMark(rName) != pMarkAccess->getAllMarksEnd()) + { + throw uno::RuntimeException("setName(): name already in use", + getXWeak()); + } + + SwPaM aPam(m_pImpl->m_pRegisteredBookmark->GetMarkPos()); + if (m_pImpl->m_pRegisteredBookmark->IsExpanded()) + { + aPam.SetMark(); + *aPam.GetMark() = m_pImpl->m_pRegisteredBookmark->GetOtherMarkPos(); + } + + pMarkAccess->renameMark(m_pImpl->m_pRegisteredBookmark, rName); +} + +OUString SAL_CALL +SwXBookmark::getImplementationName() +{ + return "SwXBookmark"; +} + +sal_Bool SAL_CALL SwXBookmark::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXBookmark::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.Bookmark", + "com.sun.star.document.LinkTarget" + }; +} + +// MetadatableMixin +::sfx2::Metadatable* SwXBookmark::GetCoreObject() +{ + return dynamic_cast< ::sfx2::Metadatable* >(m_pImpl->m_pRegisteredBookmark); +} + +uno::Reference<frame::XModel> SwXBookmark::GetModel() +{ + if (m_pImpl->m_pDoc) + { + SwDocShell const * const pShell( m_pImpl->m_pDoc->GetDocShell() ); + return pShell ? pShell->GetModel() : nullptr; + } + return nullptr; +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXBookmark::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef( + aSwMapProvider.GetPropertySet(PROPERTY_MAP_BOOKMARK) + ->getPropertySetInfo() ); + return xRef; +} + +void SAL_CALL +SwXBookmark::setPropertyValue(const OUString& PropertyName, + const uno::Any& rValue) +{ + SolarMutexGuard g; + + if (PropertyName == UNO_NAME_BOOKMARK_HIDDEN) + { + bool bNewValue = false; + if (!(rValue >>= bNewValue)) + throw lang::IllegalArgumentException("Property BookmarkHidden requires value of type boolean", nullptr, 0); + + IBookmark* pBookmark = dynamic_cast<IBookmark*>(m_pImpl->m_pRegisteredBookmark); + if (pBookmark) + { + pBookmark->Hide(bNewValue); + } + else + { + m_pImpl->m_bHidden = bNewValue; + } + return; + } + else if (PropertyName == UNO_NAME_BOOKMARK_CONDITION) + { + OUString newValue; + if (!(rValue >>= newValue)) + throw lang::IllegalArgumentException("Property BookmarkCondition requires value of type string", nullptr, 0); + + IBookmark* pBookmark = dynamic_cast<IBookmark*>(m_pImpl->m_pRegisteredBookmark); + if (pBookmark) + { + pBookmark->SetHideCondition(newValue); + } + else + { + m_pImpl->m_HideCondition = newValue; + } + return; + } + + // nothing to set here + throw lang::IllegalArgumentException("Property is read-only: " + + PropertyName, getXWeak(), 0 ); +} + +uno::Any SAL_CALL SwXBookmark::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + uno::Any aRet; + if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + if(rPropertyName == UNO_LINK_DISPLAY_NAME) + { + aRet <<= getName(); + } + else if (rPropertyName == UNO_NAME_BOOKMARK_HIDDEN) + { + IBookmark* pBookmark = dynamic_cast<IBookmark*>(m_pImpl->m_pRegisteredBookmark); + if (pBookmark) + { + aRet <<= pBookmark->IsHidden(); + } + else + { + aRet <<= m_pImpl->m_bHidden; + } + } + else if (rPropertyName == UNO_NAME_BOOKMARK_CONDITION) + { + IBookmark* pBookmark = dynamic_cast<IBookmark*>(m_pImpl->m_pRegisteredBookmark); + if (pBookmark) + { + aRet <<= pBookmark->GetHideCondition(); + } + else + { + aRet <<= m_pImpl->m_HideCondition; + } + } + } + return aRet; +} + +void SAL_CALL +SwXBookmark::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXBookmark::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXBookmark::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXBookmark::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXBookmark::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXBookmark::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXBookmark::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXBookmark::removeVetoableChangeListener(): not implemented"); +} + + +void SwXFieldmarkParameters::insertByName(const OUString& aName, const uno::Any& aElement) +{ + SolarMutexGuard aGuard; + IFieldmark::parameter_map_t* pParameters = getCoreParameters(); + if(pParameters->find(aName) != pParameters->end()) + throw container::ElementExistException(); + (*pParameters)[aName] = aElement; +} + +void SwXFieldmarkParameters::removeByName(const OUString& aName) +{ + SolarMutexGuard aGuard; + if(!getCoreParameters()->erase(aName)) + throw container::NoSuchElementException(); +} + +void SwXFieldmarkParameters::replaceByName(const OUString& aName, const uno::Any& aElement) +{ + SolarMutexGuard aGuard; + IFieldmark::parameter_map_t* pParameters = getCoreParameters(); + IFieldmark::parameter_map_t::iterator pEntry = pParameters->find(aName); + if(pEntry == pParameters->end()) + throw container::NoSuchElementException(); + pEntry->second = aElement; +} + +uno::Any SwXFieldmarkParameters::getByName(const OUString& aName) +{ + SolarMutexGuard aGuard; + IFieldmark::parameter_map_t* pParameters = getCoreParameters(); + IFieldmark::parameter_map_t::iterator pEntry = pParameters->find(aName); + if(pEntry == pParameters->end()) + throw container::NoSuchElementException(); + return pEntry->second; +} + +uno::Sequence<OUString> SwXFieldmarkParameters::getElementNames() +{ + SolarMutexGuard aGuard; + IFieldmark::parameter_map_t* pParameters = getCoreParameters(); + return comphelper::mapKeysToSequence(*pParameters); +} + +sal_Bool SwXFieldmarkParameters::hasByName(const OUString& aName) +{ + SolarMutexGuard aGuard; + IFieldmark::parameter_map_t* pParameters = getCoreParameters(); + return (pParameters->find(aName) != pParameters->end()); +} + +uno::Type SwXFieldmarkParameters::getElementType() +{ + return ::cppu::UnoType<void>::get(); +} + +sal_Bool SwXFieldmarkParameters::hasElements() +{ + SolarMutexGuard aGuard; + return !getCoreParameters()->empty(); +} + +void SwXFieldmarkParameters::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFieldmark = nullptr; +} + +IFieldmark::parameter_map_t* SwXFieldmarkParameters::getCoreParameters() +{ + if(!m_pFieldmark) + throw uno::RuntimeException(); + return m_pFieldmark->GetParameters(); +} + +SwXFieldmark::SwXFieldmark(bool const isReplacementObject, SwDoc *const pDoc) + : SwXFieldmark_Base(pDoc) + , m_bReplacementObject(isReplacementObject) +{ +} + +OUString SAL_CALL +SwXFieldmark::getImplementationName() +{ + return "SwXFieldmark"; +} + +uno::Sequence<OUString> SAL_CALL +SwXFieldmark::getSupportedServiceNames() +{ + // is const, no lock needed + if (m_bReplacementObject) + { + return {"com.sun.star.text.TextContent", + "com.sun.star.text.Bookmark", + "com.sun.star.text.FormFieldmark"}; + } + else + { + return {"com.sun.star.text.TextContent", + "com.sun.star.text.Bookmark", + "com.sun.star.text.Fieldmark"}; + } +} + +void SwXFieldmark::attachToRange( const uno::Reference < text::XTextRange >& xTextRange ) +{ + + attachToRangeEx( xTextRange, + (m_bReplacementObject ? IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK : IDocumentMarkAccess::MarkType::TEXT_FIELDMARK), + m_isFieldmarkSeparatorAtStart); +} + +OUString SwXFieldmark::getFieldType() +{ + SolarMutexGuard aGuard; + const IFieldmark *pBkm = dynamic_cast<const IFieldmark*>(GetBookmark()); + if(!pBkm) + throw uno::RuntimeException(); + return pBkm->GetFieldname(); +} + +void SwXFieldmark::setFieldType(const OUString & fieldType) +{ + SolarMutexGuard aGuard; + IFieldmark *pBkm = dynamic_cast<IFieldmark*>(GetBookmark()); + if(!pBkm) + throw uno::RuntimeException(); + + OUString const oldFieldType(getFieldType()); + if (fieldType == oldFieldType) + return; + + // note: this must not change between point-fieldmarks and range-fieldmarks + if(fieldType == ODF_FORMDROPDOWN || fieldType == ODF_FORMCHECKBOX || fieldType == ODF_FORMDATE) + { + ::sw::mark::IFieldmark* pNewFieldmark = GetIDocumentMarkAccess()->changeFormFieldmarkType(pBkm, fieldType); + if (pNewFieldmark) + { + registerInMark(*this, pNewFieldmark); + return; + } + } + + if ((!m_bReplacementObject && (fieldType == ODF_UNHANDLED + || fieldType == ODF_FORMDATE + || fieldType == ODF_FORMTEXT)) + || (m_bReplacementObject && (fieldType == ODF_FORMCHECKBOX + || fieldType == ODF_FORMDROPDOWN))) + { + pBkm->SetFieldname(fieldType); + return; + } + + throw uno::RuntimeException("changing to that type isn't implemented"); +} + +uno::Reference<container::XNameContainer> SwXFieldmark::getParameters() +{ + SolarMutexGuard aGuard; + IFieldmark *pBkm = dynamic_cast<IFieldmark*>(GetBookmark()); + if(!pBkm) + throw uno::RuntimeException(); + return uno::Reference<container::XNameContainer>(new SwXFieldmarkParameters(pBkm)); +} + +rtl::Reference<SwXBookmark> +SwXFieldmark::CreateXFieldmark(SwDoc & rDoc, ::sw::mark::IMark *const pMark, + bool const isReplacementObject) +{ + // #i105557#: do not iterate over the registered clients: race condition + ::sw::mark::MarkBase *const pMarkBase( + dynamic_cast< ::sw::mark::MarkBase * >(pMark)); + assert(!pMark || pMarkBase); + rtl::Reference<SwXBookmark> xMark; + if (pMarkBase) + { + xMark = pMarkBase->GetXBookmark(); + } + if (!xMark.is()) + { + // FIXME: These belong in XTextFieldsSupplier + rtl::Reference<SwXFieldmark> pXBkmk; + if (dynamic_cast< ::sw::mark::TextFieldmark* >(pMark)) + pXBkmk = new SwXFieldmark(false, &rDoc); + else if (dynamic_cast< ::sw::mark::CheckboxFieldmark* >(pMark)) + pXBkmk = new SwXFieldmark(true, &rDoc); + else if (dynamic_cast< ::sw::mark::DropDownFieldmark* >(pMark)) + pXBkmk = new SwXFieldmark(true, &rDoc); + else if (dynamic_cast< ::sw::mark::DateFieldmark* >(pMark)) + pXBkmk = new SwXFieldmark(false, &rDoc); + else + pXBkmk = new SwXFieldmark(isReplacementObject, &rDoc); + + xMark = pXBkmk.get(); + pXBkmk->registerInMark(*pXBkmk, pMarkBase); + } + return xMark; +} + +::sw::mark::ICheckboxFieldmark* +SwXFieldmark::getCheckboxFieldmark() +{ + ::sw::mark::ICheckboxFieldmark* pCheckboxFm = nullptr; + if ( getFieldType() == ODF_FORMCHECKBOX ) + { + pCheckboxFm = dynamic_cast< ::sw::mark::ICheckboxFieldmark* >( GetBookmark()); + assert( GetBookmark() == nullptr || pCheckboxFm != nullptr ); + // unclear to me whether GetBookmark() can be null here + } + return pCheckboxFm; + +} + +// support 'hidden' "Checked" property ( note: this property is just for convenience to support +// docx import filter thus not published via PropertySet info ) + +void SAL_CALL +SwXFieldmark::setPropertyValue(const OUString& PropertyName, + const uno::Any& rValue) +{ + SolarMutexGuard g; + if ( PropertyName == "Checked" ) + { + ::sw::mark::ICheckboxFieldmark* pCheckboxFm = getCheckboxFieldmark(); + bool bChecked( false ); + if ( !(pCheckboxFm && ( rValue >>= bChecked )) ) + throw uno::RuntimeException(); + + pCheckboxFm->SetChecked( bChecked ); + } + else if (PropertyName == "PrivateSeparatorAtStart") + { + bool isFieldmarkSeparatorAtStart{}; + if (rValue >>= isFieldmarkSeparatorAtStart) + { + m_isFieldmarkSeparatorAtStart = isFieldmarkSeparatorAtStart; + } + } + // this doesn't support any SwXBookmark property +} + +// support 'hidden' "Checked" property ( note: this property is just for convenience to support +// docx import filter thus not published via PropertySet info ) + +uno::Any SAL_CALL SwXFieldmark::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + if ( rPropertyName == "Checked" ) + { + ::sw::mark::ICheckboxFieldmark* pCheckboxFm = getCheckboxFieldmark(); + if ( !pCheckboxFm ) + throw uno::RuntimeException(); + + return uno::Any( pCheckboxFm->IsChecked() ); + } + return uno::Any(); // this doesn't support any SwXBookmark property +} + +uno::Reference<beans::XPropertySetInfo> SAL_CALL +SwXFieldmark::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference<beans::XPropertySetInfo> const xRef( + aSwMapProvider.GetPropertySet(PROPERTY_MAP_FIELDMARK) + ->getPropertySetInfo() ); + return xRef; +} + +// XComponent +void SAL_CALL SwXFieldmark::dispose() +{ + return SwXBookmark::dispose(); +} +void SAL_CALL SwXFieldmark::addEventListener( + uno::Reference<lang::XEventListener> const& xListener) +{ + return SwXBookmark::addEventListener(xListener); +} +void SAL_CALL SwXFieldmark::removeEventListener( + uno::Reference<lang::XEventListener> const& xListener) +{ + return SwXBookmark::removeEventListener(xListener); +} + +// XTextContent +void SAL_CALL SwXFieldmark::attach( + uno::Reference<text::XTextRange> const& xTextRange) +{ + return SwXBookmark::attach(xTextRange); +} + +uno::Reference<text::XTextRange> SAL_CALL SwXFieldmark::getAnchor() +{ + return SwXBookmark::getAnchor(); +} + +rtl::Reference<SwXTextRange> +SwXFieldmark::GetCommand(IFieldmark const& rMark) +{ + SwPosition const sepPos(sw::mark::FindFieldSep(rMark)); + SwPosition start(rMark.GetMarkStart()); + start.AdjustContent(1); + return SwXTextRange::CreateXTextRange(*GetDoc(), start, &sepPos); +} + +rtl::Reference<SwXTextRange> +SwXFieldmark::GetResult(IFieldmark const& rMark) +{ + SwPosition sepPos(sw::mark::FindFieldSep(rMark)); + sepPos.AdjustContent(1); + SwPosition const& rEnd(rMark.GetMarkEnd()); + return SwXTextRange::CreateXTextRange(*GetDoc(), sepPos, &rEnd); +} + +// XTextField +OUString SAL_CALL +SwXFieldmark::getPresentation(sal_Bool const bShowCommand) +{ + SolarMutexGuard g; + + IFieldmark const*const pMark(dynamic_cast<IFieldmark*>(GetBookmark())); + if (!pMark) + { + throw lang::DisposedException(); + } + + if (bShowCommand) + { + if (m_bReplacementObject) + { + return OUString(); + } + else + { // also for ODF_FORMDATE, which shouldn't be a fieldmark... + uno::Reference<text::XTextRange> const xCommand(GetCommand(*pMark)); + return xCommand->getString(); + } + } + else + { + OUString const type(getFieldType()); + if (type == ODF_FORMCHECKBOX || type == ODF_FORMDROPDOWN) + { + return sw::mark::ExpandFieldmark(const_cast<IFieldmark *>(pMark)); + } + else + { + assert(!m_bReplacementObject); + uno::Reference<text::XTextRange> const xResult(GetResult(*pMark)); + return xResult->getString(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unochart.cxx b/sw/source/core/unocore/unochart.cxx new file mode 100644 index 0000000000..db97093a31 --- /dev/null +++ b/sw/source/core/unocore/unochart.cxx @@ -0,0 +1,2695 @@ +/* -*- 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 <algorithm> +#include <string_view> + +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/chart2/data/LabelOrigin.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <comphelper/diagnose_ex.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/deleter.hxx> +#include <o3tl/string_view.hxx> +#include <mutex> +#include <vcl/svapp.hxx> + +#include "XMLRangeHelper.hxx" +#include <unochart.hxx> +#include <swtable.hxx> +#include <unoprnms.hxx> +#include <unomap.hxx> +#include <unocrsr.hxx> +#include <unotbl.hxx> +#include <doc.hxx> +#include <IDocumentChartDataProviderAccess.hxx> +#include <frmfmt.hxx> +#include <ndole.hxx> +#include <swtypes.hxx> +#include <strings.hrc> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <svl/itemprop.hxx> + +using namespace ::com::sun::star; + +void SwChartHelper::DoUpdateAllCharts( SwDoc* pDoc ) +{ + if (!pDoc) + return; + + SwOLENode *pONd; + SwStartNode *pStNd; + SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) ) + { + ++aIdx; + if (nullptr != ( pONd = aIdx.GetNode().GetOLENode() ) && + pONd->GetOLEObj().GetObject().IsChart() ) + { + // Load the object and set modified + + uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); + if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) + { + try + { + uno::Reference< util::XModifiable > xModif( xIP->getComponent(), uno::UNO_QUERY_THROW ); + xModif->setModified( true ); + } + catch ( uno::Exception& ) + { + } + + } + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } +} + +SwChartLockController_Helper::SwChartLockController_Helper( SwDoc *pDocument ) : + m_pDoc( pDocument ) + , m_aUnlockTimer( "sw::SwChartLockController_Helper aUnlockTimer" ) + , m_bIsLocked( false ) +{ + m_aUnlockTimer.SetTimeout( 1500 ); + m_aUnlockTimer.SetInvokeHandler( LINK( this, SwChartLockController_Helper, DoUnlockAllCharts )); +} + +SwChartLockController_Helper::~SwChartLockController_Helper() +{ + if (m_pDoc) // still connected? + suppress_fun_call_w_exception(Disconnect()); +} + +void SwChartLockController_Helper::StartOrContinueLocking() +{ + if (!m_bIsLocked) + LockAllCharts(); + m_aUnlockTimer.Start(); // start or continue time of locking +} + +void SwChartLockController_Helper::Disconnect() +{ + m_aUnlockTimer.Stop(); + UnlockAllCharts(); + m_pDoc = nullptr; +} + +void SwChartLockController_Helper::LockUnlockAllCharts( bool bLock ) +{ + if (!m_pDoc) + return; + + uno::Reference< frame::XModel > xRes; + SwOLENode *pONd; + SwStartNode *pStNd; + SwNodeIndex aIdx( *m_pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) ) + { + ++aIdx; + if (nullptr != ( pONd = aIdx.GetNode().GetOLENode() ) && + !pONd->GetChartTableName().isEmpty() /* is chart object? */) + { + uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); + if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) + { + xRes.set( xIP->getComponent(), uno::UNO_QUERY ); + if (xRes.is()) + { + if (bLock) + xRes->lockControllers(); + else + xRes->unlockControllers(); + } + } + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } + + m_bIsLocked = bLock; +} + +IMPL_LINK_NOARG( SwChartLockController_Helper, DoUnlockAllCharts, Timer *, void ) +{ + UnlockAllCharts(); +} + +static std::mutex & GetChartMutex() +{ + static std::mutex aMutex; + return aMutex; +} + +static void LaunchModifiedEvent( + ::comphelper::OInterfaceContainerHelper4<util::XModifyListener> &rICH, + const uno::Reference< uno::XInterface > &rxI ) +{ + lang::EventObject aEvtObj( rxI ); + std::unique_lock aGuard(GetChartMutex()); + rICH.notifyEach( aGuard, &util::XModifyListener::modified, aEvtObj ); +} + +/** + * rCellRangeName needs to be of one of the following formats: + * - e.g. "A2:E5" or + * - e.g. "Table1.A2:E5" + */ +bool FillRangeDescriptor( + SwRangeDescriptor &rDesc, + std::u16string_view rCellRangeName ) +{ + sal_Int32 nToken = std::u16string_view::npos == rCellRangeName.find('.') ? 0 : 1; + std::u16string_view aCellRangeNoTableName( o3tl::getToken(rCellRangeName, nToken, '.' ) ); + OUString aTLName( o3tl::getToken(aCellRangeNoTableName, 0, ':') ); // name of top left cell + OUString aBRName( o3tl::getToken(aCellRangeNoTableName, 1, ':') ); // name of bottom right cell + if(aTLName.isEmpty() || aBRName.isEmpty()) + return false; + + rDesc.nTop = rDesc.nLeft = rDesc.nBottom = rDesc.nRight = -1; + SwXTextTable::GetCellPosition( aTLName, rDesc.nLeft, rDesc.nTop ); + SwXTextTable::GetCellPosition( aBRName, rDesc.nRight, rDesc.nBottom ); + rDesc.Normalize(); + OSL_ENSURE( rDesc.nTop != -1 && + rDesc.nLeft != -1 && + rDesc.nBottom != -1 && + rDesc.nRight != -1, + "failed to get range descriptor" ); + OSL_ENSURE( rDesc.nTop <= rDesc.nBottom && rDesc.nLeft <= rDesc.nRight, + "invalid range descriptor"); + return true; +} + +static OUString GetCellRangeName( const SwFrameFormat &rTableFormat, SwUnoCursor &rTableCursor ) +{ + OUString aRes; + + //!! see also SwXTextTableCursor::getRangeName + + SwUnoTableCursor* pUnoTableCursor = dynamic_cast<SwUnoTableCursor*>(&rTableCursor); + if (!pUnoTableCursor) + return OUString(); + + // tdf#132714 empty outdated selection cache to avoid crashing in ActualizeSelection() + size_t nCount = pUnoTableCursor->GetSelectedBoxesCount(); + while (nCount--) + pUnoTableCursor->DeleteBox(nCount); + + pUnoTableCursor->MakeBoxSels(); + + const SwStartNode* pStart; + const SwTableBox* pStartBox = nullptr; + const SwTableBox* pEndBox = nullptr; + + pStart = pUnoTableCursor->GetPoint()->GetNode().FindTableBoxStartNode(); + if (pStart) + { + const SwTable* pTable = SwTable::FindTable( &rTableFormat ); + pEndBox = pTable->GetTableBox( pStart->GetIndex()); + aRes = pEndBox->GetName(); + + if(pUnoTableCursor->HasMark()) + { + pStart = pUnoTableCursor->GetMark()->GetNode().FindTableBoxStartNode(); + pStartBox = pTable->GetTableBox( pStart->GetIndex()); + } + OSL_ENSURE( pStartBox, "start box not found" ); + OSL_ENSURE( pEndBox, "end box not found" ); + + // need to switch start and end? + if (*pUnoTableCursor->GetPoint() < *pUnoTableCursor->GetMark()) + { + const SwTableBox* pTmpBox = pStartBox; + pStartBox = pEndBox; + pEndBox = pTmpBox; + } + + if (!pStartBox) + return aRes; + + aRes = pStartBox->GetName() + ":"; + if (pEndBox) + aRes += pEndBox->GetName(); + else + aRes += pStartBox->GetName(); + } + + return aRes; +} + +static OUString GetRangeRepFromTableAndCells( std::u16string_view rTableName, + std::u16string_view rStartCell, std::u16string_view rEndCell, + bool bForceEndCellName ) +{ + OSL_ENSURE( !rTableName.empty(), "table name missing" ); + OSL_ENSURE( !rStartCell.empty(), "cell name missing" ); + OUString aRes = OUString::Concat(rTableName) + "." + rStartCell; + + if (!rEndCell.empty()) + { + aRes += OUString::Concat(":") + rEndCell; + } + else if (bForceEndCellName) + { + aRes += OUString::Concat(":") + rStartCell; + } + + return aRes; +} + +static bool GetTableAndCellsFromRangeRep( + std::u16string_view rRangeRepresentation, + OUString &rTableName, + OUString &rStartCell, + OUString &rEndCell, + bool bSortStartEndCells = true ) +{ + // parse range representation for table name and cell/range names + // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2" + OUString aTableName; // table name + OUString aStartCell; // name of top left cell + OUString aEndCell; // name of bottom right cell + size_t nIdx = rRangeRepresentation.find( '.' ); + if (nIdx != std::u16string_view::npos) + { + aTableName = rRangeRepresentation.substr( 0, nIdx ); + std::u16string_view aRange = rRangeRepresentation.substr( nIdx + 1 ); // cell range + size_t nPos = aRange.find( ':' ); + if (nPos != std::u16string_view::npos) // a cell-range like "Table1.A2:D4" + { + aStartCell = aRange.substr( 0, nPos ); + aEndCell = aRange.substr( nPos + 1 ); + + // need to switch start and end cell ? + // (does not check for normalization here) + if (bSortStartEndCells && 1 == sw_CompareCellsByColFirst( aStartCell, aEndCell )) + { + OUString aTmp( aStartCell ); + aStartCell = aEndCell; + aEndCell = aTmp; + } + } + else // a single cell like in "Table1.B3" + { + aStartCell = aEndCell = aRange; + } + } + + bool bSuccess = !aTableName.isEmpty() && + !aStartCell.isEmpty() && !aEndCell.isEmpty(); + if (bSuccess) + { + rTableName = aTableName; + rStartCell = aStartCell; + rEndCell = aEndCell; + } + return bSuccess; +} + +static void GetTableByName( const SwDoc &rDoc, std::u16string_view rTableName, + SwFrameFormat **ppTableFormat, SwTable **ppTable) +{ + SwFrameFormat *pTableFormat = nullptr; + + // find frame format of table + //! see SwXTextTables::getByName + const size_t nCount = rDoc.GetTableFrameFormatCount(true); + for (size_t i = 0; i < nCount && !pTableFormat; ++i) + { + SwFrameFormat& rTableFormat = rDoc.GetTableFrameFormat(i, true); + if(rTableName == rTableFormat.GetName()) + pTableFormat = &rTableFormat; + } + + if (ppTableFormat) + *ppTableFormat = pTableFormat; + + if (ppTable) + *ppTable = pTableFormat ? SwTable::FindTable( pTableFormat ) : nullptr; +} + +static void GetFormatAndCreateCursorFromRangeRep( + const SwDoc *pDoc, + std::u16string_view rRangeRepresentation, // must be a single range (i.e. so called sub-range) + SwFrameFormat **ppTableFormat, // will be set to the table format of the table used in the range representation + std::shared_ptr<SwUnoCursor>& rpUnoCursor ) // will be set to cursor spanning the cell range (cursor will be created!) +{ + OUString aTableName; // table name + OUString aStartCell; // name of top left cell + OUString aEndCell; // name of bottom right cell + bool bNamesFound = GetTableAndCellsFromRangeRep( rRangeRepresentation, + aTableName, aStartCell, aEndCell ); + + if (!bNamesFound) + { + if (ppTableFormat) + *ppTableFormat = nullptr; + rpUnoCursor.reset(); + } + else + { + SwFrameFormat *pTableFormat = nullptr; + + // is the correct table format already provided? + if (*ppTableFormat != nullptr && (*ppTableFormat)->GetName() == aTableName) + pTableFormat = *ppTableFormat; + else + GetTableByName( *pDoc, aTableName, &pTableFormat, nullptr ); + + *ppTableFormat = pTableFormat; + + rpUnoCursor.reset(); // default result in case of failure + + SwTable *pTable = pTableFormat ? SwTable::FindTable( pTableFormat ) : nullptr; + // create new SwUnoCursor spanning the specified range + //! see also SwXTextTable::GetRangeByName + // #i80314# + // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTableBox(..)> + const SwTableBox* pTLBox = + pTable ? pTable->GetTableBox( aStartCell, true ) : nullptr; + if(pTLBox) + { + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + + // set cursor to top left box of range + auto pUnoCursor = pTableFormat->GetDoc()->CreateUnoCursor(aPos, true); + pUnoCursor->Move( fnMoveForward, GoInNode ); + pUnoCursor->SetRemainInSection( false ); + + // #i80314# + // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTableBox(..)> + const SwTableBox* pBRBox = pTable->GetTableBox( aEndCell, true ); + if(pBRBox) + { + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() ); + pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rCursor = + dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + // HACK: remove pending actions for old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + rCursor.MakeBoxSels(); + rpUnoCursor = pUnoCursor; + } + } + } +} + +static bool GetSubranges( std::u16string_view rRangeRepresentation, + uno::Sequence< OUString > &rSubRanges, bool bNormalize ) +{ + bool bRes = true; + const sal_Int32 nLen = comphelper::string::getTokenCount(rRangeRepresentation, ';'); + uno::Sequence< OUString > aRanges( nLen ); + + sal_Int32 nCnt = 0; + if (nLen != 0) + { + OUString *pRanges = aRanges.getArray(); + OUString aFirstTable; + sal_Int32 nPos = 0; + for( sal_Int32 i = 0; i < nLen && bRes; ++i ) + { + const OUString aRange( o3tl::getToken(rRangeRepresentation, 0, ';', nPos ) ); + if (!aRange.isEmpty()) + { + pRanges[nCnt] = aRange; + + OUString aTableName, aStartCell, aEndCell; + if (!GetTableAndCellsFromRangeRep( aRange, + aTableName, aStartCell, aEndCell )) + bRes = false; + + if (bNormalize) + { + sw_NormalizeRange( aStartCell, aEndCell ); + pRanges[nCnt] = GetRangeRepFromTableAndCells( aTableName, + aStartCell, aEndCell, true ); + } + + // make sure to use only a single table + if (nCnt == 0) + aFirstTable = aTableName; + else + if (aFirstTable != aTableName) bRes = false; + + ++nCnt; + } + } + } + aRanges.realloc( nCnt ); + + rSubRanges = aRanges; + return bRes; +} + +static void SortSubranges( uno::Sequence< OUString > &rSubRanges, bool bCmpByColumn ) +{ + sal_Int32 nLen = rSubRanges.getLength(); + OUString *pSubRanges = rSubRanges.getArray(); + + OUString aSmallestTableName; + OUString aSmallestStartCell; + OUString aSmallestEndCell; + + for (sal_Int32 i = 0; i < nLen; ++i) + { + sal_Int32 nIdxOfSmallest = i; + GetTableAndCellsFromRangeRep( pSubRanges[nIdxOfSmallest], + aSmallestTableName, aSmallestStartCell, aSmallestEndCell ); + if (aSmallestEndCell.isEmpty()) + aSmallestEndCell = aSmallestStartCell; + + for (sal_Int32 k = i+1; k < nLen; ++k) + { + // get cell names for sub range + OUString aTableName; + OUString aStartCell; + OUString aEndCell; + GetTableAndCellsFromRangeRep( pSubRanges[k], + aTableName, aStartCell, aEndCell ); + if (aEndCell.isEmpty()) + aEndCell = aStartCell; + + // compare cell ranges ( is the new one smaller? ) + if (-1 == sw_CompareCellRanges( aStartCell, aEndCell, + aSmallestStartCell, aSmallestEndCell, bCmpByColumn )) + { + nIdxOfSmallest = k; + aSmallestTableName = aTableName; + aSmallestStartCell = aStartCell; + aSmallestEndCell = aEndCell; + } + } + + // move smallest element to the start of the not sorted area + const OUString aTmp( pSubRanges[ nIdxOfSmallest ] ); + pSubRanges[ nIdxOfSmallest ] = pSubRanges[ i ]; + pSubRanges[ i ] = aTmp; + } +} + +SwChartDataProvider::SwChartDataProvider( const SwDoc& rSwDoc ) : + m_pDoc( &rSwDoc ) +{ + m_bDisposed = false; +} + +SwChartDataProvider::~SwChartDataProvider() +{ +} + +uno::Reference< chart2::data::XDataSource > SwChartDataProvider::Impl_createDataSource( + const uno::Sequence< beans::PropertyValue >& rArguments, bool bTestOnly ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + uno::Reference< chart2::data::XDataSource > xRes; + + if (!m_pDoc) + throw uno::RuntimeException("Not connected to a document."); + + // get arguments + OUString aRangeRepresentation; + uno::Sequence< sal_Int32 > aSequenceMapping; + bool bFirstIsLabel = false; + bool bDtaSrcIsColumns = true; // true : DataSource will be sequence of columns + // false: DataSource will be sequence of rows + + OUString aChartOleObjectName; //work around wrong writer ranges ( see Issue 58464 ) + sal_Int32 nArgs = rArguments.getLength(); + OSL_ENSURE( nArgs != 0, "no properties provided" ); + if (nArgs == 0) + return xRes; + for (const beans::PropertyValue& rArg : rArguments) + { + if ( rArg.Name == "DataRowSource" ) + { + chart::ChartDataRowSource eSource; + if (!(rArg.Value >>= eSource)) + { + sal_Int32 nTmp = 0; + if (!(rArg.Value >>= nTmp)) + throw lang::IllegalArgumentException(); + eSource = static_cast< chart::ChartDataRowSource >( nTmp ); + } + bDtaSrcIsColumns = eSource == chart::ChartDataRowSource_COLUMNS; + } + else if ( rArg.Name == "FirstCellAsLabel" ) + { + if (!(rArg.Value >>= bFirstIsLabel)) + throw lang::IllegalArgumentException(); + } + else if ( rArg.Name == "CellRangeRepresentation" ) + { + if (!(rArg.Value >>= aRangeRepresentation)) + throw lang::IllegalArgumentException(); + } + else if ( rArg.Name == "SequenceMapping" ) + { + if (!(rArg.Value >>= aSequenceMapping)) + throw lang::IllegalArgumentException(); + } + else if ( rArg.Name == "ChartOleObjectName" ) + { + if (!(rArg.Value >>= aChartOleObjectName)) + throw lang::IllegalArgumentException(); + } + } + + uno::Sequence< OUString > aSubRanges; + // get sub-ranges and check that they all are from the very same table + bool bOk = GetSubranges( aRangeRepresentation, aSubRanges, true ); + + if (!bOk && m_pDoc && !aChartOleObjectName.isEmpty() ) + { + //try to correct the range here + //work around wrong writer ranges ( see Issue 58464 ) + OUString aChartTableName; + + const SwNodes& rNodes = m_pDoc->GetNodes(); + for( SwNodeOffset nN = rNodes.Count(); nN--; ) + { + SwNode* pNode = rNodes[nN]; + if( !pNode ) + continue; + const SwOLENode* pOleNode = pNode->GetOLENode(); + if( !pOleNode ) + continue; + const SwOLEObj& rOObj = pOleNode->GetOLEObj(); + if( aChartOleObjectName == rOObj.GetCurrentPersistName() ) + { + aChartTableName = pOleNode->GetChartTableName(); + break; + } + } + + if( !aChartTableName.isEmpty() ) + { + //the wrong range is still shifted one row down + //thus the first row is missing and an invalid row at the end is added. + //Therefore we need to shift the range one row up + SwRangeDescriptor aDesc; + if (aRangeRepresentation.isEmpty()) + return xRes; // we can't handle this thus returning an empty references + + aRangeRepresentation = aRangeRepresentation.copy( 1 ); // get rid of '.' to have only the cell range left + FillRangeDescriptor( aDesc, aRangeRepresentation ); + aDesc.Normalize(); + + if (aDesc.nTop <= 0) // no chance to shift the range one row up? + return xRes; // we can't handle this thus returning an empty references + + aDesc.nTop -= 1; + aDesc.nBottom -= 1; + + OUString aNewStartCell( sw_GetCellName( aDesc.nLeft, aDesc.nTop ) ); + OUString aNewEndCell( sw_GetCellName( aDesc.nRight, aDesc.nBottom ) ); + aRangeRepresentation = GetRangeRepFromTableAndCells( + aChartTableName, aNewStartCell, aNewEndCell, true ); + bOk = GetSubranges( aRangeRepresentation, aSubRanges, true ); + } + } + if (!bOk) // different tables used, or incorrect range specifiers + throw lang::IllegalArgumentException(); + + SortSubranges( aSubRanges, bDtaSrcIsColumns ); + + // get table format for that single table from above + SwFrameFormat *pTableFormat = nullptr; // pointer to table format + std::shared_ptr<SwUnoCursor> pUnoCursor; // here required to check if the cells in the range do actually exist + if (aSubRanges.hasElements()) + GetFormatAndCreateCursorFromRangeRep( m_pDoc, aSubRanges[0], &pTableFormat, pUnoCursor ); + + if (!pTableFormat || !pUnoCursor) + throw lang::IllegalArgumentException(); + + SwTable* pTable = SwTable::FindTable(pTableFormat); + if (pTable->IsTableComplex()) + return xRes; // we can't handle this thus returning an empty references + + // get a character map in the size of the table to mark + // all the ranges to use in + sal_Int32 nRows = pTable->GetTabLines().size(); + sal_Int32 nCols = 0; + // As per tdf#149718 one should know that some cells can be merged together. + // Therefore, the number of columns (boxes in each row) are not necessarily + // equal. Here, we calculate the maximum number of columns in all rows. + for (sal_Int32 i = 0; i < nRows; ++i) + nCols = std::max(nCols, static_cast<sal_Int32>(pTable->GetTabLines()[i]->GetTabBoxes().size())); + + std::vector<std::vector<char>> aMap(nRows); + for (sal_Int32 i = 0; i < nRows; ++i) + aMap[i].resize(nCols); + + // iterate over subranges and mark used cells in above map + //!! by proceeding this way we automatically get rid of + //!! multiple listed or overlapping cell ranges which should + //!! just be ignored silently + for (const OUString& rSubRange : std::as_const(aSubRanges)) + { + OUString aTableName, aStartCell, aEndCell; + bool bOk2 = GetTableAndCellsFromRangeRep( + rSubRange, aTableName, aStartCell, aEndCell ); + OSL_ENSURE(bOk2, "failed to get table and start/end cells"); + + sal_Int32 nStartRow, nStartCol, nEndRow, nEndCol; + SwXTextTable::GetCellPosition(aStartCell, nStartCol, nStartRow); + SwXTextTable::GetCellPosition(aEndCell, nEndCol, nEndRow); + OSL_ENSURE( nStartRow <= nEndRow && nStartCol <= nEndCol, + "cell range not normalized"); + + // test if the ranges span more than the available cells + if( nStartRow < 0 || nEndRow >= nRows || + nStartCol < 0 || nEndCol >= nCols ) + { + throw lang::IllegalArgumentException(); + } + for (sal_Int32 k1 = nStartRow; k1 <= nEndRow; ++k1) + { + for (sal_Int32 k2 = nStartCol; k2 <= nEndCol; ++k2) + aMap[k1][k2] = 'x'; + } + } + + // find label and data sequences to use + + sal_Int32 oi; // outer index (slower changing index) + sal_Int32 ii; // inner index (faster changing index) + sal_Int32 oiEnd = bDtaSrcIsColumns ? nCols : nRows; + sal_Int32 iiEnd = bDtaSrcIsColumns ? nRows : nCols; + std::vector<sal_Int32> aLabelIdx(oiEnd); + std::vector<sal_Int32> aDataStartIdx(oiEnd); + std::vector<sal_Int32> aDataLen(oiEnd); + for (oi = 0; oi < oiEnd; ++oi) + { + aLabelIdx[oi] = -1; + aDataStartIdx[oi] = -1; + aDataLen[oi] = 0; + } + + for (oi = 0; oi < oiEnd; ++oi) + { + ii = 0; + while (ii < iiEnd) + { + char &rChar = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii]; + + // label should be used but is not yet found? + if (rChar == 'x' && bFirstIsLabel && aLabelIdx[oi] == -1) + { + aLabelIdx[oi] = ii; + rChar = 'L'; // setting a different char for labels here + // makes the test for the data sequence below + // easier + } + + // find data sequence + if (rChar == 'x' && aDataStartIdx[oi] == -1) + { + aDataStartIdx[oi] = ii; + + // get length of data sequence + sal_Int32 nL = 0; + while (ii< iiEnd && 'x' == (bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) + { + ++nL; ++ii; + } + aDataLen[oi] = nL; + + // check that there is no other separate sequence of data + // to be found because that is not supported + while (ii < iiEnd) + { + if ('x' == (bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) + throw lang::IllegalArgumentException(); + ++ii; + } + } + else + ++ii; + } + } + + // make some other consistency checks while calculating + // the number of XLabeledDataSequence to build: + // - labels should always be used or not at all + // - the data sequences should have equal non-zero length + sal_Int32 nNumLDS = 0; + if (oiEnd > 0) + { + for (oi = 0; oi < oiEnd; ++oi) + { + // row/col used at all? + if (aDataStartIdx[oi] != -1 && + (!bFirstIsLabel || aLabelIdx[oi] != -1)) + { + ++nNumLDS; + } + } + } + if (nNumLDS == 0) + throw lang::IllegalArgumentException(); + + // now we should have all necessary data to build a proper DataSource + // thus if we came this far there should be no further problem + if (bTestOnly) + return xRes; // have createDataSourcePossible return true + + // create data source from found label and data sequences + uno::Sequence<uno::Reference<chart2::data::XDataSequence>> aLabelSeqs(nNumLDS); + uno::Reference<chart2::data::XDataSequence>* pLabelSeqs = aLabelSeqs.getArray(); + uno::Sequence<uno::Reference<chart2::data::XDataSequence>> aDataSeqs(nNumLDS); + uno::Reference<chart2::data::XDataSequence>* pDataSeqs = aDataSeqs.getArray(); + sal_Int32 nSeqsIdx = 0; + for (oi = 0; oi < oiEnd; ++oi) + { + // row/col not used? (see if-statement above where nNumLDS was counted) + if (!(aDataStartIdx[oi] != -1 && + (!bFirstIsLabel || aLabelIdx[oi] != -1))) + continue; + + // get cell ranges for label and data + + SwRangeDescriptor aLabelDesc; + SwRangeDescriptor aDataDesc; + if (bDtaSrcIsColumns) // use columns + { + aLabelDesc.nTop = aLabelIdx[oi]; + aLabelDesc.nLeft = oi; + aLabelDesc.nBottom = aLabelDesc.nTop; + aLabelDesc.nRight = oi; + + aDataDesc.nTop = aDataStartIdx[oi]; + aDataDesc.nLeft = oi; + aDataDesc.nBottom = aDataDesc.nTop + aDataLen[oi] - 1; + aDataDesc.nRight = oi; + } + else // use rows + { + aLabelDesc.nTop = oi; + aLabelDesc.nLeft = aLabelIdx[oi]; + aLabelDesc.nBottom = oi; + aLabelDesc.nRight = aLabelDesc.nLeft; + + aDataDesc.nTop = oi; + aDataDesc.nLeft = aDataStartIdx[oi]; + aDataDesc.nBottom = oi; + aDataDesc.nRight = aDataDesc.nLeft + aDataLen[oi] - 1; + } + const OUString aBaseName = pTableFormat->GetName() + "."; + + OUString aLabelRange; + if (aLabelIdx[oi] != -1) + { + aLabelRange = aBaseName + + sw_GetCellName( aLabelDesc.nLeft, aLabelDesc.nTop ) + + ":" + sw_GetCellName( aLabelDesc.nRight, aLabelDesc.nBottom ); + } + + OUString aDataRange = aBaseName + + sw_GetCellName( aDataDesc.nLeft, aDataDesc.nTop ) + + ":" + sw_GetCellName( aDataDesc.nRight, aDataDesc.nBottom ); + + // get cursors spanning the cell ranges for label and data + std::shared_ptr<SwUnoCursor> pLabelUnoCursor; + std::shared_ptr<SwUnoCursor> pDataUnoCursor; + GetFormatAndCreateCursorFromRangeRep(m_pDoc, aLabelRange, &pTableFormat, pLabelUnoCursor); + GetFormatAndCreateCursorFromRangeRep(m_pDoc, aDataRange, &pTableFormat, pDataUnoCursor); + + // create XDataSequence's from cursors + if (pLabelUnoCursor) + pLabelSeqs[nSeqsIdx] = new SwChartDataSequence(*this, *pTableFormat, pLabelUnoCursor); + OSL_ENSURE(pDataUnoCursor, "pointer to data sequence missing"); + if (pDataUnoCursor) + pDataSeqs[nSeqsIdx] = new SwChartDataSequence(*this, *pTableFormat, pDataUnoCursor); + if (pLabelUnoCursor || pDataUnoCursor) + ++nSeqsIdx; + } + OSL_ENSURE(nSeqsIdx == nNumLDS, "mismatch between sequence size and num,ber of entries"); + + // build data source from data and label sequences + uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence>> aLDS(nNumLDS); + uno::Reference<chart2::data::XLabeledDataSequence>* pLDS = aLDS.getArray(); + for (sal_Int32 i = 0; i < nNumLDS; ++i) + { + rtl::Reference<SwChartLabeledDataSequence> pLabeledDtaSeq = new SwChartLabeledDataSequence; + pLabeledDtaSeq->setLabel(pLabelSeqs[i]); + pLabeledDtaSeq->setValues(pDataSeqs[i]); + pLDS[i] = pLabeledDtaSeq; + } + + // apply 'SequenceMapping' if it was provided + if (aSequenceMapping.hasElements()) + { + uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence>> aOld_LDS(aLDS); + uno::Reference<chart2::data::XLabeledDataSequence>* pOld_LDS = aOld_LDS.getArray(); + + sal_Int32 nNewCnt = 0; + for (sal_Int32 nIdx : std::as_const(aSequenceMapping)) + { + // check that index to be used is valid + // and has not yet been used + if (0 <= nIdx && nIdx < nNumLDS && pOld_LDS[nIdx].is()) + { + pLDS[nNewCnt++] = pOld_LDS[nIdx]; + + // mark index as being used already (avoids duplicate entries) + pOld_LDS[nIdx].clear(); + } + } + // add not yet used 'old' sequences to new one + for (sal_Int32 i = 0; i < nNumLDS; ++i) + { + if (pOld_LDS[i].is()) + pLDS[nNewCnt++] = pOld_LDS[i]; + } + OSL_ENSURE(nNewCnt == nNumLDS, "unexpected size of resulting sequence"); + } + + xRes = new SwChartDataSource(aLDS); + return xRes; +} + +sal_Bool SAL_CALL SwChartDataProvider::createDataSourcePossible( + const uno::Sequence< beans::PropertyValue >& rArguments ) +{ + SolarMutexGuard aGuard; + + bool bPossible = true; + try + { + Impl_createDataSource( rArguments, true ); + } + catch (lang::IllegalArgumentException &) + { + bPossible = false; + } + + return bPossible; +} + +uno::Reference< chart2::data::XDataSource > SAL_CALL SwChartDataProvider::createDataSource( + const uno::Sequence< beans::PropertyValue >& rArguments ) +{ + SolarMutexGuard aGuard; + return Impl_createDataSource( rArguments ); +} + +/** + * Fix for #i79009 + * we need to return a property that has the same value as the property + * 'CellRangeRepresentation' but for all rows which are increased by one. + * E.g. Table1.A1:D5 -> Table1,A2:D6 + * Since the problem is only for old charts which did not support multiple + * we do not need to provide that property/string if the 'CellRangeRepresentation' + * contains multiple ranges. + */ +OUString SwChartDataProvider::GetBrokenCellRangeForExport( + std::u16string_view rCellRangeRepresentation ) +{ + // check that we do not have multiple ranges + if (std::u16string_view::npos == rCellRangeRepresentation.find( ';' )) + { + // get current cell and table names + OUString aTableName, aStartCell, aEndCell; + GetTableAndCellsFromRangeRep( rCellRangeRepresentation, + aTableName, aStartCell, aEndCell, false ); + sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; + SwXTextTable::GetCellPosition( aStartCell, nStartCol, nStartRow ); + SwXTextTable::GetCellPosition( aEndCell, nEndCol, nEndRow ); + + // get new cell names + ++nStartRow; + ++nEndRow; + aStartCell = sw_GetCellName( nStartCol, nStartRow ); + aEndCell = sw_GetCellName( nEndCol, nEndRow ); + + return GetRangeRepFromTableAndCells( aTableName, + aStartCell, aEndCell, false ); + } + + return OUString(); +} + +uno::Sequence< beans::PropertyValue > SAL_CALL SwChartDataProvider::detectArguments( + const uno::Reference< chart2::data::XDataSource >& xDataSource ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + uno::Sequence< beans::PropertyValue > aResult; + if (!xDataSource.is()) + return aResult; + + const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDS_LDS( xDataSource->getDataSequences() ); + const uno::Reference< chart2::data::XLabeledDataSequence > *pDS_LDS = aDS_LDS.getConstArray(); + sal_Int32 nNumDS_LDS = aDS_LDS.getLength(); + + if (nNumDS_LDS == 0) + { + OSL_FAIL( "XLabeledDataSequence in data source contains 0 entries" ); + return aResult; + } + + SwFrameFormat *pTableFormat = nullptr; + SwTable *pTable = nullptr; + OUString aTableName; + sal_Int32 nTableRows = 0; + sal_Int32 nTableCols = 0; + + // data used to build 'CellRangeRepresentation' from later on + std::vector< std::vector< char > > aMap; + + uno::Sequence< sal_Int32 > aSequenceMapping( nNumDS_LDS ); + sal_Int32 *pSequenceMapping = aSequenceMapping.getArray(); + + OUString aCellRanges; + sal_Int16 nDtaSrcIsColumns = -1;// -1: don't know yet, 0: false, 1: true -2: neither + sal_Int32 nLabelSeqLen = -1; // used to see if labels are always used or not and have + // the expected size of 1 (i.e. if FirstCellAsLabel can + // be determined) + // -1: don't know yet, 0: not used, 1: always a single labe cell, ... + // -2: neither/failed + for (sal_Int32 nDS1 = 0; nDS1 < nNumDS_LDS; ++nDS1) + { + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledDataSequence( pDS_LDS[nDS1] ); + if( !xLabeledDataSequence.is() ) + { + OSL_FAIL("got NULL for XLabeledDataSequence from Data source"); + continue; + } + const uno::Reference< chart2::data::XDataSequence > xCurLabel = xLabeledDataSequence->getLabel(); + const uno::Reference< chart2::data::XDataSequence > xCurValues = xLabeledDataSequence->getValues(); + + // get sequence lengths for label and values. + // (0 length is Ok) + sal_Int32 nCurLabelSeqLen = -1; + sal_Int32 nCurValuesSeqLen = -1; + if (xCurLabel.is()) + nCurLabelSeqLen = xCurLabel->getData().getLength(); + if (xCurValues.is()) + nCurValuesSeqLen = xCurValues->getData().getLength(); + + // check for consistent use of 'first cell as label' + if (nLabelSeqLen == -1) // set initial value to compare with below further on + nLabelSeqLen = nCurLabelSeqLen; + if (nLabelSeqLen != nCurLabelSeqLen) + nLabelSeqLen = -2; // failed / no consistent use of label cells + + // get table and cell names for label and values data sequences + // (start and end cell will be sorted, i.e. start cell <= end cell) + OUString aLabelTableName, aLabelStartCell, aLabelEndCell; + OUString aValuesTableName, aValuesStartCell, aValuesEndCell; + OUString aLabelRange, aValuesRange; + if (xCurLabel.is()) + aLabelRange = xCurLabel->getSourceRangeRepresentation(); + if (xCurValues.is()) + aValuesRange = xCurValues->getSourceRangeRepresentation(); + if ((!aLabelRange.isEmpty() && !GetTableAndCellsFromRangeRep( aLabelRange, + aLabelTableName, aLabelStartCell, aLabelEndCell )) || + !GetTableAndCellsFromRangeRep( aValuesRange, + aValuesTableName, aValuesStartCell, aValuesEndCell )) + { + return aResult; // failed -> return empty property sequence + } + + // make sure all sequences use the same table + if (aTableName.isEmpty()) + aTableName = aValuesTableName; // get initial value to compare with + if (aTableName.isEmpty() || + aTableName != aValuesTableName || + (!aLabelTableName.isEmpty() && aTableName != aLabelTableName)) + { + return aResult; // failed -> return empty property sequence + } + + // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting + // first and last cell used in both sequences + + sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; + const OUString aCell( !aLabelStartCell.isEmpty() ? aLabelStartCell : aValuesStartCell ); + OSL_ENSURE( !aCell.isEmpty() , "start cell missing?" ); + SwXTextTable::GetCellPosition( aCell, nFirstCol, nFirstRow); + SwXTextTable::GetCellPosition( aValuesEndCell, nLastCol, nLastRow); + + sal_Int16 nDirection = -1; // -1: not yet set, 0: columns, 1: rows, -2: failed + if (nFirstCol == nLastCol && nFirstRow == nLastRow) // a single cell... + { + OSL_ENSURE( nCurLabelSeqLen == 0 && nCurValuesSeqLen == 1, + "trying to determine 'DataRowSource': something's fishy... should have been a single cell"); + nDirection = 0; // default direction for a single cell should be 'columns' + } + else // more than one cell is available (in values and label together!) + { + if (nFirstCol == nLastCol && nFirstRow != nLastRow) + nDirection = 1; + else if (nFirstCol != nLastCol && nFirstRow == nLastRow) + nDirection = 0; + else + { + OSL_FAIL( "trying to determine 'DataRowSource': unexpected case found" ); + nDirection = -2; + } + } + // check for consistent direction of data source + if (nDtaSrcIsColumns == -1) // set initial value to compare with below + nDtaSrcIsColumns = nDirection; + if (nDtaSrcIsColumns != nDirection) + { + nDtaSrcIsColumns = -2; // failed + } + + if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) + { + // build data to obtain 'SequenceMapping' later on + + OSL_ENSURE( nDtaSrcIsColumns == 0 || /* rows */ + nDtaSrcIsColumns == 1, /* columns */ + "unexpected value for 'nDtaSrcIsColumns'" ); + pSequenceMapping[nDS1] = nDtaSrcIsColumns ? nFirstCol : nFirstRow; + + // build data used to determine 'CellRangeRepresentation' later on + + GetTableByName( *m_pDoc, aTableName, &pTableFormat, &pTable ); + if (!pTable || pTable->IsTableComplex()) + return aResult; // failed -> return empty property sequence + nTableRows = pTable->GetTabLines().size(); + nTableCols = pTable->GetTabLines().front()->GetTabBoxes().size(); + aMap.resize( nTableRows ); + for (sal_Int32 i = 0; i < nTableRows; ++i) + aMap[i].resize( nTableCols ); + + if (!aLabelStartCell.isEmpty() && !aLabelEndCell.isEmpty()) + { + sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; + SwXTextTable::GetCellPosition( aLabelStartCell, nStartCol, nStartRow ); + SwXTextTable::GetCellPosition( aLabelEndCell, nEndCol, nEndRow ); + if (nStartRow < 0 || nEndRow >= nTableRows || + nStartCol < 0 || nEndCol >= nTableCols) + { + return aResult; // failed -> return empty property sequence + } + for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) + { + for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) + { + char &rChar = aMap[i][k]; + if (rChar == '\0') // check for overlapping values and/or labels + rChar = 'L'; + else + return aResult; // failed -> return empty property sequence + } + } + } + if (!aValuesStartCell.isEmpty() && !aValuesEndCell.isEmpty()) + { + sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; + SwXTextTable::GetCellPosition( aValuesStartCell, nStartCol, nStartRow ); + SwXTextTable::GetCellPosition( aValuesEndCell, nEndCol, nEndRow ); + if (nStartRow < 0 || nEndRow >= nTableRows || + nStartCol < 0 || nEndCol >= nTableCols) + { + return aResult; // failed -> return empty property sequence + } + for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) + { + for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) + { + char &rChar = aMap[i][k]; + if (rChar == '\0') // check for overlapping values and/or labels + rChar = 'x'; + else + return aResult; // failed -> return empty property sequence + } + } + } + } + +#if OSL_DEBUG_LEVEL > 0 + // do some extra sanity checking that the length of the sequences + // matches their range representation + { + sal_Int32 nStartRow = -1, nStartCol = -1, nEndRow = -1, nEndCol = -1; + if (xCurLabel.is()) + { + SwXTextTable::GetCellPosition( aLabelStartCell, nStartCol, nStartRow); + SwXTextTable::GetCellPosition( aLabelEndCell, nEndCol, nEndRow); + OSL_ENSURE( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurLabel->getData().getLength()) || + (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurLabel->getData().getLength()), + "label sequence length does not match range representation!" ); + } + if (xCurValues.is()) + { + SwXTextTable::GetCellPosition( aValuesStartCell, nStartCol, nStartRow); + SwXTextTable::GetCellPosition( aValuesEndCell, nEndCol, nEndRow); + OSL_ENSURE( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurValues->getData().getLength()) || + (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurValues->getData().getLength()), + "value sequence length does not match range representation!" ); + } + } +#endif + } // for + + // build value for 'CellRangeRepresentation' + + const OUString aCellRangeBase = aTableName + "."; + OUString aCurRange; + for (sal_Int32 i = 0; i < nTableRows; ++i) + { + for (sal_Int32 k = 0; k < nTableCols; ++k) + { + if (aMap[i][k] != '\0') // top-left cell of a sub-range found + { + // find rectangular sub-range to use + sal_Int32 nRowIndex1 = i; // row index + sal_Int32 nColIndex1 = k; // column index + sal_Int32 nRowSubLen = 0; + sal_Int32 nColSubLen = 0; + while (nRowIndex1 < nTableRows && aMap[nRowIndex1++][k] != '\0') + ++nRowSubLen; + // be aware of shifted sequences! + // (according to the checks done prior the length should be ok) + while (nColIndex1 < nTableCols && aMap[i][nColIndex1] != '\0' + && aMap[i + nRowSubLen-1][nColIndex1] != '\0') + { + ++nColIndex1; + ++nColSubLen; + } + OUString aStartCell( sw_GetCellName( k, i ) ); + OUString aEndCell( sw_GetCellName( k + nColSubLen - 1, i + nRowSubLen - 1) ); + aCurRange = aCellRangeBase + aStartCell + ":" + aEndCell; + if (!aCellRanges.isEmpty()) + aCellRanges += ";"; + aCellRanges += aCurRange; + + // clear already found sub-range from map + for (sal_Int32 nRowIndex2 = 0; nRowIndex2 < nRowSubLen; ++nRowIndex2) + for (sal_Int32 nColumnIndex2 = 0; nColumnIndex2 < nColSubLen; ++nColumnIndex2) + aMap[i + nRowIndex2][k + nColumnIndex2] = '\0'; + } + } + } + // to be nice to the user we now sort the cell ranges according to + // rows or columns depending on the direction used in the data source + uno::Sequence< OUString > aSortedRanges; + GetSubranges( aCellRanges, aSortedRanges, false /*sub ranges should already be normalized*/ ); + SortSubranges( aSortedRanges, (nDtaSrcIsColumns == 1) ); + OUString aSortedCellRanges; + for (const OUString& rSortedRange : std::as_const(aSortedRanges)) + { + if (!aSortedCellRanges.isEmpty()) + aSortedCellRanges += ";"; + aSortedCellRanges += rSortedRange; + } + + // build value for 'SequenceMapping' + + uno::Sequence< sal_Int32 > aSortedMapping( aSequenceMapping ); + auto [begin, end] = asNonConstRange(aSortedMapping); + std::sort(begin, end); + bool bNeedSequenceMapping = false; + for (sal_Int32 i = 0; i < aSequenceMapping.getLength(); ++i) + { + auto it = std::find( std::cbegin(aSortedMapping), std::cend(aSortedMapping), + aSequenceMapping[i] ); + pSequenceMapping[i] = std::distance(std::cbegin(aSortedMapping), it); + + if (i != std::as_const(aSequenceMapping)[i]) + bNeedSequenceMapping = true; + } + + // check if 'SequenceMapping' is actually not required... + // (don't write unnecessary properties to the XML file) + if (!bNeedSequenceMapping) + aSequenceMapping.realloc(0); + + // build resulting properties + + OSL_ENSURE(nLabelSeqLen >= 0 || nLabelSeqLen == -2 /*not used*/, + "unexpected value for 'nLabelSeqLen'" ); + bool bFirstCellIsLabel = false; // default value if 'nLabelSeqLen' could not properly determined + if (nLabelSeqLen > 0) // == 0 means no label sequence in use + bFirstCellIsLabel = true; + + OSL_ENSURE( !aSortedCellRanges.isEmpty(), "CellRangeRepresentation missing" ); + const OUString aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges ) ); + + aResult.realloc(5); + auto pResult = aResult.getArray(); + sal_Int32 nProps = 0; + pResult[nProps ].Name = "FirstCellAsLabel"; + pResult[nProps++].Value <<= bFirstCellIsLabel; + pResult[nProps ].Name = "CellRangeRepresentation"; + pResult[nProps++].Value <<= aSortedCellRanges; + if (!aBrokenCellRangeForExport.isEmpty()) + { + pResult[nProps ].Name = "BrokenCellRangeForExport"; + pResult[nProps++].Value <<= aBrokenCellRangeForExport; + } + if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) + { + chart::ChartDataRowSource eDataRowSource = (nDtaSrcIsColumns == 1) ? + chart::ChartDataRowSource_COLUMNS : chart::ChartDataRowSource_ROWS; + pResult[nProps ].Name = "DataRowSource"; + pResult[nProps++].Value <<= eDataRowSource; + + if (aSequenceMapping.hasElements()) + { + pResult[nProps ].Name = "SequenceMapping"; + pResult[nProps++].Value <<= aSequenceMapping; + } + } + aResult.realloc( nProps ); + + return aResult; +} + +uno::Reference< chart2::data::XDataSequence > SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation( + std::u16string_view rRangeRepresentation, bool bTestOnly ) +{ + if (m_bDisposed) + throw lang::DisposedException(); + + SwFrameFormat *pTableFormat = nullptr; // pointer to table format + std::shared_ptr<SwUnoCursor> pUnoCursor; // pointer to new created cursor spanning the cell range + GetFormatAndCreateCursorFromRangeRep( m_pDoc, rRangeRepresentation, + &pTableFormat, pUnoCursor ); + if (!pTableFormat || !pUnoCursor) + throw lang::IllegalArgumentException(); + + // check that cursors point and mark are in a single row or column. + OUString aCellRange( GetCellRangeName( *pTableFormat, *pUnoCursor ) ); + SwRangeDescriptor aDesc; + FillRangeDescriptor( aDesc, aCellRange ); + if (aDesc.nTop != aDesc.nBottom && aDesc.nLeft != aDesc.nRight) + throw lang::IllegalArgumentException(); + + OSL_ENSURE( pTableFormat && pUnoCursor, "table format or cursor missing" ); + uno::Reference< chart2::data::XDataSequence > xDataSeq; + if (!bTestOnly) + xDataSeq = new SwChartDataSequence( *this, *pTableFormat, pUnoCursor ); + + return xDataSeq; +} + +sal_Bool SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentationPossible( + const OUString& rRangeRepresentation ) +{ + SolarMutexGuard aGuard; + + bool bPossible = true; + try + { + Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation, true ); + } + catch (lang::IllegalArgumentException &) + { + bPossible = false; + } + + return bPossible; +} + +uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentation( + const OUString& rRangeRepresentation ) +{ + SolarMutexGuard aGuard; + return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation ); +} + +uno::Reference< sheet::XRangeSelection > SAL_CALL SwChartDataProvider::getRangeSelection( ) +{ + // note: it is no error to return nothing here + return uno::Reference< sheet::XRangeSelection >(); +} + +uno::Reference<css::chart2::data::XDataSequence> SAL_CALL + SwChartDataProvider::createDataSequenceByValueArray( + const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/, + const OUString& /*aRoleQualifier*/ ) +{ + return uno::Reference<css::chart2::data::XDataSequence>(); +} + +void SAL_CALL SwChartDataProvider::dispose( ) +{ + bool bMustDispose( false ); + { + std::unique_lock aGuard( GetChartMutex() ); + bMustDispose = !m_bDisposed; + if (!m_bDisposed) + m_bDisposed = true; + } + if (!bMustDispose) + return; + + // dispose all data-sequences + for (const auto& rEntry : m_aDataSequences) + { + DisposeAllDataSequences( rEntry.first ); + } + // release all references to data-sequences + m_aDataSequences.clear(); + + // require listeners to release references to this object + lang::EventObject aEvtObj( static_cast< chart2::data::XDataProvider * >(this) ); + std::unique_lock aGuard( GetChartMutex() ); + m_aEventListeners.disposeAndClear( aGuard, aEvtObj ); +} + +void SAL_CALL SwChartDataProvider::addEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEventListeners.addInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartDataProvider::removeEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEventListeners.removeInterface( aGuard, rxListener ); +} + +OUString SAL_CALL SwChartDataProvider::getImplementationName( ) +{ + return "SwChartDataProvider"; +} + +sal_Bool SAL_CALL SwChartDataProvider::supportsService(const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwChartDataProvider::getSupportedServiceNames( ) +{ + return { "com.sun.star.chart2.data.DataProvider"}; +} + +void SwChartDataProvider::AddDataSequence( const SwTable &rTable, rtl::Reference< SwChartDataSequence > const &rxDataSequence ) +{ + Vec_DataSequenceRef_t& rVec = m_aDataSequences[ &rTable ]; + assert(std::find_if(rVec.begin(), rVec.end(), + [&rxDataSequence](const unotools::WeakReference < SwChartDataSequence >& i) + { + return i.get() == rxDataSequence; + }) == rVec.end() && "duplicate insert"); + rVec.push_back( rxDataSequence ); +} + +void SwChartDataProvider::RemoveDataSequence( const SwTable &rTable, rtl::Reference< SwChartDataSequence > const &rxDataSequence ) +{ + Vec_DataSequenceRef_t& rVec = m_aDataSequences[ &rTable ]; + std::erase_if(rVec, + [&rxDataSequence](const unotools::WeakReference < SwChartDataSequence >& i) + { + return i.get() == rxDataSequence; + }); +} + +void SwChartDataProvider::InvalidateTable( const SwTable *pTable, bool bImmediate ) +{ + OSL_ENSURE( pTable, "table pointer is NULL" ); + if (!pTable) + return; + + if (!m_bDisposed) + pTable->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking(); + + const Vec_DataSequenceRef_t &rVec = m_aDataSequences[ pTable ]; + for (const unotools::WeakReference<SwChartDataSequence>& rItem : rVec) + { + rtl::Reference< SwChartDataSequence > xRef(rItem); + if (xRef.is()) + { + // mark the sequence as 'dirty' and notify listeners + xRef->setModified( true ); + } + } + + // tdf#122995 added Immediate-mode to allow non-timer-delayed Chart invalidation + if (bImmediate && !m_bDisposed) + pTable->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().Disconnect(); +} + +void SwChartDataProvider::DeleteBox( const SwTable *pTable, const SwTableBox &rBox ) +{ + OSL_ENSURE( pTable, "table pointer is NULL" ); + if (!pTable) + return; + + if (!m_bDisposed) + pTable->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking(); + + Vec_DataSequenceRef_t &rVec = m_aDataSequences[ pTable ]; + + // iterate over all data-sequences for that table... + auto aIt( rVec.begin() ); + while (aIt != rVec.end()) + { + bool bNowEmpty = false; + bool bSeqDisposed = false; + + // check if weak reference is still valid... + rtl::Reference< SwChartDataSequence > pDataSeq(*aIt); + if (pDataSeq.is()) + { + // then delete that table box (check if implementation cursor needs to be adjusted) + try + { + bNowEmpty = pDataSeq->DeleteBox( rBox ); + } + catch (const lang::DisposedException&) + { + bNowEmpty = true; + bSeqDisposed = true; + } + } + + if (bNowEmpty) + { + aIt = rVec.erase( aIt ); + if (pDataSeq && !bSeqDisposed) + pDataSeq->dispose(); // the current way to tell chart that sth. got removed + } + else + ++aIt; + } +} + +void SwChartDataProvider::DisposeAllDataSequences( const SwTable *pTable ) +{ + OSL_ENSURE( pTable, "table pointer is NULL" ); + if (!pTable) + return; + + if (!m_bDisposed) + pTable->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().StartOrContinueLocking(); + + //! make a copy of the STL container! + //! This is necessary since calling 'dispose' will implicitly remove an element + //! of the original container, and thus any iterator in the original container + //! would become invalid. + const Vec_DataSequenceRef_t aVec( m_aDataSequences[ pTable ] ); + + for (const unotools::WeakReference<SwChartDataSequence>& rItem : aVec) + { + rtl::Reference< SwChartDataSequence > xRef(rItem); + if (xRef.is()) + { + xRef->dispose(); + } + } +} + +/** + * SwChartDataProvider::AddRowCols tries to notify charts of added columns + * or rows and extends the value sequence respectively (if possible). + * If those can be added to the end of existing value data-sequences those + * sequences get modified accordingly and will send a modification + * notification (calling 'setModified + * + * Since this function is a work-around for non existent Writer core functionality + * (no arbitrary multi-selection in tables that can be used to define a + * data-sequence) this function will be somewhat unreliable. + * For example we will only try to adapt value sequences. For this we assume + * that a sequence of length 1 is a label sequence and those with length >= 2 + * we presume to be value sequences. Also new cells can only be added in the + * direction the value sequence is already pointing (rows / cols) and at the + * start or end of the values data-sequence. + * Nothing needs to be done if the new cells are in between the table cursors + * point and mark since data-sequence are considered to consist of all cells + * between those. + * New rows/cols need to be added already to the table before calling + * this function. + */ +void SwChartDataProvider::AddRowCols( + const SwTable &rTable, + const SwSelBoxes& rBoxes, + sal_uInt16 nLines, bool bBehind ) +{ + if (rTable.IsTableComplex()) + return; + + const size_t nBoxes = rBoxes.size(); + if (nBoxes < 1 || nLines < 1) + return; + + SwTableBox* pFirstBox = rBoxes[0]; + SwTableBox* pLastBox = rBoxes.back(); + + if (!(pFirstBox && pLastBox)) + return; + + sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; + SwXTextTable::GetCellPosition( pFirstBox->GetName(), nFirstCol, nFirstRow ); + SwXTextTable::GetCellPosition( pLastBox->GetName(), nLastCol, nLastRow ); + + bool bAddCols = false; // default; also to be used if nBoxes == 1 :-/ + if (nFirstCol == nLastCol && nFirstRow != nLastRow) + bAddCols = true; + if (nFirstCol != nLastCol && nFirstRow != nLastRow) + return; + + //get range of indices in col/rows for new cells + sal_Int32 nFirstNewCol = nFirstCol; + sal_Int32 nFirstNewRow = bBehind ? nFirstRow + 1 : nFirstRow - nLines; + if (bAddCols) + { + OSL_ENSURE( nFirstCol == nLastCol, "column indices seem broken" ); + nFirstNewCol = bBehind ? nFirstCol + 1 : nFirstCol - nLines; + nFirstNewRow = nFirstRow; + } + + // iterate over all data-sequences for the table + const Vec_DataSequenceRef_t &rVec = m_aDataSequences[ &rTable ]; + for (const unotools::WeakReference<SwChartDataSequence>& rItem : rVec) + { + rtl::Reference< SwChartDataSequence > pDataSeq(rItem); + if (pDataSeq.is()) + { + const sal_Int32 nLen = pDataSeq->getTextualData().getLength(); + if (nLen > 1) // value data-sequence ? + { + SwRangeDescriptor aDesc; + pDataSeq->FillRangeDesc( aDesc ); + + chart::ChartDataRowSource eDRSource = chart::ChartDataRowSource_COLUMNS; + if (aDesc.nTop == aDesc.nBottom && aDesc.nLeft != aDesc.nRight) + eDRSource = chart::ChartDataRowSource_ROWS; + + if (!bAddCols && eDRSource == chart::ChartDataRowSource_COLUMNS) + { + // add rows: extend affected columns by newly added row cells + pDataSeq->ExtendTo( true, nFirstNewRow, nLines ); + } + else if (bAddCols && eDRSource == chart::ChartDataRowSource_ROWS) + { + // add cols: extend affected rows by newly added column cells + pDataSeq->ExtendTo( false, nFirstNewCol, nLines ); + } + } + } + } +} + +// XRangeXMLConversion +OUString SAL_CALL SwChartDataProvider::convertRangeToXML( const OUString& rRangeRepresentation ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (rRangeRepresentation.isEmpty()) + return OUString(); + + OUStringBuffer aRes; + + // multiple ranges are delimited by a ';' like in + // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges! + SwTable* pFirstFoundTable = nullptr; // to check that only one table will be used + sal_Int32 nPos = 0; + do { + const OUString aRange( rRangeRepresentation.getToken(0, ';', nPos) ); + SwFrameFormat *pTableFormat = nullptr; // pointer to table format + std::shared_ptr<SwUnoCursor> pCursor; + GetFormatAndCreateCursorFromRangeRep( m_pDoc, aRange, &pTableFormat, pCursor ); + if (!pTableFormat) + throw lang::IllegalArgumentException(); + SwTable* pTable = SwTable::FindTable( pTableFormat ); + if (pTable->IsTableComplex()) + throw uno::RuntimeException("Table too complex."); + + // check that there is only one table used in all ranges + if (!pFirstFoundTable) + pFirstFoundTable = pTable; + if (pTable != pFirstFoundTable) + throw lang::IllegalArgumentException(); + + OUString aTableName; + OUString aStartCell; + OUString aEndCell; + if (!GetTableAndCellsFromRangeRep( aRange, aTableName, aStartCell, aEndCell )) + throw lang::IllegalArgumentException(); + + sal_Int32 nCol, nRow; + SwXTextTable::GetCellPosition( aStartCell, nCol, nRow ); + if (nCol < 0 || nRow < 0) + throw uno::RuntimeException("Cell not found."); + + //!! following objects/functions are implemented in XMLRangeHelper.?xx + //!! which is a copy of the respective file from chart2 !! + XMLRangeHelper::CellRange aCellRange; + aCellRange.aTableName = aTableName; + aCellRange.aUpperLeft.nColumn = nCol; + aCellRange.aUpperLeft.nRow = nRow; + aCellRange.aUpperLeft.bIsEmpty = false; + if (aStartCell != aEndCell && !aEndCell.isEmpty()) + { + SwXTextTable::GetCellPosition( aEndCell, nCol, nRow ); + if (nCol < 0 || nRow < 0) + throw uno::RuntimeException("Cell not found."); + + aCellRange.aLowerRight.nColumn = nCol; + aCellRange.aLowerRight.nRow = nRow; + aCellRange.aLowerRight.bIsEmpty = false; + } + OUString aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange ) ); + if (!aRes.isEmpty()) // in case of multiple ranges add delimiter + aRes.append(" "); + aRes.append(aTmp); + } + while (nPos>0); + + return aRes.makeStringAndClear(); +} + +OUString SAL_CALL SwChartDataProvider::convertRangeFromXML( const OUString& rXMLRange ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (rXMLRange.isEmpty()) + return OUString(); + + OUStringBuffer aRes; + + // multiple ranges are delimited by a ' ' like in + // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges! + OUString aFirstFoundTable; // to check that only one table will be used + sal_Int32 nPos = 0; + do + { + OUString aRange( rXMLRange.getToken(0, ' ', nPos) ); + + //!! following objects and function are implemented in XMLRangeHelper.?xx + //!! which is a copy of the respective file from chart2 !! + XMLRangeHelper::CellRange aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange )); + + // check that there is only one table used in all ranges + if (aFirstFoundTable.isEmpty()) + aFirstFoundTable = aCellRange.aTableName; + if (aCellRange.aTableName != aFirstFoundTable) + throw lang::IllegalArgumentException(); + + OUString aTmp = aCellRange.aTableName + "." + + sw_GetCellName( aCellRange.aUpperLeft.nColumn, + aCellRange.aUpperLeft.nRow ); + // does cell range consist of more than a single cell? + if (!aCellRange.aLowerRight.bIsEmpty) + { + aTmp += ":" + sw_GetCellName( aCellRange.aLowerRight.nColumn, + aCellRange.aLowerRight.nRow ); + } + + if (!aRes.isEmpty()) // in case of multiple ranges add delimiter + aRes.append(";"); + aRes.append(aTmp); + } + while (nPos>0); + + return aRes.makeStringAndClear(); +} + +SwChartDataSource::SwChartDataSource( + const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > &rLDS ) : + m_aLDS( rLDS ) +{ +} + +SwChartDataSource::~SwChartDataSource() +{ +} + +uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL SwChartDataSource::getDataSequences( ) +{ + SolarMutexGuard aGuard; + return m_aLDS; +} + +OUString SAL_CALL SwChartDataSource::getImplementationName( ) +{ + return "SwChartDataSource"; +} + +sal_Bool SAL_CALL SwChartDataSource::supportsService(const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwChartDataSource::getSupportedServiceNames( ) +{ + return { "com.sun.star.chart2.data.DataSource" }; +} + +SwChartDataSequence::SwChartDataSequence( + SwChartDataProvider& rProvider, + SwFrameFormat& rTableFormat, + const std::shared_ptr<SwUnoCursor>& pTableCursor ) : + m_pFormat(&rTableFormat), + m_aRowLabelText( SwResId( STR_CHART2_ROW_LABEL_TEXT ) ), + m_aColLabelText( SwResId( STR_CHART2_COL_LABEL_TEXT ) ), + m_xDataProvider( &rProvider ), + m_pTableCursor( pTableCursor ), + m_pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE ) ) +{ + StartListening(rTableFormat.GetNotifier()); + m_bDisposed = false; + + acquire(); + try + { + const SwTable* pTable = SwTable::FindTable( &rTableFormat ); + if (pTable) + { + m_xDataProvider->AddDataSequence( *pTable, this ); + m_xDataProvider->addEventListener( static_cast< lang::XEventListener * >(this) ); + } + else { + OSL_FAIL( "table missing" ); + } + } + catch (uno::RuntimeException &) + { + // TODO: shouldn't there be a call to release() here? + throw; + } + catch (uno::Exception &) + { + } + release(); + +#if OSL_DEBUG_LEVEL > 0 + // check if it can properly convert into a SwUnoTableCursor + // which is required for some functions + SwUnoTableCursor* pUnoTableCursor = dynamic_cast<SwUnoTableCursor*>(&(*m_pTableCursor)); + OSL_ENSURE(pUnoTableCursor, "SwChartDataSequence: cursor not SwUnoTableCursor"); +#endif +} + +SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence &rObj ) : + SwChartDataSequenceBaseClass(rObj), + SvtListener(), + m_pFormat( rObj.m_pFormat ), + m_aRole( rObj.m_aRole ), + m_aRowLabelText( SwResId(STR_CHART2_ROW_LABEL_TEXT) ), + m_aColLabelText( SwResId(STR_CHART2_COL_LABEL_TEXT) ), + m_xDataProvider( rObj.m_xDataProvider ), + m_pTableCursor( rObj.m_pTableCursor ), + m_pPropSet( rObj.m_pPropSet ) +{ + if(m_pFormat) + StartListening(m_pFormat->GetNotifier()); + m_bDisposed = false; + + acquire(); + try + { + const SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); + if (pTable) + { + m_xDataProvider->AddDataSequence( *pTable, this ); + m_xDataProvider->addEventListener( static_cast< lang::XEventListener * >(this) ); + } + else { + OSL_FAIL( "table missing" ); + } + } + catch (uno::RuntimeException &) + { + // TODO: shouldn't there be a call to release() here? + throw; + } + catch (uno::Exception &) + { + } + release(); + +#if OSL_DEBUG_LEVEL > 0 + // check if it can properly convert into a SwUnoTableCursor + // which is required for some functions + SwUnoTableCursor* pUnoTableCursor = dynamic_cast<SwUnoTableCursor*>(&(*m_pTableCursor)); + OSL_ENSURE(pUnoTableCursor, "SwChartDataSequence: cursor not SwUnoTableCursor"); +#endif +} + +SwChartDataSequence::~SwChartDataSequence() +{ +} + +OUString SAL_CALL SwChartDataSequence::getSourceRangeRepresentation( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + OUString aRes; + SwFrameFormat* pTableFormat = GetFrameFormat(); + if (pTableFormat) + { + const OUString aCellRange( GetCellRangeName( *pTableFormat, *m_pTableCursor ) ); + OSL_ENSURE( !aCellRange.isEmpty(), "failed to get cell range" ); + aRes = pTableFormat->GetName() + "." + aCellRange; + } + return aRes; +} + +uno::Sequence< OUString > SAL_CALL SwChartDataSequence::generateLabel( + chart2::data::LabelOrigin eLabelOrigin ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + uno::Sequence< OUString > aLabels; + + { + SwRangeDescriptor aDesc; + bool bOk = false; + SwFrameFormat* pTableFormat = GetFrameFormat(); + if (!pTableFormat) + throw uno::RuntimeException("No table format found."); + SwTable* pTable = SwTable::FindTable( pTableFormat ); + if (!pTable) + throw uno::RuntimeException("No table found."); + if (pTable->IsTableComplex()) + throw uno::RuntimeException("Table too complex."); + + const OUString aCellRange( GetCellRangeName( *pTableFormat, *m_pTableCursor ) ); + OSL_ENSURE( !aCellRange.isEmpty(), "failed to get cell range" ); + bOk = FillRangeDescriptor( aDesc, aCellRange ); + OSL_ENSURE( bOk, "failed to get SwRangeDescriptor" ); + + if (bOk) + { + aDesc.Normalize(); + sal_Int32 nColSpan = aDesc.nRight - aDesc.nLeft + 1; + sal_Int32 nRowSpan = aDesc.nBottom - aDesc.nTop + 1; + OSL_ENSURE( nColSpan == 1 || nRowSpan == 1, + "unexpected range of selected cells" ); + + OUString aText; // label text to be returned + bool bReturnEmptyText = false; + bool bUseCol = true; + if (eLabelOrigin == chart2::data::LabelOrigin_COLUMN) + bUseCol = true; + else if (eLabelOrigin == chart2::data::LabelOrigin_ROW) + bUseCol = false; + else if (eLabelOrigin == chart2::data::LabelOrigin_SHORT_SIDE) + { + bUseCol = nColSpan < nRowSpan; + bReturnEmptyText = nColSpan == nRowSpan; + } + else if (eLabelOrigin == chart2::data::LabelOrigin_LONG_SIDE) + { + bUseCol = nColSpan > nRowSpan; + bReturnEmptyText = nColSpan == nRowSpan; + } + else { + OSL_FAIL( "unexpected case" ); + } + + // build label sequence + + sal_Int32 nSeqLen = bUseCol ? nColSpan : nRowSpan; + aLabels.realloc( nSeqLen ); + OUString *pLabels = aLabels.getArray(); + for (sal_Int32 i = 0; i < nSeqLen; ++i) + { + if (!bReturnEmptyText) + { + aText = bUseCol ? m_aColLabelText : m_aRowLabelText; + sal_Int32 nCol = aDesc.nLeft; + sal_Int32 nRow = aDesc.nTop; + if (bUseCol) + nCol = nCol + i; + else + nRow = nRow + i; + OUString aCellName( sw_GetCellName( nCol, nRow ) ); + + sal_Int32 nLen = aCellName.getLength(); + if (nLen) + { + const sal_Unicode *pBuf = aCellName.getStr(); + const sal_Unicode *pEnd = pBuf + nLen; + while (pBuf < pEnd && ('0' > *pBuf || *pBuf > '9')) + ++pBuf; + // start of number found? + if (pBuf < pEnd && ('0' <= *pBuf && *pBuf <= '9')) + { + OUString aRplc; + std::u16string_view aNew; + if (bUseCol) + { + aRplc = "%COLUMNLETTER"; + aNew = aCellName.subView(0, pBuf - aCellName.getStr()); + } + else + { + aRplc = "%ROWNUMBER"; + aNew = std::u16string_view(pBuf, (aCellName.getStr() + nLen) - pBuf); + } + aText = aText.replaceFirst( aRplc, aNew ); + } + } + } + pLabels[i] = aText; + } + } + } + + return aLabels; +} + +::sal_Int32 SAL_CALL SwChartDataSequence::getNumberFormatKeyByIndex( + ::sal_Int32 /*nIndex*/ ) +{ + return 0; +} + +std::vector< css::uno::Reference< css::table::XCell > > SwChartDataSequence::GetCells() +{ + if (m_bDisposed) + throw lang::DisposedException(); + auto pTableFormat(GetFrameFormat()); + if(!pTableFormat) + return std::vector< css::uno::Reference< css::table::XCell > >(); + auto pTable(SwTable::FindTable(pTableFormat)); + if(pTable->IsTableComplex()) + return std::vector< css::uno::Reference< css::table::XCell > >(); + SwRangeDescriptor aDesc; + if(!FillRangeDescriptor(aDesc, GetCellRangeName(*pTableFormat, *m_pTableCursor))) + return std::vector< css::uno::Reference< css::table::XCell > >(); + return SwXCellRange::CreateXCellRange(m_pTableCursor, *pTableFormat, aDesc)->GetCells(); +} + +uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getTextualData() +{ + SolarMutexGuard aGuard; + auto vCells(GetCells()); + uno::Sequence< OUString > vTextData(vCells.size()); + std::transform(vCells.begin(), + vCells.end(), + vTextData.getArray(), + [] (decltype(vCells)::value_type& xCell) + { return static_cast<SwXCell*>(xCell.get())->getString(); }); + return vTextData; +} + +uno::Sequence< uno::Any > SAL_CALL SwChartDataSequence::getData() +{ + SolarMutexGuard aGuard; + try + { + auto vCells(GetCells()); + uno::Sequence< uno::Any > vAnyData(vCells.size()); + std::transform(vCells.begin(), + vCells.end(), + vAnyData.getArray(), + [] (decltype(vCells)::value_type& xCell) + { return static_cast<SwXCell*>(xCell.get())->GetAny(); }); + return vAnyData; + } + catch (const lang::DisposedException&) + { + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + } + return uno::Sequence< uno::Any >{}; +} + +uno::Sequence< double > SAL_CALL SwChartDataSequence::getNumericalData() +{ + SolarMutexGuard aGuard; + auto vCells(GetCells()); + uno::Sequence< double > vNumData(vCells.size()); + std::transform(vCells.begin(), + vCells.end(), + vNumData.getArray(), + [] (decltype(vCells)::value_type& xCell) + { return static_cast<SwXCell*>(xCell.get())->GetForcedNumericalValue(); }); + return vNumData; +} + +uno::Reference< util::XCloneable > SAL_CALL SwChartDataSequence::createClone( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + return new SwChartDataSequence( *this ); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL SwChartDataSequence::getPropertySetInfo( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + static uno::Reference< beans::XPropertySetInfo > xRes = m_pPropSet->getPropertySetInfo(); + return xRes; +} + +void SAL_CALL SwChartDataSequence::setPropertyValue( + const OUString& rPropertyName, + const uno::Any& rValue ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (rPropertyName != UNO_NAME_ROLE) + throw beans::UnknownPropertyException(rPropertyName); + + if ( !(rValue >>= m_aRole) ) + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL SwChartDataSequence::getPropertyValue( + const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (!(rPropertyName == UNO_NAME_ROLE)) + throw beans::UnknownPropertyException(rPropertyName); + + return uno::Any(m_aRole); +} + +void SAL_CALL SwChartDataSequence::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL( "not implemented" ); +} + +void SAL_CALL SwChartDataSequence::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL( "not implemented" ); +} + +void SAL_CALL SwChartDataSequence::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) +{ + OSL_FAIL( "not implemented" ); +} + +void SAL_CALL SwChartDataSequence::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) +{ + OSL_FAIL( "not implemented" ); +} + +OUString SAL_CALL SwChartDataSequence::getImplementationName( ) +{ + return "SwChartDataSequence"; +} + +sal_Bool SAL_CALL SwChartDataSequence::supportsService(const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getSupportedServiceNames( ) +{ + return { "com.sun.star.chart2.data.DataSequence" }; +} + +void SwChartDataSequence::Notify( const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFormat = nullptr; + if(!m_pFormat || !m_pTableCursor) + { + m_pFormat = nullptr; + m_pTableCursor.reset(nullptr); + dispose(); + } + else if (rHint.GetId() == SfxHintId::SwLegacyModify) + { + setModified( true ); + } +} + +sal_Bool SAL_CALL SwChartDataSequence::isModified( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + return true; +} + +void SAL_CALL SwChartDataSequence::setModified( + sal_Bool bModified ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (bModified) + LaunchModifiedEvent( m_aModifyListeners, static_cast< XModifyBroadcaster * >(this) ); +} + +void SAL_CALL SwChartDataSequence::addModifyListener( + const uno::Reference< util::XModifyListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aModifyListeners.addInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartDataSequence::removeModifyListener( + const uno::Reference< util::XModifyListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aModifyListeners.removeInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartDataSequence::disposing( const lang::EventObject& rSource ) +{ + if (m_bDisposed) + throw lang::DisposedException(); + if (rSource.Source == cppu::getXWeak(m_xDataProvider.get())) + { + m_xDataProvider.clear(); + } +} + +void SAL_CALL SwChartDataSequence::dispose( ) +{ + bool bMustDispose( false ); + { + std::unique_lock aGuard( GetChartMutex() ); + bMustDispose = !m_bDisposed; + if (!m_bDisposed) + m_bDisposed = true; + } + if (!bMustDispose) + return; + + m_bDisposed = true; + if (m_xDataProvider.is()) + { + const SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); + if (pTable) + { + m_xDataProvider->RemoveDataSequence( *pTable, this ); + } + else { + OSL_FAIL( "table missing" ); + } + + //#i119653# The bug is crashed for an exception thrown by + //SwCharDataSequence::setModified() because + //the SwCharDataSequence object has been disposed. + + //Actually, the former design of SwClient will disconnect itself + //from the notification list in its destructor. + + //But the SwCharDataSequence won't be destructed but disposed in code + //(the data member SwChartDataSequence::bDisposed will be set to + //TRUE), the relationship between client and modification is not + //released. + + //So any notification from modify object will lead to said + //exception threw out. Recorrect the logic of code in + //SwChartDataSequence::Dispose(), release the relationship + //here... + if (m_pFormat && m_pFormat->HasWriterListeners()) + { + EndListeningAll(); + m_pFormat = nullptr; + m_pTableCursor.reset(nullptr); + } + } + + // require listeners to release references to this object + lang::EventObject aEvtObj( static_cast< chart2::data::XDataSequence * >(this) ); + std::unique_lock aGuard( GetChartMutex() ); + m_aModifyListeners.disposeAndClear( aGuard, aEvtObj ); + m_aEvtListeners.disposeAndClear( aGuard, aEvtObj ); +} + +void SAL_CALL SwChartDataSequence::addEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEvtListeners.addInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartDataSequence::removeEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEvtListeners.removeInterface( aGuard, rxListener ); +} + +bool SwChartDataSequence::DeleteBox( const SwTableBox &rBox ) +{ + if (m_bDisposed) + throw lang::DisposedException(); + + // to be set if the last box of the data-sequence was removed here + bool bNowEmpty = false; + + // if the implementation cursor gets affected (i.e. the box where it is located + // in gets removed) we need to move it before that... (otherwise it does not need to change) + + const SwStartNode* pPointStartNode = m_pTableCursor->GetPoint()->GetNode().FindTableBoxStartNode(); + const SwStartNode* pMarkStartNode = m_pTableCursor->GetMark()->GetNode().FindTableBoxStartNode(); + + if (!m_pTableCursor->HasMark() || (pPointStartNode == rBox.GetSttNd() && pMarkStartNode == rBox.GetSttNd())) + { + bNowEmpty = true; + } + else if (pPointStartNode == rBox.GetSttNd() || pMarkStartNode == rBox.GetSttNd()) + { + sal_Int32 nPointRow = -1, nPointCol = -1; + sal_Int32 nMarkRow = -1, nMarkCol = -1; + const SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); + OUString aPointCellName( pTable->GetTableBox( pPointStartNode->GetIndex() )->GetName() ); + OUString aMarkCellName( pTable->GetTableBox( pMarkStartNode->GetIndex() )->GetName() ); + + SwXTextTable::GetCellPosition( aPointCellName, nPointCol, nPointRow ); + SwXTextTable::GetCellPosition( aMarkCellName, nMarkCol, nMarkRow ); + OSL_ENSURE( nPointRow >= 0 && nPointCol >= 0, "invalid row and col" ); + OSL_ENSURE( nMarkRow >= 0 && nMarkCol >= 0, "invalid row and col" ); + + // move vertical or horizontal? + OSL_ENSURE( nPointRow == nMarkRow || nPointCol == nMarkCol, + "row/col indices not matching" ); + OSL_ENSURE( nPointRow != nMarkRow || nPointCol != nMarkCol, + "point and mark are identical" ); + bool bMoveVertical = (nPointCol == nMarkCol); + bool bMoveHorizontal = (nPointRow == nMarkRow); + + // get movement direction + bool bMoveLeft = false; // move left or right? + bool bMoveUp = false; // move up or down? + if (bMoveVertical) + { + if (pPointStartNode == rBox.GetSttNd()) // move point? + bMoveUp = nPointRow > nMarkRow; + else // move mark + bMoveUp = nMarkRow > nPointRow; + } + else if (bMoveHorizontal) + { + if (pPointStartNode == rBox.GetSttNd()) // move point? + bMoveLeft = nPointCol > nMarkCol; + else // move mark + bMoveLeft = nMarkCol > nPointCol; + } + else { + OSL_FAIL( "neither vertical nor horizontal movement" ); + } + + // get new box (position) to use... + sal_Int32 nRow = (pPointStartNode == rBox.GetSttNd()) ? nPointRow : nMarkRow; + sal_Int32 nCol = (pPointStartNode == rBox.GetSttNd()) ? nPointCol : nMarkCol; + if (bMoveVertical) + nRow += bMoveUp ? -1 : +1; + if (bMoveHorizontal) + nCol += bMoveLeft ? -1 : +1; + const OUString aNewCellName = sw_GetCellName( nCol, nRow ); + SwTableBox* pNewBox = const_cast<SwTableBox*>(pTable->GetTableBox( aNewCellName )); + + if (pNewBox) // set new position (cell range) to use + { + // This is how you get the first content node of a row: + // First get a SwNodeIndex pointing to the node after SwStartNode of the box... + SwNodeIndex aIdx( *pNewBox->GetSttNd(), +1 ); + // This can be a SwContentNode, but might also be a table or section node, + // therefore call GoNext + SwContentNode *pCNd = aIdx.GetNode().GetContentNode(); + if (!pCNd) + pCNd = GetFrameFormat()->GetDoc()->GetNodes().GoNext( &aIdx ); + // and then one can e.g. create a SwPosition: + SwPosition aNewPos( *pCNd ); // new position to be used with cursor + + // if the mark is to be changed, make sure there is one + if (pMarkStartNode == rBox.GetSttNd() && !m_pTableCursor->HasMark()) + m_pTableCursor->SetMark(); + + // set cursor to new position + SwPosition *pPos = (pPointStartNode == rBox.GetSttNd()) ? + m_pTableCursor->GetPoint() : m_pTableCursor->GetMark(); + if (pPos) + { + *pPos = aNewPos; + } + else { + OSL_FAIL( "neither point nor mark available for change" ); + } + } + else { + OSL_FAIL( "failed to get position" ); + } + } + + return bNowEmpty; +} + +void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor &rRangeDesc ) const +{ + SwFrameFormat* pTableFormat = GetFrameFormat(); + if(pTableFormat) + { + SwTable* pTable = SwTable::FindTable( pTableFormat ); + if(!pTable->IsTableComplex()) + { + FillRangeDescriptor( rRangeDesc, GetCellRangeName( *pTableFormat, *m_pTableCursor ) ); + } + } +} + +/** + * Extends the data-sequence by new cells added at the end of the direction + * the data-sequence points to. + * If the cells are already within the range of the sequence nothing needs + * to be done. + * If the cells are beyond the end of the sequence (are not adjacent to the + * current last cell) nothing can be done. Only if the cells are adjacent to + * the last cell they can be added. + * + * @returns true if the data-sequence was changed. + * @param bExtendCols - specifies if columns or rows are to be extended + * @param nFirstNew - index of first new row/col to be included in data-sequence + * @param nLastNew - index of last new row/col to be included in data-sequence + */ +void SwChartDataSequence::ExtendTo( bool bExtendCol, + sal_Int32 nFirstNew, sal_Int32 nCount ) +{ + SwUnoTableCursor* pUnoTableCursor = dynamic_cast<SwUnoTableCursor*>(&(*m_pTableCursor)); + if (!pUnoTableCursor) + return; + + const SwStartNode *pStartNd = nullptr; + const SwTableBox *pStartBox = nullptr; + const SwTableBox *pEndBox = nullptr; + + const SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); + OSL_ENSURE( !pTable->IsTableComplex(), "table too complex" ); + if (nCount < 1 || nFirstNew < 0 || pTable->IsTableComplex()) + return; + + // get range descriptor (cell range) for current data-sequence + + pStartNd = pUnoTableCursor->GetPoint()->GetNode().FindTableBoxStartNode(); + pEndBox = pTable->GetTableBox( pStartNd->GetIndex() ); + const OUString aEndBox( pEndBox->GetName() ); + + pStartNd = pUnoTableCursor->GetMark()->GetNode().FindTableBoxStartNode(); + pStartBox = pTable->GetTableBox( pStartNd->GetIndex() ); + const OUString aStartBox( pStartBox->GetName() ); + + SwRangeDescriptor aDesc; + // note that cell range here takes the newly added rows/cols already into account + OUString sDescrip = aStartBox + ":" + aEndBox; + FillRangeDescriptor( aDesc, sDescrip ); + + bool bChanged = false; + OUString aNewStartCell; + OUString aNewEndCell; + if (bExtendCol && aDesc.nBottom + 1 == nFirstNew) + { + // new column cells adjacent to the bottom of the + // current data-sequence to be added... + OSL_ENSURE( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); + aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop); + aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom + nCount); + bChanged = true; + } + else if (bExtendCol && aDesc.nTop - nCount == nFirstNew) + { + // new column cells adjacent to the top of the + // current data-sequence to be added... + OSL_ENSURE( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); + aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop - nCount); + aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom); + bChanged = true; + } + else if (!bExtendCol && aDesc.nRight + 1 == nFirstNew) + { + // new row cells adjacent to the right of the + // current data-sequence to be added... + OSL_ENSURE( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); + aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop); + aNewEndCell = sw_GetCellName(aDesc.nRight + nCount, aDesc.nBottom); + bChanged = true; + } + else if (!bExtendCol && aDesc.nLeft - nCount == nFirstNew) + { + // new row cells adjacent to the left of the + // current data-sequence to be added... + OSL_ENSURE( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); + aNewStartCell = sw_GetCellName(aDesc.nLeft - nCount, aDesc.nTop); + aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom); + bChanged = true; + } + + if (bChanged) + { + // move table cursor to new start and end of data-sequence + const SwTableBox *pNewStartBox = pTable->GetTableBox( aNewStartCell ); + const SwTableBox *pNewEndBox = pTable->GetTableBox( aNewEndCell ); + pUnoTableCursor->SetMark(); + pUnoTableCursor->GetPoint()->Assign( *pNewEndBox->GetSttNd() ); + pUnoTableCursor->GetMark()->Assign( *pNewStartBox->GetSttNd() ); + pUnoTableCursor->Move( fnMoveForward, GoInNode ); + pUnoTableCursor->MakeBoxSels(); + } +} + +SwChartLabeledDataSequence::SwChartLabeledDataSequence() +{ + m_bDisposed = false; +} + +SwChartLabeledDataSequence::~SwChartLabeledDataSequence() +{ +} + +uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getValues( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + return m_xData; +} + +void SwChartLabeledDataSequence::SetDataSequence( + uno::Reference< chart2::data::XDataSequence >& rxDest, + const uno::Reference< chart2::data::XDataSequence >& rxSource) +{ + uno::Reference< util::XModifyListener > xML(this); + uno::Reference< lang::XEventListener > xEL(this); + + // stop listening to old data-sequence + uno::Reference< util::XModifyBroadcaster > xMB( rxDest, uno::UNO_QUERY ); + if (xMB.is()) + xMB->removeModifyListener( xML ); + uno::Reference< lang::XComponent > xC( rxDest, uno::UNO_QUERY ); + if (xC.is()) + xC->removeEventListener( xEL ); + + rxDest = rxSource; + + // start listening to new data-sequence + xC.set( rxDest, uno::UNO_QUERY ); + if (xC.is()) + xC->addEventListener( xEL ); + xMB.set( rxDest, uno::UNO_QUERY ); + if (xMB.is()) + xMB->addModifyListener( xML ); +} + +void SAL_CALL SwChartLabeledDataSequence::setValues( + const uno::Reference< chart2::data::XDataSequence >& rxSequence ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (m_xData != rxSequence) + { + SetDataSequence( m_xData, rxSequence ); + // inform listeners of changes + LaunchModifiedEvent( m_aModifyListeners, static_cast< XModifyBroadcaster * >(this) ); + } +} + +uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getLabel( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + return m_xLabels; +} + +void SAL_CALL SwChartLabeledDataSequence::setLabel( + const uno::Reference< chart2::data::XDataSequence >& rxSequence ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + if (m_xLabels != rxSequence) + { + SetDataSequence( m_xLabels, rxSequence ); + // inform listeners of changes + LaunchModifiedEvent( m_aModifyListeners, static_cast< XModifyBroadcaster * >(this) ); + } +} + +uno::Reference< util::XCloneable > SAL_CALL SwChartLabeledDataSequence::createClone( ) +{ + SolarMutexGuard aGuard; + if (m_bDisposed) + throw lang::DisposedException(); + + uno::Reference< util::XCloneable > xDataCloneable( m_xData, uno::UNO_QUERY ); + uno::Reference< util::XCloneable > xLabelsCloneable( m_xLabels, uno::UNO_QUERY ); + rtl::Reference<SwChartLabeledDataSequence > pRes = new SwChartLabeledDataSequence(); + if (xDataCloneable.is()) + { + uno::Reference< chart2::data::XDataSequence > xDataClone( xDataCloneable->createClone(), uno::UNO_QUERY ); + pRes->setValues( xDataClone ); + } + + if (xLabelsCloneable.is()) + { + uno::Reference< chart2::data::XDataSequence > xLabelsClone( xLabelsCloneable->createClone(), uno::UNO_QUERY ); + pRes->setLabel( xLabelsClone ); + } + return pRes; +} + +OUString SAL_CALL SwChartLabeledDataSequence::getImplementationName( ) +{ + return "SwChartLabeledDataSequence"; +} + +sal_Bool SAL_CALL SwChartLabeledDataSequence::supportsService( + const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwChartLabeledDataSequence::getSupportedServiceNames( ) +{ + return { "com.sun.star.chart2.data.LabeledDataSequence" }; +} + +void SAL_CALL SwChartLabeledDataSequence::disposing( + const lang::EventObject& rSource ) +{ + std::unique_lock aGuard( GetChartMutex() ); + uno::Reference< uno::XInterface > xRef( rSource.Source ); + if (xRef == m_xData) + m_xData.clear(); + if (xRef == m_xLabels) + m_xLabels.clear(); + if (!m_xData.is() && !m_xLabels.is()) + { + aGuard.unlock(); + dispose(); + } +} + +void SAL_CALL SwChartLabeledDataSequence::modified( + const lang::EventObject& rEvent ) +{ + if (rEvent.Source == m_xData || rEvent.Source == m_xLabels) + { + LaunchModifiedEvent( m_aModifyListeners, static_cast< XModifyBroadcaster * >(this) ); + } +} + +void SAL_CALL SwChartLabeledDataSequence::addModifyListener( + const uno::Reference< util::XModifyListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aModifyListeners.addInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartLabeledDataSequence::removeModifyListener( + const uno::Reference< util::XModifyListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aModifyListeners.removeInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartLabeledDataSequence::dispose( ) +{ + bool bMustDispose( false ); + { + std::unique_lock aGuard( GetChartMutex() ); + bMustDispose = !m_bDisposed; + if (!m_bDisposed) + m_bDisposed = true; + } + if (bMustDispose) + { + m_bDisposed = true; + + // require listeners to release references to this object + lang::EventObject aEvtObj( static_cast< chart2::data::XLabeledDataSequence * >(this) ); + std::unique_lock aGuard( GetChartMutex() ); + m_aModifyListeners.disposeAndClear( aGuard, aEvtObj ); + m_aEventListeners.disposeAndClear( aGuard, aEvtObj ); + } +} + +void SAL_CALL SwChartLabeledDataSequence::addEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEventListeners.addInterface( aGuard, rxListener ); +} + +void SAL_CALL SwChartLabeledDataSequence::removeEventListener( + const uno::Reference< lang::XEventListener >& rxListener ) +{ + std::unique_lock aGuard( GetChartMutex() ); + if (!m_bDisposed && rxListener.is()) + m_aEventListeners.removeInterface( aGuard, rxListener ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unocoll.cxx b/sw/source/core/unocore/unocoll.cxx new file mode 100644 index 0000000000..d0f3332421 --- /dev/null +++ b/sw/source/core/unocore/unocoll.cxx @@ -0,0 +1,1871 @@ +/* -*- 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 <config_features.h> + +#include <hintids.hxx> +#include <doc.hxx> +#include <IDocumentChartDataProviderAccess.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <docary.hxx> +#include <unocoll.hxx> +#include <unosett.hxx> +#include <section.hxx> +#include <IMark.hxx> +#include <ftnidx.hxx> +#include <fmtftn.hxx> +#include <txtftn.hxx> +#include <com/sun/star/text/XTextTable.hpp> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <svtools/unoimap.hxx> +#include <svtools/unoevent.hxx> +#include <svx/SvxXTextColumns.hxx> +#include <unotbl.hxx> +#include <unostyle.hxx> +#include <unofield.hxx> +#include <unoidx.hxx> +#include <unoframe.hxx> +#include <textboxhelper.hxx> +#include <unofootnote.hxx> +#include <unolinebreak.hxx> +#include <unoport.hxx> +#include <vcl/svapp.hxx> +#include <fmtcntnt.hxx> +#include <authfld.hxx> +#include <SwXTextDefaults.hxx> +#include <unochart.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <unosection.hxx> +#include <unoparagraph.hxx> +#include <unobookmark.hxx> +#include <unorefmark.hxx> +#include <unometa.hxx> +#include <unocontentcontrol.hxx> +#include <docsh.hxx> +#include <hints.hxx> +#include <frameformats.hxx> +#include <com/sun/star/document/XCodeNameQuery.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <vbahelper/vbaaccesshelper.hxx> +#include <basic/basmgr.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase.hxx> +#include <sfx2/event.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +#if HAVE_FEATURE_SCRIPTING + +namespace { + +class SwVbaCodeNameProvider : public ::cppu::WeakImplHelper< document::XCodeNameQuery > +{ + SwDocShell* mpDocShell; + OUString msThisDocumentCodeName; +public: + explicit SwVbaCodeNameProvider( SwDocShell* pDocShell ) : mpDocShell( pDocShell ) {} + // XCodeNameQuery + + OUString SAL_CALL getCodeNameForContainer( const uno::Reference< uno::XInterface >& /*xIf*/ ) override + { + // #FIXME not implemented... + return OUString(); + } + + OUString SAL_CALL getCodeNameForObject( const uno::Reference< uno::XInterface >& xIf ) override + { + // Initialise the code name + if ( msThisDocumentCodeName.isEmpty() ) + { + try + { + uno::Reference< beans::XPropertySet > xProps( mpDocShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xLibContainer( xProps->getPropertyValue("BasicLibraries"), uno::UNO_QUERY_THROW ); + OUString sProjectName( "Standard"); + if ( !mpDocShell->GetBasicManager()->GetName().isEmpty() ) + { + sProjectName = mpDocShell->GetBasicManager()->GetName(); + } + uno::Reference< container::XNameAccess > xLib( xLibContainer->getByName( sProjectName ), uno::UNO_QUERY_THROW ); + const uno::Sequence< OUString > sModuleNames = xLib->getElementNames(); + uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY ); + + auto pModuleName = std::find_if(sModuleNames.begin(), sModuleNames.end(), [&xVBAModuleInfo](const OUString& rName) { + return xVBAModuleInfo->hasModuleInfo(rName) + && xVBAModuleInfo->getModuleInfo(rName).ModuleType == script::ModuleType::DOCUMENT; }); + if (pModuleName != sModuleNames.end()) + msThisDocumentCodeName = *pModuleName; + } + catch( uno::Exception& ) + { + } + } + OUString sCodeName; + if ( mpDocShell ) + { + // need to find the page ( and index ) for this control + uno::Reference< drawing::XDrawPageSupplier > xSupplier( mpDocShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xIndex( xSupplier->getDrawPage(), uno::UNO_QUERY_THROW ); + + try + { + uno::Reference< form::XFormsSupplier > xFormSupplier( xIndex, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexAccess > xFormIndex( xFormSupplier->getForms(), uno::UNO_QUERY_THROW ); + // get the www-standard container + uno::Reference< container::XIndexAccess > xFormControls( xFormIndex->getByIndex(0), uno::UNO_QUERY_THROW ); + sal_Int32 nCntrls = xFormControls->getCount(); + for( sal_Int32 cIndex = 0; cIndex < nCntrls; ++cIndex ) + { + uno::Reference< uno::XInterface > xControl( xFormControls->getByIndex( cIndex ), uno::UNO_QUERY_THROW ); + bool bMatched = ( xControl == xIf ); + if ( bMatched ) + { + sCodeName = msThisDocumentCodeName; + break; + } + } + } + catch( uno::Exception& ) + { + } + } + // #TODO Probably should throw here ( if !bMatched ) + return sCodeName; + } +}; + +} + +typedef std::unordered_map< OUString, OUString > StringHashMap; + +namespace { + +class SwVbaProjectNameProvider : public ::cppu::WeakImplHelper< container::XNameContainer > +{ + StringHashMap mTemplateToProject; +public: + SwVbaProjectNameProvider() + { + } + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + return ( mTemplateToProject.find( aName ) != mTemplateToProject.end() ); + } + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + return uno::Any( mTemplateToProject.find( aName )->second ); + } + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + return comphelper::mapKeysToSequence( mTemplateToProject ); + } + + virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override + { + + OUString sProjectName; + aElement >>= sProjectName; + SAL_INFO("sw.uno", "Template cache inserting template name " << aName + << " with project " << sProjectName); + mTemplateToProject[ aName ] = sProjectName; + } + + virtual void SAL_CALL removeByName( const OUString& Name ) override + { + if ( !hasByName( Name ) ) + throw container::NoSuchElementException(); + mTemplateToProject.erase( Name ); + } + virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override + { + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + insertByName( aName, aElement ); // insert will overwrite + } + // XElemenAccess + virtual css::uno::Type SAL_CALL getElementType( ) override + { + return ::cppu::UnoType<OUString>::get(); + } + virtual sal_Bool SAL_CALL hasElements( ) override + { + + return ( !mTemplateToProject.empty() ); + } + +}; + +class SwVbaObjectForCodeNameProvider : public ::cppu::WeakImplHelper< container::XNameAccess > +{ + SwDocShell* mpDocShell; +public: + explicit SwVbaObjectForCodeNameProvider( SwDocShell* pDocShell ) : mpDocShell( pDocShell ) + { + // #FIXME #TODO is the code name for ThisDocument read anywhere? + } + + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override + { + // #FIXME #TODO we really need to be checking against the codename for + // ThisDocument + if ( aName == "ThisDocument" ) + return true; + return false; + } + + css::uno::Any SAL_CALL getByName( const OUString& aName ) override + { + if ( !hasByName( aName ) ) + throw container::NoSuchElementException(); + uno::Sequence< uno::Any > aArgs{ uno::Any(uno::Reference< uno::XInterface >()), + uno::Any(mpDocShell->GetModel()) }; + uno::Reference< uno::XInterface > xDocObj = ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.word.Document" , aArgs ); + SAL_INFO("sw.uno", + "Creating Object ( ooo.vba.word.Document ) 0x" << xDocObj.get()); + return uno::Any( xDocObj ); + } + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override + { + uno::Sequence< OUString > aNames; + return aNames; + } + // XElemenAccess + virtual css::uno::Type SAL_CALL getElementType( ) override { return uno::Type(); } + virtual sal_Bool SAL_CALL hasElements( ) override { return true; } + +}; + +} + +#endif + +namespace { + +struct ProvNamesId_Type +{ + const char * pName; + SwServiceType nType; +}; + +} + +// note: this thing is indexed as an array, so do not insert/remove entries! +const ProvNamesId_Type aProvNamesId[] = +{ + { "com.sun.star.text.TextTable", SwServiceType::TypeTextTable }, + { "com.sun.star.text.TextFrame", SwServiceType::TypeTextFrame }, + { "com.sun.star.text.GraphicObject", SwServiceType::TypeGraphic }, + { "com.sun.star.text.TextEmbeddedObject", SwServiceType::TypeOLE }, + { "com.sun.star.text.Bookmark", SwServiceType::TypeBookmark }, + { "com.sun.star.text.Footnote", SwServiceType::TypeFootnote }, + { "com.sun.star.text.Endnote", SwServiceType::TypeEndnote }, + { "com.sun.star.text.DocumentIndexMark", SwServiceType::TypeIndexMark }, + { "com.sun.star.text.DocumentIndex", SwServiceType::TypeIndex }, + { "com.sun.star.text.ReferenceMark", SwServiceType::ReferenceMark }, + { "com.sun.star.style.CharacterStyle", SwServiceType::StyleCharacter }, + { "com.sun.star.style.ParagraphStyle", SwServiceType::StyleParagraph }, + { "com.sun.star.style.FrameStyle", SwServiceType::StyleFrame }, + { "com.sun.star.style.PageStyle", SwServiceType::StylePage }, + { "com.sun.star.style.NumberingStyle", SwServiceType::StyleNumbering }, + { "com.sun.star.text.ContentIndexMark", SwServiceType::ContentIndexMark }, + { "com.sun.star.text.ContentIndex", SwServiceType::ContentIndex }, + { "com.sun.star.text.UserIndexMark", SwServiceType::UserIndexMark }, + { "com.sun.star.text.UserIndex", SwServiceType::UserIndex }, + { "com.sun.star.text.TextSection", SwServiceType::TextSection }, + { "com.sun.star.text.TextField.DateTime", SwServiceType::FieldTypeDateTime }, + { "com.sun.star.text.TextField.User", SwServiceType::FieldTypeUser }, + { "com.sun.star.text.TextField.SetExpression", SwServiceType::FieldTypeSetExp }, + { "com.sun.star.text.TextField.GetExpression", SwServiceType::FieldTypeGetExp }, + { "com.sun.star.text.TextField.FileName", SwServiceType::FieldTypeFileName }, + { "com.sun.star.text.TextField.PageNumber", SwServiceType::FieldTypePageNum }, + { "com.sun.star.text.TextField.Author", SwServiceType::FieldTypeAuthor }, + { "com.sun.star.text.TextField.Chapter", SwServiceType::FieldTypeChapter }, + { "", SwServiceType::FieldTypeDummy0 }, + { "com.sun.star.text.TextField.GetReference", SwServiceType::FieldTypeGetReference }, + { "com.sun.star.text.TextField.ConditionalText", SwServiceType::FieldTypeConditionedText }, + { "com.sun.star.text.TextField.Annotation", SwServiceType::FieldTypeAnnotation }, + { "com.sun.star.text.TextField.Input", SwServiceType::FieldTypeInput }, + { "com.sun.star.text.TextField.Macro", SwServiceType::FieldTypeMacro }, + { "com.sun.star.text.TextField.DDE", SwServiceType::FieldTypeDDE }, + { "com.sun.star.text.TextField.HiddenParagraph", SwServiceType::FieldTypeHiddenPara }, + { "" /*com.sun.star.text.TextField.DocumentInfo"*/, SwServiceType::FieldTypeDocInfo }, + { "com.sun.star.text.TextField.TemplateName", SwServiceType::FieldTypeTemplateName }, + { "com.sun.star.text.TextField.ExtendedUser", SwServiceType::FieldTypeUserExt }, + { "com.sun.star.text.TextField.ReferencePageSet", SwServiceType::FieldTypeRefPageSet }, + { "com.sun.star.text.TextField.ReferencePageGet", SwServiceType::FieldTypeRefPageGet }, + { "com.sun.star.text.TextField.JumpEdit", SwServiceType::FieldTypeJumpEdit }, + { "com.sun.star.text.TextField.Script", SwServiceType::FieldTypeScript }, + { "com.sun.star.text.TextField.DatabaseNextSet", SwServiceType::FieldTypeDatabaseNextSet }, + { "com.sun.star.text.TextField.DatabaseNumberOfSet", SwServiceType::FieldTypeDatabaseNumSet }, + { "com.sun.star.text.TextField.DatabaseSetNumber", SwServiceType::FieldTypeDatabaseSetNum }, + { "com.sun.star.text.TextField.Database", SwServiceType::FieldTypeDatabase }, + { "com.sun.star.text.TextField.DatabaseName", SwServiceType::FieldTypeDatabaseName }, + { "com.sun.star.text.TextField.TableFormula", SwServiceType::FieldTypeTableFormula }, + { "com.sun.star.text.TextField.PageCount", SwServiceType::FieldTypePageCount }, + { "com.sun.star.text.TextField.ParagraphCount", SwServiceType::FieldTypeParagraphCount }, + { "com.sun.star.text.TextField.WordCount", SwServiceType::FieldTypeWordCount }, + { "com.sun.star.text.TextField.CharacterCount", SwServiceType::FieldTypeCharacterCount }, + { "com.sun.star.text.TextField.TableCount", SwServiceType::FieldTypeTableCount }, + { "com.sun.star.text.TextField.GraphicObjectCount", SwServiceType::FieldTypeGraphicObjectCount }, + { "com.sun.star.text.TextField.EmbeddedObjectCount", SwServiceType::FieldTypeEmbeddedObjectCount }, + { "com.sun.star.text.TextField.DocInfo.ChangeAuthor", SwServiceType::FieldTypeDocInfoChangeAuthor }, + { "com.sun.star.text.TextField.DocInfo.ChangeDateTime", SwServiceType::FieldTypeDocInfoChangeDateTime }, + { "com.sun.star.text.TextField.DocInfo.EditTime", SwServiceType::FieldTypeDocInfoEditTime }, + { "com.sun.star.text.TextField.DocInfo.Description", SwServiceType::FieldTypeDocInfoDescription }, + { "com.sun.star.text.TextField.DocInfo.CreateAuthor", SwServiceType::FieldTypeDocInfoCreateAuthor }, + { "com.sun.star.text.TextField.DocInfo.CreateDateTime", SwServiceType::FieldTypeDocInfoCreateDateTime }, + { "", SwServiceType::FieldTypeDummy0 }, + { "", SwServiceType::FieldTypeDummy1 }, + { "", SwServiceType::FieldTypeDummy2 }, + { "", SwServiceType::FieldTypeDummy3 }, + { "com.sun.star.text.TextField.DocInfo.Custom", SwServiceType::FieldTypeDocInfoCustom }, + { "com.sun.star.text.TextField.DocInfo.PrintAuthor", SwServiceType::FieldTypeDocInfoPrintAuthor }, + { "com.sun.star.text.TextField.DocInfo.PrintDateTime", SwServiceType::FieldTypeDocInfoPrintDateTime }, + { "com.sun.star.text.TextField.DocInfo.KeyWords", SwServiceType::FieldTypeDocInfoKeywords }, + { "com.sun.star.text.TextField.DocInfo.Subject", SwServiceType::FieldTypeDocInfoSubject }, + { "com.sun.star.text.TextField.DocInfo.Title", SwServiceType::FieldTypeDocInfoTitle }, + { "com.sun.star.text.TextField.DocInfo.Revision", SwServiceType::FieldTypeDocInfoRevision }, + { "com.sun.star.text.TextField.Bibliography", SwServiceType::FieldTypeBibliography }, + { "com.sun.star.text.TextField.CombinedCharacters", SwServiceType::FieldTypeCombinedCharacters }, + { "com.sun.star.text.TextField.DropDown", SwServiceType::FieldTypeDropdown }, + { "com.sun.star.text.textfield.MetadataField", SwServiceType::FieldTypeMetafield }, + { "", SwServiceType::FieldTypeDummy4 }, + { "", SwServiceType::FieldTypeDummy5 }, + { "", SwServiceType::FieldTypeDummy6 }, + { "", SwServiceType::FieldTypeDummy7 }, + { "com.sun.star.text.FieldMaster.User", SwServiceType::FieldMasterUser }, + { "com.sun.star.text.FieldMaster.DDE", SwServiceType::FieldMasterDDE }, + { "com.sun.star.text.FieldMaster.SetExpression", SwServiceType::FieldMasterSetExp }, + { "com.sun.star.text.FieldMaster.Database", SwServiceType::FieldMasterDatabase }, + { "com.sun.star.text.FieldMaster.Bibliography", SwServiceType::FieldMasterBibliography }, + { "", SwServiceType::FieldMasterDummy2 }, + { "", SwServiceType::FieldMasterDummy3 }, + { "", SwServiceType::FieldMasterDummy4 }, + { "", SwServiceType::FieldMasterDummy5 }, + { "com.sun.star.text.IllustrationsIndex", SwServiceType::IndexIllustrations }, + { "com.sun.star.text.ObjectIndex", SwServiceType::IndexObjects }, + { "com.sun.star.text.TableIndex", SwServiceType::IndexTables }, + { "com.sun.star.text.Bibliography", SwServiceType::IndexBibliography }, + { "com.sun.star.text.Paragraph", SwServiceType::Paragraph }, + { "com.sun.star.text.TextField.InputUser", SwServiceType::FieldTypeInputUser }, + { "com.sun.star.text.TextField.HiddenText", SwServiceType::FieldTypeHiddenText }, + { "com.sun.star.style.ConditionalParagraphStyle", SwServiceType::StyleConditionalParagraph }, + { "com.sun.star.text.NumberingRules", SwServiceType::NumberingRules }, + { "com.sun.star.text.TextColumns", SwServiceType::TextColumns }, + { "com.sun.star.text.IndexHeaderSection", SwServiceType::IndexHeaderSection }, + { "com.sun.star.text.Defaults", SwServiceType::Defaults }, + { "com.sun.star.image.ImageMapRectangleObject", SwServiceType::IMapRectangle }, + { "com.sun.star.image.ImageMapCircleObject", SwServiceType::IMapCircle }, + { "com.sun.star.image.ImageMapPolygonObject", SwServiceType::IMapPolygon }, + { "com.sun.star.text.TextGraphicObject", SwServiceType::TypeTextGraphic }, + { "com.sun.star.chart2.data.DataProvider", SwServiceType::Chart2DataProvider }, + { "com.sun.star.text.Fieldmark", SwServiceType::TypeFieldMark }, + { "com.sun.star.text.FormFieldmark", SwServiceType::TypeFormFieldMark }, + { "com.sun.star.text.InContentMetadata", SwServiceType::TypeMeta }, + { "ooo.vba.VBAObjectModuleObjectProvider", SwServiceType::VbaObjectProvider }, + { "ooo.vba.VBACodeNameProvider", SwServiceType::VbaCodeNameProvider }, + { "ooo.vba.VBAProjectNameProvider", SwServiceType::VbaProjectNameProvider }, + { "ooo.vba.VBAGlobals", SwServiceType::VbaGlobals }, + + // case-correct versions of the service names (see #i67811) + { CSS_TEXT_TEXTFIELD_DATE_TIME, SwServiceType::FieldTypeDateTime }, + { CSS_TEXT_TEXTFIELD_USER, SwServiceType::FieldTypeUser }, + { CSS_TEXT_TEXTFIELD_SET_EXPRESSION, SwServiceType::FieldTypeSetExp }, + { CSS_TEXT_TEXTFIELD_GET_EXPRESSION, SwServiceType::FieldTypeGetExp }, + { CSS_TEXT_TEXTFIELD_FILE_NAME, SwServiceType::FieldTypeFileName }, + { CSS_TEXT_TEXTFIELD_PAGE_NUMBER, SwServiceType::FieldTypePageNum }, + { CSS_TEXT_TEXTFIELD_AUTHOR, SwServiceType::FieldTypeAuthor }, + { CSS_TEXT_TEXTFIELD_CHAPTER, SwServiceType::FieldTypeChapter }, + { CSS_TEXT_TEXTFIELD_GET_REFERENCE, SwServiceType::FieldTypeGetReference }, + { CSS_TEXT_TEXTFIELD_CONDITIONAL_TEXT, SwServiceType::FieldTypeConditionedText }, + { CSS_TEXT_TEXTFIELD_ANNOTATION, SwServiceType::FieldTypeAnnotation }, + { CSS_TEXT_TEXTFIELD_INPUT, SwServiceType::FieldTypeInput }, + { CSS_TEXT_TEXTFIELD_MACRO, SwServiceType::FieldTypeMacro }, + { CSS_TEXT_TEXTFIELD_DDE, SwServiceType::FieldTypeDDE }, + { CSS_TEXT_TEXTFIELD_HIDDEN_PARAGRAPH, SwServiceType::FieldTypeHiddenPara }, + { CSS_TEXT_TEXTFIELD_TEMPLATE_NAME, SwServiceType::FieldTypeTemplateName }, + { CSS_TEXT_TEXTFIELD_EXTENDED_USER, SwServiceType::FieldTypeUserExt }, + { CSS_TEXT_TEXTFIELD_REFERENCE_PAGE_SET, SwServiceType::FieldTypeRefPageSet }, + { CSS_TEXT_TEXTFIELD_REFERENCE_PAGE_GET, SwServiceType::FieldTypeRefPageGet }, + { CSS_TEXT_TEXTFIELD_JUMP_EDIT, SwServiceType::FieldTypeJumpEdit }, + { CSS_TEXT_TEXTFIELD_SCRIPT, SwServiceType::FieldTypeScript }, + { CSS_TEXT_TEXTFIELD_DATABASE_NEXT_SET, SwServiceType::FieldTypeDatabaseNextSet }, + { CSS_TEXT_TEXTFIELD_DATABASE_NUMBER_OF_SET, SwServiceType::FieldTypeDatabaseNumSet }, + { CSS_TEXT_TEXTFIELD_DATABASE_SET_NUMBER, SwServiceType::FieldTypeDatabaseSetNum }, + { CSS_TEXT_TEXTFIELD_DATABASE, SwServiceType::FieldTypeDatabase }, + { CSS_TEXT_TEXTFIELD_DATABASE_NAME, SwServiceType::FieldTypeDatabaseName }, + { CSS_TEXT_TEXTFIELD_TABLE_FORMULA, SwServiceType::FieldTypeTableFormula }, + { CSS_TEXT_TEXTFIELD_PAGE_COUNT, SwServiceType::FieldTypePageCount }, + { CSS_TEXT_TEXTFIELD_PARAGRAPH_COUNT, SwServiceType::FieldTypeParagraphCount }, + { CSS_TEXT_TEXTFIELD_WORD_COUNT, SwServiceType::FieldTypeWordCount }, + { CSS_TEXT_TEXTFIELD_CHARACTER_COUNT, SwServiceType::FieldTypeCharacterCount }, + { CSS_TEXT_TEXTFIELD_TABLE_COUNT, SwServiceType::FieldTypeTableCount }, + { CSS_TEXT_TEXTFIELD_GRAPHIC_OBJECT_COUNT, SwServiceType::FieldTypeGraphicObjectCount }, + { CSS_TEXT_TEXTFIELD_EMBEDDED_OBJECT_COUNT, SwServiceType::FieldTypeEmbeddedObjectCount }, + { CSS_TEXT_TEXTFIELD_DOCINFO_CHANGE_AUTHOR, SwServiceType::FieldTypeDocInfoChangeAuthor }, + { CSS_TEXT_TEXTFIELD_DOCINFO_CHANGE_DATE_TIME, SwServiceType::FieldTypeDocInfoChangeDateTime }, + { CSS_TEXT_TEXTFIELD_DOCINFO_EDIT_TIME, SwServiceType::FieldTypeDocInfoEditTime }, + { CSS_TEXT_TEXTFIELD_DOCINFO_DESCRIPTION, SwServiceType::FieldTypeDocInfoDescription }, + { CSS_TEXT_TEXTFIELD_DOCINFO_CREATE_AUTHOR, SwServiceType::FieldTypeDocInfoCreateAuthor }, + { CSS_TEXT_TEXTFIELD_DOCINFO_CREATE_DATE_TIME, SwServiceType::FieldTypeDocInfoCreateDateTime }, + { CSS_TEXT_TEXTFIELD_DOCINFO_PRINT_AUTHOR, SwServiceType::FieldTypeDocInfoPrintAuthor }, + { CSS_TEXT_TEXTFIELD_DOCINFO_PRINT_DATE_TIME, SwServiceType::FieldTypeDocInfoPrintDateTime }, + { CSS_TEXT_TEXTFIELD_DOCINFO_KEY_WORDS, SwServiceType::FieldTypeDocInfoKeywords }, + { CSS_TEXT_TEXTFIELD_DOCINFO_SUBJECT, SwServiceType::FieldTypeDocInfoSubject }, + { CSS_TEXT_TEXTFIELD_DOCINFO_TITLE, SwServiceType::FieldTypeDocInfoTitle }, + { CSS_TEXT_TEXTFIELD_DOCINFO_REVISION, SwServiceType::FieldTypeDocInfoRevision }, + { CSS_TEXT_TEXTFIELD_DOCINFO_CUSTOM, SwServiceType::FieldTypeDocInfoCustom }, + { CSS_TEXT_TEXTFIELD_BIBLIOGRAPHY, SwServiceType::FieldTypeBibliography }, + { CSS_TEXT_TEXTFIELD_COMBINED_CHARACTERS, SwServiceType::FieldTypeCombinedCharacters }, + { CSS_TEXT_TEXTFIELD_DROP_DOWN, SwServiceType::FieldTypeDropdown }, + { CSS_TEXT_TEXTFIELD_INPUT_USER, SwServiceType::FieldTypeInputUser }, + { CSS_TEXT_TEXTFIELD_HIDDEN_TEXT, SwServiceType::FieldTypeHiddenText }, + { CSS_TEXT_FIELDMASTER_USER, SwServiceType::FieldMasterUser }, + { CSS_TEXT_FIELDMASTER_DDE, SwServiceType::FieldMasterDDE }, + { CSS_TEXT_FIELDMASTER_SET_EXPRESSION, SwServiceType::FieldMasterSetExp }, + { CSS_TEXT_FIELDMASTER_DATABASE, SwServiceType::FieldMasterDatabase }, + { CSS_TEXT_FIELDMASTER_BIBLIOGRAPHY, SwServiceType::FieldMasterBibliography }, + { "com.sun.star.style.TableStyle", SwServiceType::StyleTable }, + { "com.sun.star.style.CellStyle", SwServiceType::StyleCell }, + { "com.sun.star.text.LineBreak", SwServiceType::LineBreak }, + { "com.sun.star.text.ContentControl", SwServiceType::ContentControl } +}; + +const SvEventDescription* sw_GetSupportedMacroItems() +{ + static const SvEventDescription aMacroDescriptionsImpl[] = + { + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::NONE, nullptr } + }; + + return aMacroDescriptionsImpl; +} + +OUString SwXServiceProvider::GetProviderName(SwServiceType nObjectType) +{ + OUString sRet; + const sal_uInt16 nEntries = SAL_N_ELEMENTS(aProvNamesId); + if(static_cast<sal_uInt16>(nObjectType) < nEntries) + sRet = OUString::createFromAscii(aProvNamesId[static_cast<sal_uInt16>(nObjectType)].pName); + return sRet; +} + +uno::Sequence<OUString> SwXServiceProvider::GetAllServiceNames() +{ + const sal_uInt16 nEntries = SAL_N_ELEMENTS(aProvNamesId); + uno::Sequence<OUString> aRet(nEntries); + OUString* pArray = aRet.getArray(); + sal_uInt16 n = 0; + for(const ProvNamesId_Type & i : aProvNamesId) + { + OUString sProv(OUString::createFromAscii(i.pName)); + if(!sProv.isEmpty()) + { + pArray[n] = sProv; + n++; + } + } + aRet.realloc(n); + return aRet; + +} + +SwServiceType SwXServiceProvider::GetProviderType(std::u16string_view rServiceName) +{ + for(const ProvNamesId_Type & i : aProvNamesId) + { + if (o3tl::equalsAscii(rServiceName, i.pName)) + return i.nType; + } + return SwServiceType::Invalid; +} + +uno::Reference<uno::XInterface> +SwXServiceProvider::MakeInstance(SwServiceType nObjectType, SwDoc & rDoc) +{ + SolarMutexGuard aGuard; + uno::Reference< uno::XInterface > xRet; + switch(nObjectType) + { + case SwServiceType::TypeTextTable: + { + xRet = getXWeak(SwXTextTable::CreateXTextTable(nullptr).get()); + } + break; + case SwServiceType::TypeTextFrame: + { + xRet = getXWeak(SwXTextFrame::CreateXTextFrame(rDoc, nullptr).get()); + } + break; + case SwServiceType::TypeGraphic : + case SwServiceType::TypeTextGraphic /* #i47503# */ : + { + xRet = getXWeak(SwXTextGraphicObject::CreateXTextGraphicObject(rDoc, nullptr).get()); + + } + break; + case SwServiceType::TypeOLE : + { + xRet = getXWeak(SwXTextEmbeddedObject::CreateXTextEmbeddedObject(rDoc, nullptr).get()); + } + break; + case SwServiceType::TypeBookmark : + { + xRet = getXWeak(SwXBookmark::CreateXBookmark(rDoc, nullptr).get()); + } + break; + case SwServiceType::TypeFieldMark : + { + xRet = getXWeak(SwXFieldmark::CreateXFieldmark(rDoc, nullptr).get()); + } + break; + case SwServiceType::TypeFormFieldMark : + { + xRet = getXWeak(SwXFieldmark::CreateXFieldmark(rDoc, nullptr, true).get()); + } + break; + case SwServiceType::VbaObjectProvider : +#if HAVE_FEATURE_SCRIPTING + { + xRet = getXWeak(new SwVbaObjectForCodeNameProvider(rDoc.GetDocShell())); + } +#endif + break; + case SwServiceType::VbaCodeNameProvider : +#if HAVE_FEATURE_SCRIPTING + { + if (rDoc.GetDocShell() && ooo::vba::isAlienWordDoc(*rDoc.GetDocShell())) + { + xRet = getXWeak(new SwVbaCodeNameProvider(rDoc.GetDocShell())); + } + } +#endif + break; + case SwServiceType::VbaProjectNameProvider : +#if HAVE_FEATURE_SCRIPTING + { + uno::Reference< container::XNameContainer > xProjProv = rDoc.GetVBATemplateToProjectCache(); + if (!xProjProv.is() && rDoc.GetDocShell() + && ooo::vba::isAlienWordDoc(*rDoc.GetDocShell())) + { + xProjProv = new SwVbaProjectNameProvider; + rDoc.SetVBATemplateToProjectCache(xProjProv); + } + xRet = xProjProv; + } +#endif + break; + case SwServiceType::VbaGlobals : +#if HAVE_FEATURE_SCRIPTING + { + uno::Any aGlobs; + BasicManager *pBasicMan = rDoc.GetDocShell()->GetBasicManager(); + if (pBasicMan && !pBasicMan->GetGlobalUNOConstant("VBAGlobals", aGlobs)) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(rDoc.GetDocShell()->GetModel()) }; + aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs ); + pBasicMan->SetGlobalUNOConstant( "VBAGlobals", aGlobs ); + } + aGlobs >>= xRet; + } +#endif + break; + + case SwServiceType::TypeFootnote : + xRet = getXWeak(SwXFootnote::CreateXFootnote(rDoc, nullptr).get()); + break; + case SwServiceType::TypeEndnote : + xRet = getXWeak(SwXFootnote::CreateXFootnote(rDoc, nullptr, true).get()); + break; + case SwServiceType::ContentIndexMark : + case SwServiceType::UserIndexMark : + case SwServiceType::TypeIndexMark: + { + TOXTypes eType = TOX_INDEX; + if(SwServiceType::ContentIndexMark== nObjectType) + eType = TOX_CONTENT; + else if(SwServiceType::UserIndexMark == nObjectType) + eType = TOX_USER; + xRet = getXWeak(SwXDocumentIndexMark::CreateXDocumentIndexMark(rDoc, nullptr, eType).get()); + } + break; + case SwServiceType::ContentIndex : + case SwServiceType::UserIndex : + case SwServiceType::TypeIndex : + case SwServiceType::IndexIllustrations: + case SwServiceType::IndexObjects : + case SwServiceType::IndexTables: + case SwServiceType::IndexBibliography : + { + TOXTypes eType = TOX_INDEX; + if(SwServiceType::ContentIndex == nObjectType) + eType = TOX_CONTENT; + else if(SwServiceType::UserIndex == nObjectType) + eType = TOX_USER; + else if(SwServiceType::IndexIllustrations == nObjectType) + { + eType = TOX_ILLUSTRATIONS; + } + else if(SwServiceType::IndexObjects == nObjectType) + { + eType = TOX_OBJECTS; + } + else if(SwServiceType::IndexBibliography == nObjectType) + { + eType = TOX_AUTHORITIES; + } + else if(SwServiceType::IndexTables == nObjectType) + { + eType = TOX_TABLES; + } + xRet = getXWeak(SwXDocumentIndex::CreateXDocumentIndex(rDoc, nullptr, eType).get()); + } + break; + case SwServiceType::IndexHeaderSection : + case SwServiceType::TextSection : + xRet = getXWeak(SwXTextSection::CreateXTextSection(nullptr, + (SwServiceType::IndexHeaderSection == nObjectType)).get()); + + break; + case SwServiceType::ReferenceMark : + xRet = getXWeak(SwXReferenceMark::CreateXReferenceMark(rDoc, nullptr).get()); + break; + case SwServiceType::StyleCharacter: + case SwServiceType::StyleParagraph: + case SwServiceType::StyleConditionalParagraph: + case SwServiceType::StyleFrame: + case SwServiceType::StylePage: + case SwServiceType::StyleNumbering: + case SwServiceType::StyleTable: + case SwServiceType::StyleCell: + { + SfxStyleFamily eFamily = SfxStyleFamily::Char; + switch(nObjectType) + { + case SwServiceType::StyleParagraph: + eFamily = SfxStyleFamily::Para; + break; + case SwServiceType::StyleConditionalParagraph: + eFamily = SfxStyleFamily::Para; + xRet = SwXStyleFamilies::CreateStyleCondParagraph(rDoc); + break; + case SwServiceType::StyleFrame: + eFamily = SfxStyleFamily::Frame; + break; + case SwServiceType::StylePage: + eFamily = SfxStyleFamily::Page; + break; + case SwServiceType::StyleNumbering: + eFamily = SfxStyleFamily::Pseudo; + break; + case SwServiceType::StyleTable: + eFamily = SfxStyleFamily::Table; + break; + case SwServiceType::StyleCell: + eFamily = SfxStyleFamily::Cell; + break; + default: break; + } + if(!xRet.is()) + xRet = SwXStyleFamilies::CreateStyle(eFamily, rDoc); + } + break; + case SwServiceType::FieldTypeDateTime: + case SwServiceType::FieldTypeUser: + case SwServiceType::FieldTypeSetExp: + case SwServiceType::FieldTypeGetExp: + case SwServiceType::FieldTypeFileName: + case SwServiceType::FieldTypePageNum: + case SwServiceType::FieldTypeAuthor: + case SwServiceType::FieldTypeChapter: + case SwServiceType::FieldTypeGetReference: + case SwServiceType::FieldTypeConditionedText: + case SwServiceType::FieldTypeInput: + case SwServiceType::FieldTypeMacro: + case SwServiceType::FieldTypeDDE: + case SwServiceType::FieldTypeHiddenPara: + case SwServiceType::FieldTypeDocInfo: + case SwServiceType::FieldTypeTemplateName: + case SwServiceType::FieldTypeUserExt: + case SwServiceType::FieldTypeRefPageSet: + case SwServiceType::FieldTypeRefPageGet: + case SwServiceType::FieldTypeJumpEdit: + case SwServiceType::FieldTypeScript: + case SwServiceType::FieldTypeDatabaseNextSet: + case SwServiceType::FieldTypeDatabaseNumSet: + case SwServiceType::FieldTypeDatabaseSetNum: + case SwServiceType::FieldTypeDatabase: + case SwServiceType::FieldTypeDatabaseName: + case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypeParagraphCount: + case SwServiceType::FieldTypeWordCount: + case SwServiceType::FieldTypeCharacterCount: + case SwServiceType::FieldTypeTableCount: + case SwServiceType::FieldTypeGraphicObjectCount: + case SwServiceType::FieldTypeEmbeddedObjectCount: + case SwServiceType::FieldTypeDocInfoChangeAuthor: + case SwServiceType::FieldTypeDocInfoChangeDateTime: + case SwServiceType::FieldTypeDocInfoEditTime: + case SwServiceType::FieldTypeDocInfoDescription: + case SwServiceType::FieldTypeDocInfoCreateAuthor: + case SwServiceType::FieldTypeDocInfoCreateDateTime: + case SwServiceType::FieldTypeDocInfoCustom: + case SwServiceType::FieldTypeDocInfoPrintAuthor: + case SwServiceType::FieldTypeDocInfoPrintDateTime: + case SwServiceType::FieldTypeDocInfoKeywords: + case SwServiceType::FieldTypeDocInfoSubject: + case SwServiceType::FieldTypeDocInfoTitle: + case SwServiceType::FieldTypeDocInfoRevision: + case SwServiceType::FieldTypeBibliography: + case SwServiceType::FieldTypeInputUser: + case SwServiceType::FieldTypeHiddenText: + case SwServiceType::FieldTypeCombinedCharacters: + case SwServiceType::FieldTypeDropdown: + case SwServiceType::FieldTypeTableFormula: + // NOTE: the sw.SwXAutoTextEntry unoapi test depends on pDoc = 0 + xRet = getXWeak(SwXTextField::CreateXTextField(nullptr, nullptr, nObjectType).get()); + break; + case SwServiceType::FieldTypeAnnotation: + xRet = getXWeak(SwXTextField::CreateXTextField(&rDoc, nullptr, nObjectType).get()); + break; + case SwServiceType::FieldMasterUser: + case SwServiceType::FieldMasterDDE: + case SwServiceType::FieldMasterSetExp : + case SwServiceType::FieldMasterDatabase: + { + SwFieldIds nResId = SwFieldIds::Unknown; + switch(nObjectType) + { + case SwServiceType::FieldMasterUser: nResId = SwFieldIds::User; break; + case SwServiceType::FieldMasterDDE: nResId = SwFieldIds::Dde; break; + case SwServiceType::FieldMasterSetExp : nResId = SwFieldIds::SetExp; break; + case SwServiceType::FieldMasterDatabase: nResId = SwFieldIds::Database; break; + default: break; + } + xRet = getXWeak(SwXFieldMaster::CreateXFieldMaster(&rDoc, nullptr, nResId).get()); + } + break; + case SwServiceType::FieldMasterBibliography: + { + SwFieldType* pType = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::TableOfAuthorities, OUString(), true); + if(!pType) + { + SwAuthorityFieldType aType(&rDoc); + pType = rDoc.getIDocumentFieldsAccess().InsertFieldType(aType); + } + xRet = getXWeak(SwXFieldMaster::CreateXFieldMaster(&rDoc, pType).get()); + } + break; + case SwServiceType::Paragraph: + xRet = getXWeak(SwXParagraph::CreateXParagraph(rDoc, nullptr, nullptr).get()); + break; + case SwServiceType::NumberingRules: + xRet = getXWeak(new SwXNumberingRules(rDoc)); + break; + case SwServiceType::TextColumns: + xRet = SvxXTextColumns_createInstance(); + break; + case SwServiceType::Defaults: + xRet = getXWeak(new SwXTextDefaults(&rDoc)); + break; + case SwServiceType::IMapRectangle: + xRet = SvUnoImageMapRectangleObject_createInstance( sw_GetSupportedMacroItems() ); + break; + case SwServiceType::IMapCircle: + xRet = SvUnoImageMapCircleObject_createInstance( sw_GetSupportedMacroItems() ); + break; + case SwServiceType::IMapPolygon: + xRet = SvUnoImageMapPolygonObject_createInstance( sw_GetSupportedMacroItems() ); + break; + case SwServiceType::Chart2DataProvider: + // #i64497# If a chart is in a temporary document during clipboard + // paste, there should be no data provider, so that own data is used + // This should not happen during copy/paste, as this will unlink + // charts using table data. + if (rDoc.GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED) + xRet = getXWeak(rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider( true /* create - if not yet available */ )); + else + SAL_WARN("sw.uno", + "not creating chart data provider for embedded object"); + + break; + case SwServiceType::TypeMeta: + xRet = getXWeak(SwXMeta::CreateXMeta(rDoc, false).get()); + break; + case SwServiceType::FieldTypeMetafield: + xRet = getXWeak(SwXMeta::CreateXMeta(rDoc, true).get()); + break; + case SwServiceType::LineBreak: + xRet = getXWeak(SwXLineBreak::CreateXLineBreak(nullptr).get()); + break; + case SwServiceType::ContentControl: + xRet = getXWeak(SwXContentControl::CreateXContentControl(rDoc).get()); + break; + default: + throw uno::RuntimeException(); + } + return xRet; +} + +//SMART_UNO_IMPLEMENTATION( SwXTextTables, UsrObject ); +SwXTextTables::SwXTextTables(SwDoc* pDc) : + SwUnoCollection(pDc) +{ + +} + +SwXTextTables::~SwXTextTables() +{ + +} + +sal_Int32 SwXTextTables::getCount() +{ + SolarMutexGuard aGuard; + sal_Int32 nRet = 0; + if(IsValid()) + nRet = static_cast<sal_Int32>(GetDoc().GetTableFrameFormatCount(true)); + return nRet; +} + +uno::Any SAL_CALL SwXTextTables::getByIndex(sal_Int32 nInputIndex) +{ + SolarMutexGuard aGuard; + + if (nInputIndex < 0) + throw IndexOutOfBoundsException(); + + size_t nIndex = static_cast<size_t>(nInputIndex); + for(SwTableFormat* pFormat: *GetDoc().GetTableFrameFormats()) + { + if(!pFormat->IsUsed()) + continue; + if(nIndex) + --nIndex; + else + { + uno::Reference<XTextTable> xTable = SwXTextTables::GetObject(*pFormat); + uno::Any aRet; + aRet <<= xTable; + return aRet; + } + } + throw IndexOutOfBoundsException(); +} + +uno::Any SwXTextTables::getByName(const OUString& rItemName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + + const size_t nCount = GetDoc().GetTableFrameFormatCount(true); + uno::Reference< XTextTable > xTable; + for( size_t i = 0; i < nCount; ++i) + { + SwFrameFormat& rFormat = GetDoc().GetTableFrameFormat(i, true); + if (rItemName == rFormat.GetName()) + { + xTable = SwXTextTables::GetObject(rFormat); + aRet <<= xTable; + break; + } + } + if(!xTable.is()) + throw NoSuchElementException(); + + return aRet; +} + +uno::Sequence< OUString > SwXTextTables::getElementNames() +{ + SolarMutexGuard aGuard; + const size_t nCount = GetDoc().GetTableFrameFormatCount(true); + uno::Sequence<OUString> aSeq(static_cast<sal_Int32>(nCount)); + if(nCount) + { + OUString* pArray = aSeq.getArray(); + for( size_t i = 0; i < nCount; ++i) + { + SwFrameFormat& rFormat = GetDoc().GetTableFrameFormat(i, true); + + pArray[i] = rFormat.GetName(); + } + } + return aSeq; +} + +sal_Bool SwXTextTables::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + bool bRet= false; + + const size_t nCount = GetDoc().GetTableFrameFormatCount(true); + for( size_t i = 0; i < nCount; ++i) + { + SwFrameFormat& rFormat = GetDoc().GetTableFrameFormat(i, true); + if (rName == rFormat.GetName()) + { + bRet = true; + break; + } + } + return bRet; +} + +uno::Type SAL_CALL + SwXTextTables::getElementType( ) +{ + return cppu::UnoType<XTextTable>::get(); +} + +sal_Bool SwXTextTables::hasElements() +{ + SolarMutexGuard aGuard; + return 0 != GetDoc().GetTableFrameFormatCount(true); +} + +OUString SwXTextTables::getImplementationName() +{ + return "SwXTextTables"; +} + +sal_Bool SwXTextTables::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextTables::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextTables" }; +} + +uno::Reference<text::XTextTable> SwXTextTables::GetObject(SwFrameFormat& rFormat) +{ + return SwXTextTable::CreateXTextTable(& rFormat); +} + +namespace +{ + template<FlyCntType T> struct UnoFrameWrap_traits {}; + + template<> + struct UnoFrameWrap_traits<FLYCNTTYPE_FRM> + { + static uno::Any wrapFrame(SwFrameFormat & rFrameFormat) + { + uno::Reference<text::XTextFrame> const xRet( + SwXTextFrame::CreateXTextFrame(*rFrameFormat.GetDoc(), &rFrameFormat)); + return uno::Any(xRet); + } + static bool filter(const SwNode* const pNode) { return !pNode->IsNoTextNode(); }; + }; + + template<> + struct UnoFrameWrap_traits<FLYCNTTYPE_GRF> + { + static uno::Any wrapFrame(SwFrameFormat & rFrameFormat) + { + uno::Reference<text::XTextContent> const xRet( + SwXTextGraphicObject::CreateXTextGraphicObject(*rFrameFormat.GetDoc(), &rFrameFormat)); + return uno::Any(xRet); + } + static bool filter(const SwNode* const pNode) { return pNode->IsGrfNode(); }; + }; + + template<> + struct UnoFrameWrap_traits<FLYCNTTYPE_OLE> + { + static uno::Any wrapFrame(SwFrameFormat & rFrameFormat) + { + uno::Reference<text::XTextContent> const xRet( + SwXTextEmbeddedObject::CreateXTextEmbeddedObject(*rFrameFormat.GetDoc(), &rFrameFormat)); + return uno::Any(xRet); + } + static bool filter(const SwNode* const pNode) { return pNode->IsOLENode(); }; + }; + + template<FlyCntType T> + uno::Any lcl_UnoWrapFrame(SwFrameFormat* pFormat) + { + return UnoFrameWrap_traits<T>::wrapFrame(*pFormat); + } + + // runtime adapter for lcl_UnoWrapFrame + /// @throws uno::RuntimeException + uno::Any lcl_UnoWrapFrame(SwFrameFormat* pFormat, FlyCntType eType) + { + switch(eType) + { + case FLYCNTTYPE_FRM: + return lcl_UnoWrapFrame<FLYCNTTYPE_FRM>(pFormat); + case FLYCNTTYPE_GRF: + return lcl_UnoWrapFrame<FLYCNTTYPE_GRF>(pFormat); + case FLYCNTTYPE_OLE: + return lcl_UnoWrapFrame<FLYCNTTYPE_OLE>(pFormat); + default: + throw uno::RuntimeException(); + } + } + + template<FlyCntType T> + class SwXFrameEnumeration + : public SwSimpleEnumeration_Base + { + private: + std::vector< Any > m_aFrames; + protected: + virtual ~SwXFrameEnumeration() override {}; + public: + SwXFrameEnumeration(const SwDoc& rDoc); + + //XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual Any SAL_CALL nextElement() override; + + //XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + }; +} + +template<FlyCntType T> +SwXFrameEnumeration<T>::SwXFrameEnumeration(const SwDoc& rDoc) +{ + SolarMutexGuard aGuard; + for(sw::SpzFrameFormat* pFormat: *rDoc.GetSpzFrameFormats()) + { + // #i104937# + if(pFormat->Which() != RES_FLYFRMFMT || SwTextBoxHelper::isTextBox(pFormat, RES_FLYFRMFMT)) + continue; + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(!pIdx || !pIdx->GetNodes().IsDocNodes()) + continue; + const SwNode* pNd = rDoc.GetNodes()[ pIdx->GetIndex() + 1 ]; + if(UnoFrameWrap_traits<T>::filter(pNd)) + m_aFrames.push_back(lcl_UnoWrapFrame<T>(pFormat)); + } +} + +template<FlyCntType T> +sal_Bool SwXFrameEnumeration<T>::hasMoreElements() +{ + SolarMutexGuard aGuard; + return !m_aFrames.empty(); +} + +template<FlyCntType T> +Any SwXFrameEnumeration<T>::nextElement() +{ + SolarMutexGuard aGuard; + if(m_aFrames.empty()) + throw NoSuchElementException(); + + Any aResult = m_aFrames.back(); + m_aFrames.pop_back(); + return aResult; +} + +template<FlyCntType T> +OUString SwXFrameEnumeration<T>::getImplementationName() +{ + return "SwXFrameEnumeration"; +} + +template<FlyCntType T> +sal_Bool SwXFrameEnumeration<T>::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +template<FlyCntType T> +Sequence< OUString > SwXFrameEnumeration<T>::getSupportedServiceNames() +{ + return { OUString("com.sun.star.container.XEnumeration") }; +} + +OUString SwXFrames::getImplementationName() +{ + return "SwXFrames"; +} + +sal_Bool SwXFrames::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SwXFrames::getSupportedServiceNames() +{ + return { OUString("com.sun.star.text.TextFrames") }; +} + +SwXFrames::SwXFrames(SwDoc* _pDoc, FlyCntType eSet) : + SwUnoCollection(_pDoc), + m_eType(eSet) +{} + +SwXFrames::~SwXFrames() +{} + +uno::Reference<container::XEnumeration> SwXFrames::createEnumeration() +{ + SolarMutexGuard aGuard; + switch(m_eType) + { + case FLYCNTTYPE_FRM: + return uno::Reference< container::XEnumeration >( + new SwXFrameEnumeration<FLYCNTTYPE_FRM>(GetDoc())); + case FLYCNTTYPE_GRF: + return uno::Reference< container::XEnumeration >( + new SwXFrameEnumeration<FLYCNTTYPE_GRF>(GetDoc())); + case FLYCNTTYPE_OLE: + return uno::Reference< container::XEnumeration >( + new SwXFrameEnumeration<FLYCNTTYPE_OLE>(GetDoc())); + default: + throw uno::RuntimeException(); + } +} + +sal_Int32 SwXFrames::getCount() +{ + SolarMutexGuard aGuard; + // Ignore TextBoxes for TextFrames. + return static_cast<sal_Int32>(GetDoc().GetFlyCount(m_eType, /*bIgnoreTextBoxes=*/m_eType == FLYCNTTYPE_FRM)); +} + +uno::Any SwXFrames::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(nIndex < 0) + throw IndexOutOfBoundsException(); + // Ignore TextBoxes for TextFrames. + SwFrameFormat* pFormat = GetDoc().GetFlyNum(static_cast<size_t>(nIndex), m_eType, /*bIgnoreTextBoxes=*/m_eType == FLYCNTTYPE_FRM); + if(!pFormat) + throw IndexOutOfBoundsException(); + return lcl_UnoWrapFrame(pFormat, m_eType); +} + +uno::Any SwXFrames::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + const SwFrameFormat* pFormat; + switch(m_eType) + { + case FLYCNTTYPE_GRF: + pFormat = GetDoc().FindFlyByName(rName, SwNodeType::Grf); + break; + case FLYCNTTYPE_OLE: + pFormat = GetDoc().FindFlyByName(rName, SwNodeType::Ole); + break; + default: + pFormat = GetDoc().FindFlyByName(rName, SwNodeType::Text); + break; + } + if(!pFormat) + throw NoSuchElementException(); + return lcl_UnoWrapFrame(const_cast<SwFrameFormat*>(pFormat), m_eType); +} + +uno::Sequence<OUString> SwXFrames::getElementNames() +{ + SolarMutexGuard aGuard; + const Reference<XEnumeration> xEnum = createEnumeration(); + std::vector<OUString> vNames; + while(xEnum->hasMoreElements()) + { + Reference<container::XNamed> xNamed; + xEnum->nextElement() >>= xNamed; + if(xNamed.is()) + vNames.push_back(xNamed->getName()); + } + return ::comphelper::containerToSequence(vNames); +} + +sal_Bool SwXFrames::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + switch(m_eType) + { + case FLYCNTTYPE_GRF: + return GetDoc().FindFlyByName(rName, SwNodeType::Grf) != nullptr; + case FLYCNTTYPE_OLE: + return GetDoc().FindFlyByName(rName, SwNodeType::Ole) != nullptr; + default: + return GetDoc().FindFlyByName(rName, SwNodeType::Text) != nullptr; + } +} + +uno::Type SAL_CALL SwXFrames::getElementType() +{ + SolarMutexGuard aGuard; + switch(m_eType) + { + case FLYCNTTYPE_FRM: + return cppu::UnoType<XTextFrame>::get(); + case FLYCNTTYPE_GRF: + return cppu::UnoType<XTextContent>::get(); + case FLYCNTTYPE_OLE: + return cppu::UnoType<XEmbeddedObjectSupplier>::get(); + default: + return uno::Type(); + } +} + +sal_Bool SwXFrames::hasElements() +{ + SolarMutexGuard aGuard; + return GetDoc().GetFlyCount(m_eType) > 0; +} + + +OUString SwXTextFrames::getImplementationName() +{ + return "SwXTextFrames"; +} + +sal_Bool SwXTextFrames::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXTextFrames::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextFrames" }; +} + +SwXTextFrames::SwXTextFrames(SwDoc* _pDoc) : + SwXFrames(_pDoc, FLYCNTTYPE_FRM) +{ +} + +SwXTextFrames::~SwXTextFrames() +{ +} + +OUString SwXTextGraphicObjects::getImplementationName() +{ + return "SwXTextGraphicObjects"; +} + +sal_Bool SwXTextGraphicObjects::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXTextGraphicObjects::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextGraphicObjects" }; +} + +SwXTextGraphicObjects::SwXTextGraphicObjects(SwDoc* _pDoc) : + SwXFrames(_pDoc, FLYCNTTYPE_GRF) +{ +} + +SwXTextGraphicObjects::~SwXTextGraphicObjects() +{ +} + +OUString SwXTextEmbeddedObjects::getImplementationName() +{ + return "SwXTextEmbeddedObjects"; +} + +sal_Bool SwXTextEmbeddedObjects::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXTextEmbeddedObjects::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextEmbeddedObjects" }; +} + +SwXTextEmbeddedObjects::SwXTextEmbeddedObjects(SwDoc* _pDoc) : + SwXFrames(_pDoc, FLYCNTTYPE_OLE) +{ +} + +SwXTextEmbeddedObjects::~SwXTextEmbeddedObjects() +{ +} + +OUString SwXTextSections::getImplementationName() +{ + return "SwXTextSections"; +} + +sal_Bool SwXTextSections::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXTextSections::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextSections" }; +} + +SwXTextSections::SwXTextSections(SwDoc* _pDoc) : + SwUnoCollection(_pDoc) +{ +} + +SwXTextSections::~SwXTextSections() +{ +} + +sal_Int32 SwXTextSections::getCount() +{ + SolarMutexGuard aGuard; + const SwSectionFormats& rSectFormats = GetDoc().GetSections(); + size_t nCount = rSectFormats.size(); + for(size_t i = nCount; i; --i) + { + if( !rSectFormats[i - 1]->IsInNodesArr()) + nCount--; + } + return nCount; +} + +uno::Any SwXTextSections::getByIndex(sal_Int32 nIndex) +{ + if (nIndex < 0) + throw IndexOutOfBoundsException(); + size_t nIndex2 = nIndex; + SolarMutexGuard aGuard; + + const SwSectionFormats& rSectFormats = GetDoc().GetSections(); + const size_t nCount = rSectFormats.size(); + for(size_t i = 0; i < nCount; ++i) + { + if( !rSectFormats[i]->IsInNodesArr()) + nIndex2++; + else if (nIndex2 == i) + return Any(GetObject(*rSectFormats[i])); + } + throw IndexOutOfBoundsException(); +} + +uno::Any SwXTextSections::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + + SwSectionFormats& rFormats = GetDoc().GetSections(); + uno::Reference< XTextSection > xSect; + for(size_t i = 0; i < rFormats.size(); ++i) + { + SwSectionFormat* pFormat = rFormats[i]; + if (pFormat->IsInNodesArr() + && (rName == pFormat->GetSection()->GetSectionName())) + { + xSect = GetObject(*pFormat); + aRet <<= xSect; + break; + } + } + if(!xSect.is()) + throw NoSuchElementException(); + + return aRet; +} + +uno::Sequence< OUString > SwXTextSections::getElementNames() +{ + SolarMutexGuard aGuard; + SwSectionFormats& rSectFormats = GetDoc().GetSections(); + size_t nCount = rSectFormats.size(); + for(size_t i = nCount; i; --i) + { + if( !rSectFormats[i - 1]->IsInNodesArr()) + nCount--; + } + + uno::Sequence<OUString> aSeq(nCount); + if(nCount) + { + OUString* pArray = aSeq.getArray(); + size_t nIndex = 0; + for( size_t i = 0; i < nCount; ++i, ++nIndex) + { + const SwSectionFormat* pFormat = rSectFormats[nIndex]; + while(!pFormat->IsInNodesArr()) + { + pFormat = rSectFormats[++nIndex]; + } + pArray[i] = pFormat->GetSection()->GetSectionName(); + } + } + return aSeq; +} + +sal_Bool SwXTextSections::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + bool bRet = false; + if(IsValid()) + { + SwSectionFormats& rFormats = GetDoc().GetSections(); + for(size_t i = 0; i < rFormats.size(); ++i) + { + const SwSectionFormat* pFormat = rFormats[i]; + if (rName == pFormat->GetSection()->GetSectionName()) + { + bRet = true; + break; + } + } + } + else + { + // special handling for dbg_ methods + if( !rName.startsWith("dbg_")) + throw uno::RuntimeException(); + } + return bRet; +} + +uno::Type SAL_CALL SwXTextSections::getElementType() +{ + return cppu::UnoType<XTextSection>::get(); +} + +sal_Bool SwXTextSections::hasElements() +{ + SolarMutexGuard aGuard; + size_t nCount = 0; + + SwSectionFormats& rFormats = GetDoc().GetSections(); + nCount = rFormats.size(); + + return nCount > 0; +} + +uno::Reference< XTextSection > SwXTextSections::GetObject( SwSectionFormat& rFormat ) +{ + return SwXTextSection::CreateXTextSection(&rFormat); +} + +OUString SwXBookmarks::getImplementationName() +{ + return "SwXBookmarks"; +} + +sal_Bool SwXBookmarks::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXBookmarks::getSupportedServiceNames() +{ + return { "com.sun.star.text.Bookmarks" }; +} + +SwXBookmarks::SwXBookmarks(SwDoc* _pDoc) : + SwUnoCollection(_pDoc) +{ } + +SwXBookmarks::~SwXBookmarks() +{ } + +sal_Int32 SwXBookmarks::getCount() +{ + SolarMutexGuard aGuard; + + sal_Int32 count(0); + IDocumentMarkAccess* const pMarkAccess = GetDoc().getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppMark = + pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); ++ppMark) + { + if (IDocumentMarkAccess::MarkType::BOOKMARK == + IDocumentMarkAccess::GetType(**ppMark)) + { + ++count; // only count real bookmarks + } + } + return count; +} + +uno::Any SwXBookmarks::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + auto& rDoc = GetDoc(); + IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); + if(nIndex < 0 || nIndex >= pMarkAccess->getBookmarksCount()) + throw IndexOutOfBoundsException(); + + sal_Int32 count(0); + for (IDocumentMarkAccess::const_iterator_t ppMark = + pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); ++ppMark) + { + if (IDocumentMarkAccess::MarkType::BOOKMARK == + IDocumentMarkAccess::GetType(**ppMark)) + { + if (count == nIndex) + { + uno::Any aRet; + const uno::Reference< text::XTextContent > xRef = + SwXBookmark::CreateXBookmark(rDoc, *ppMark); + aRet <<= xRef; + return aRet; + } + ++count; // only count real bookmarks + } + } + throw IndexOutOfBoundsException(); +} + +uno::Any SwXBookmarks::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + auto& rDoc = GetDoc(); + IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); + IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark(rName); + if(ppBkmk == pMarkAccess->getBookmarksEnd()) + throw NoSuchElementException(); + + uno::Any aRet; + const uno::Reference< text::XTextContent > xRef = + SwXBookmark::CreateXBookmark(rDoc, *ppBkmk); + aRet <<= xRef; + return aRet; +} + +uno::Sequence< OUString > SwXBookmarks::getElementNames() +{ + SolarMutexGuard aGuard; + + std::vector< OUString > ret; + IDocumentMarkAccess* const pMarkAccess = GetDoc().getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppMark = + pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); ++ppMark) + { + if (IDocumentMarkAccess::MarkType::BOOKMARK == + IDocumentMarkAccess::GetType(**ppMark)) + { + ret.push_back((*ppMark)->GetName()); // only add real bookmarks + } + } + return comphelper::containerToSequence(ret); +} + +sal_Bool SwXBookmarks::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + IDocumentMarkAccess* const pMarkAccess = GetDoc().getIDocumentMarkAccess(); + return pMarkAccess->findBookmark(rName) != pMarkAccess->getBookmarksEnd(); +} + +uno::Type SAL_CALL SwXBookmarks::getElementType() +{ + return cppu::UnoType<XTextContent>::get(); +} + +sal_Bool SwXBookmarks::hasElements() +{ + SolarMutexGuard aGuard; + + IDocumentMarkAccess* const pMarkAccess = GetDoc().getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppMark = + pMarkAccess->getBookmarksBegin(); + ppMark != pMarkAccess->getBookmarksEnd(); ++ppMark) + { + if (IDocumentMarkAccess::MarkType::BOOKMARK == + IDocumentMarkAccess::GetType(**ppMark)) + { + return true; + } + } + return false; +} + +SwXNumberingRulesCollection::SwXNumberingRulesCollection( SwDoc* _pDoc ) : + SwUnoCollection(_pDoc) +{ +} + +SwXNumberingRulesCollection::~SwXNumberingRulesCollection() +{ +} + +sal_Int32 SwXNumberingRulesCollection::getCount() +{ + SolarMutexGuard aGuard; + return GetDoc().GetNumRuleTable().size(); +} + +uno::Any SwXNumberingRulesCollection::getByIndex(sal_Int32 nIndex) +{ + if (nIndex < 0) + throw IndexOutOfBoundsException(); + + SolarMutexGuard aGuard; + + if (SwDoc& rDoc = GetDoc(); o3tl::make_unsigned(nIndex) < rDoc.GetNumRuleTable().size()) + { + uno::Reference<XIndexReplace> xRef( + new SwXNumberingRules(*rDoc.GetNumRuleTable()[nIndex], &rDoc)); + return uno::Any(xRef); + } + + throw IndexOutOfBoundsException(); +} + +uno::Type SAL_CALL SwXNumberingRulesCollection::getElementType() +{ + return cppu::UnoType<XIndexReplace>::get(); +} + +sal_Bool SwXNumberingRulesCollection::hasElements() +{ + SolarMutexGuard aGuard; + return !GetDoc().GetNumRuleTable().empty(); +} + +OUString SwXFootnotes::getImplementationName() +{ + return "SwXFootnotes"; +} + +sal_Bool SwXFootnotes::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXFootnotes::getSupportedServiceNames() +{ + return { "com.sun.star.text.Footnotes" }; +} + +SwXFootnotes::SwXFootnotes(bool bEnd, SwDoc* _pDoc) + : SwUnoCollection(_pDoc) + , m_bEndnote(bEnd) +{ +} + +SwXFootnotes::~SwXFootnotes() +{ +} + +sal_Int32 SwXFootnotes::getCount() +{ + SolarMutexGuard aGuard; + sal_Int32 nCount = 0; + auto& rIdxs = GetDoc().GetFootnoteIdxs(); + const size_t nFootnoteCnt = rIdxs.size(); + SwTextFootnote* pTextFootnote; + for( size_t n = 0; n < nFootnoteCnt; ++n ) + { + pTextFootnote = rIdxs[n]; + const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); + if ( rFootnote.IsEndNote() != m_bEndnote ) + continue; + nCount++; + } + return nCount; +} + +uno::Any SwXFootnotes::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + sal_Int32 nCount = 0; + + auto& rDoc = GetDoc(); + auto& rIdxs = rDoc.GetFootnoteIdxs(); + const size_t nFootnoteCnt = rIdxs.size(); + SwTextFootnote* pTextFootnote; + uno::Reference< XFootnote > xRef; + for( size_t n = 0; n < nFootnoteCnt; ++n ) + { + pTextFootnote = rIdxs[n]; + const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); + if ( rFootnote.IsEndNote() != m_bEndnote ) + continue; + + if(nCount == nIndex) + { + xRef = SwXFootnote::CreateXFootnote(rDoc, + &const_cast<SwFormatFootnote&>(rFootnote)); + aRet <<= xRef; + break; + } + nCount++; + } + if(!xRef.is()) + throw IndexOutOfBoundsException(); + + return aRet; +} + +uno::Type SAL_CALL SwXFootnotes::getElementType() +{ + return cppu::UnoType<XFootnote>::get(); +} + +sal_Bool SwXFootnotes::hasElements() +{ + SolarMutexGuard aGuard; + return !GetDoc().GetFootnoteIdxs().empty(); +} + +Reference<XFootnote> SwXFootnotes::GetObject( SwDoc& rDoc, const SwFormatFootnote& rFormat ) +{ + return SwXFootnote::CreateXFootnote(rDoc, &const_cast<SwFormatFootnote&>(rFormat)); +} + +OUString SwXReferenceMarks::getImplementationName() +{ + return "SwXReferenceMarks"; +} + +sal_Bool SwXReferenceMarks::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXReferenceMarks::getSupportedServiceNames() +{ + return { "com.sun.star.text.ReferenceMarks" }; +} + +SwXReferenceMarks::SwXReferenceMarks(SwDoc* _pDoc) : + SwUnoCollection(_pDoc) +{ +} + +SwXReferenceMarks::~SwXReferenceMarks() +{ +} + +sal_Int32 SwXReferenceMarks::getCount() +{ + SolarMutexGuard aGuard; + return GetDoc().GetRefMarks(); +} + +uno::Any SwXReferenceMarks::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + uno::Reference< XTextContent > xRef; + if(0 <= nIndex && nIndex < SAL_MAX_UINT16) + { + auto& rDoc = GetDoc(); + SwFormatRefMark *const pMark = const_cast<SwFormatRefMark*>( + rDoc.GetRefMark(o3tl::narrowing<sal_uInt16>(nIndex))); + if(pMark) + { + xRef = SwXReferenceMark::CreateXReferenceMark(rDoc, pMark); + aRet <<= xRef; + } + } + if(!xRef.is()) + throw IndexOutOfBoundsException(); + return aRet; +} + +uno::Any SwXReferenceMarks::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + + auto& rDoc = GetDoc(); + SwFormatRefMark *const pMark = + const_cast<SwFormatRefMark*>(rDoc.GetRefMark(rName)); + if(!pMark) + throw NoSuchElementException(); + + uno::Reference<XTextContent> const xRef = + SwXReferenceMark::CreateXReferenceMark(rDoc, pMark); + aRet <<= xRef; + + return aRet; +} + +uno::Sequence< OUString > SwXReferenceMarks::getElementNames() +{ + SolarMutexGuard aGuard; + uno::Sequence<OUString> aRet; + + std::vector<OUString> aStrings; + const sal_uInt16 nCount = GetDoc().GetRefMarks(&aStrings); + aRet.realloc(nCount); + OUString* pNames = aRet.getArray(); + for(sal_uInt16 i = 0; i < nCount; i++) + pNames[i] = aStrings[i]; + + return aRet; +} + +sal_Bool SwXReferenceMarks::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + return nullptr != GetDoc().GetRefMark( rName); +} + +uno::Type SAL_CALL SwXReferenceMarks::getElementType() +{ + return cppu::UnoType<XTextContent>::get(); +} + +sal_Bool SwXReferenceMarks::hasElements() +{ + SolarMutexGuard aGuard; + return 0 != GetDoc().GetRefMarks(); +} + +SwDoc& SwUnoCollection::GetDoc() const +{ + DBG_TESTSOLARMUTEX(); + if (!m_pDoc) + throw uno::RuntimeException(); + return *m_pDoc; +} + +void SwUnoCollection::Invalidate() +{ + SolarMutexGuard aGuard; + m_pDoc = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx new file mode 100644 index 0000000000..5d54d60e9b --- /dev/null +++ b/sw/source/core/unocore/unocontentcontrol.cxx @@ -0,0 +1,1458 @@ +/* -*- 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 <unocontentcontrol.hxx> + +#include <mutex> + +#include <com/sun/star/text/XWordCursor.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <formatcontentcontrol.hxx> +#include <ndtxt.hxx> +#include <textcontentcontrol.hxx> +#include <unotext.hxx> +#include <unotextcursor.hxx> +#include <unotextrange.hxx> +#include <doc.hxx> +#include <unoport.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <utility> + +using namespace com::sun::star; + +namespace +{ +/// UNO API wrapper around the text inside an SwXContentControl. +class SwXContentControlText : public cppu::OWeakObject, public SwXText +{ +private: + SwXContentControl& m_rContentControl; + + void PrepareForAttach(uno::Reference<text::XTextRange>& xRange, const SwPaM& rPam) override; + +protected: + const SwStartNode* GetStartNode() const override; + +public: + SwXContentControlText(SwDoc& rDoc, SwXContentControl& rContentControl); + + /// SwXText::Invalidate() is protected. + using SwXText::Invalidate; + + // XInterface + void SAL_CALL acquire() noexcept override { cppu::OWeakObject::acquire(); } + void SAL_CALL release() noexcept override { cppu::OWeakObject::release(); } + + // XTypeProvider + uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + + // XText + virtual rtl::Reference<SwXTextCursor> createXTextCursor() override; + virtual rtl::Reference<SwXTextCursor> createXTextCursorByRange( + const ::css::uno::Reference<::css::text::XTextRange>& aTextPosition) override; +}; +} + +SwXContentControlText::SwXContentControlText(SwDoc& rDoc, SwXContentControl& rContentControl) + : SwXText(&rDoc, CursorType::ContentControl) + , m_rContentControl(rContentControl) +{ +} + +const SwStartNode* SwXContentControlText::GetStartNode() const +{ + SwXText* pParent = m_rContentControl.GetParentText().get(); + return pParent ? pParent->GetStartNode() : nullptr; +} + +void SwXContentControlText::PrepareForAttach(uno::Reference<text::XTextRange>& xRange, + const SwPaM& rPam) +{ + // Create a new cursor to prevent modifying SwXTextRange. + xRange = static_cast<text::XWordCursor*>( + new SwXTextCursor(*GetDoc(), &m_rContentControl, CursorType::ContentControl, + *rPam.GetPoint(), (rPam.HasMark()) ? rPam.GetMark() : nullptr)); +} + +rtl::Reference<SwXTextCursor> SwXContentControlText::createXTextCursor() +{ + rtl::Reference<SwXTextCursor> xRet; + if (IsValid()) + { + SwTextNode* pTextNode; + sal_Int32 nContentControlStart; + sal_Int32 nContentControlEnd; + bool bSuccess = m_rContentControl.SetContentRange(pTextNode, nContentControlStart, + nContentControlEnd); + if (bSuccess) + { + SwPosition aPos(*pTextNode, nContentControlStart); + xRet = new SwXTextCursor(*GetDoc(), &m_rContentControl, CursorType::ContentControl, + aPos); + } + } + return xRet; +} + +uno::Sequence<sal_Int8> SAL_CALL SwXContentControlText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XText + +rtl::Reference<SwXTextCursor> SwXContentControlText::createXTextCursorByRange( + const uno::Reference<text::XTextRange>& xTextPosition) +{ + const rtl::Reference<SwXTextCursor> xCursor(createXTextCursor()); + xCursor->gotoRange(xTextPosition, false); + return xCursor; +} + +/** + * The inner part SwXContentControl, which is deleted with a locked SolarMutex. + * + * The content control has a cached list of text portions for its contents. This list is created by + * SwXTextPortionEnumeration. The content control listens at the SwTextNode and throws away the + * cache when the text node changes. + */ +class SwXContentControl::Impl : public SvtListener +{ +public: + unotools::WeakReference<SwXContentControl> m_wThis; + // Just for OInterfaceContainerHelper4. + std::mutex m_Mutex; + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + std::unique_ptr<const TextRangeList_t> m_pTextPortions; + // 3 possible states: not attached, attached, disposed + bool m_bIsDisposed; + bool m_bIsDescriptor; + css::uno::Reference<SwXText> m_xParentText; + rtl::Reference<SwXContentControlText> m_xText; + SwContentControl* m_pContentControl; + bool m_bShowingPlaceHolder; + bool m_bCheckbox; + bool m_bChecked; + OUString m_aCheckedState; + OUString m_aUncheckedState; + std::vector<SwContentControlListItem> m_aListItems; + bool m_bPicture; + bool m_bDate; + OUString m_aDateFormat; + OUString m_aDateLanguage; + OUString m_aCurrentDate; + bool m_bPlainText; + bool m_bComboBox; + bool m_bDropDown; + OUString m_aPlaceholderDocPart; + OUString m_aDataBindingPrefixMappings; + OUString m_aDataBindingXpath; + OUString m_aDataBindingStoreItemID; + OUString m_aColor; + OUString m_aAppearance; + OUString m_aAlias; + OUString m_aTag; + sal_Int32 m_nId; + sal_uInt32 m_nTabIndex; + OUString m_aLock; + OUString m_aMultiLine; + + Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl, + css::uno::Reference<SwXText> xParentText, std::unique_ptr<const TextRangeList_t> pPortions) + : m_pTextPortions(std::move(pPortions)) + , m_bIsDisposed(false) + , m_bIsDescriptor(pContentControl == nullptr) + , m_xParentText(std::move(xParentText)) + , m_xText(new SwXContentControlText(rDoc, rThis)) + , m_pContentControl(pContentControl) + , m_bShowingPlaceHolder(false) + , m_bCheckbox(false) + , m_bChecked(false) + , m_bPicture(false) + , m_bDate(false) + , m_bPlainText(false) + , m_bComboBox(false) + , m_bDropDown(false) + , m_nId(0) + , m_nTabIndex(0) + { + if (m_pContentControl) + { + StartListening(m_pContentControl->GetNotifier()); + } + } + + const SwContentControl* GetContentControl() const; + +protected: + void Notify(const SfxHint& rHint) override; +}; + +const SwContentControl* SwXContentControl::Impl::GetContentControl() const +{ + return m_pContentControl; +} + +// sw::BroadcastingModify +void SwXContentControl::Impl::Notify(const SfxHint& rHint) +{ + // throw away cache (SwTextNode changed) + m_pTextPortions.reset(); + + if (rHint.GetId() != SfxHintId::Dying && rHint.GetId() != SfxHintId::Deinitializing) + return; + + m_bIsDisposed = true; + m_pContentControl = nullptr; + m_xText->Invalidate(); + uno::Reference<uno::XInterface> xThis(m_wThis); + if (!xThis.is()) + { + // If UNO object is already dead, don't refer to it in an event. + return; + } + lang::EventObject aEvent(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, aEvent); +} + +const css::uno::Reference<SwXText>& SwXContentControl::GetParentText() const +{ + return m_pImpl->m_xParentText; +} + +SwXContentControl::SwXContentControl(SwDoc* pDoc, SwContentControl* pContentControl, + const css::uno::Reference<SwXText>& xParentText, + std::unique_ptr<const TextRangeList_t> pPortions) + : m_pImpl(new SwXContentControl::Impl(*this, *pDoc, pContentControl, xParentText, + std::move(pPortions))) +{ +} + +SwXContentControl::SwXContentControl(SwDoc* pDoc) + : m_pImpl(new SwXContentControl::Impl(*this, *pDoc, nullptr, nullptr, nullptr)) +{ +} + +SwXContentControl::~SwXContentControl() {} + +rtl::Reference<SwXContentControl> SwXContentControl::CreateXContentControl(SwDoc& rDoc) +{ + rtl::Reference<SwXContentControl> xContentControl(new SwXContentControl(&rDoc)); + xContentControl->m_pImpl->m_wThis = xContentControl.get(); + return xContentControl; +} + +rtl::Reference<SwXContentControl> +SwXContentControl::CreateXContentControl(SwContentControl& rContentControl, + const css::uno::Reference<SwXText>& xParent, + std::unique_ptr<const TextRangeList_t>&& pPortions) +{ + // re-use existing SwXContentControl + rtl::Reference<SwXContentControl> xContentControl(rContentControl.GetXContentControl()); + if (xContentControl.is()) + { + if (pPortions) + { + // The content control must always be created with the complete content. If + // SwXTextPortionEnumeration is created for a selection, it must be checked that the + // content control is contained in the selection. + xContentControl->m_pImpl->m_pTextPortions = std::move(pPortions); + if (xContentControl->m_pImpl->m_xParentText.get() != xParent.get()) + { + SAL_WARN("sw.uno", "SwXContentControl with different parent"); + xContentControl->m_pImpl->m_xParentText = xParent; + } + } + return xContentControl; + } + + // Create new SwXContentControl. + SwTextNode* pTextNode = rContentControl.GetTextNode(); + if (!pTextNode) + { + SAL_WARN("sw.uno", "CreateXContentControl: no text node"); + return nullptr; + } + css::uno::Reference<SwXText> xParentText(xParent); + if (!xParentText.is()) + { + SwTextContentControl* pTextAttr = rContentControl.GetTextAttr(); + if (!pTextAttr) + { + SAL_WARN("sw.uno", "CreateXContentControl: no text attr"); + return nullptr; + } + SwPosition aPos(*pTextNode, pTextAttr->GetStart()); + xParentText = sw::CreateParentXText(pTextNode->GetDoc(), aPos); + } + if (!xParentText.is()) + { + return nullptr; + } + xContentControl = new SwXContentControl(&pTextNode->GetDoc(), &rContentControl, xParentText, + std::move(pPortions)); + rContentControl.SetXContentControl(xContentControl); + xContentControl->m_pImpl->m_wThis = xContentControl.get(); + return xContentControl; +} + +bool SwXContentControl::SetContentRange(SwTextNode*& rpNode, sal_Int32& rStart, + sal_Int32& rEnd) const +{ + const SwContentControl* pContentControl = m_pImpl->GetContentControl(); + if (pContentControl) + { + const SwTextContentControl* pTextAttr = pContentControl->GetTextAttr(); + if (pTextAttr) + { + rpNode = pContentControl->GetTextNode(); + if (rpNode) + { + // rStart points at the first position within the content control. + rStart = pTextAttr->GetStart() + 1; + // rEnd points at the last position within the content control. + rEnd = *pTextAttr->End() - 1; + return true; + } + } + } + return false; +} + +// XServiceInfo +OUString SAL_CALL SwXContentControl::getImplementationName() { return "SwXContentControl"; } + +sal_Bool SAL_CALL SwXContentControl::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL SwXContentControl::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextContent", "com.sun.star.text.ContentControl" }; +} + +// XComponent +void SAL_CALL +SwXContentControl::addEventListener(const uno::Reference<lang::XEventListener>& xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL +SwXContentControl::removeEventListener(const uno::Reference<lang::XEventListener>& xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +void SAL_CALL SwXContentControl::dispose() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pTextPortions.reset(); + lang::EventObject aEvent(getXWeak()); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard, aEvent); + m_pImpl->m_bIsDisposed = true; + m_pImpl->m_xText->Invalidate(); + } + else if (!m_pImpl->m_bIsDisposed) + { + SwTextNode* pTextNode; + sal_Int32 nContentControlStart; + sal_Int32 nContentControlEnd; + bool bSuccess = SetContentRange(pTextNode, nContentControlStart, nContentControlEnd); + if (!bSuccess) + { + SAL_WARN("sw.core", "SwXContentControl::dispose: no pam"); + } + else + { + // -1 because of CH_TXTATR + SwPaM aPam(*pTextNode, nContentControlStart - 1, *pTextNode, nContentControlEnd); + SwDoc& rDoc(pTextNode->GetDoc()); + rDoc.getIDocumentContentOperations().DeleteAndJoin(aPam); + + // removal should call Modify and do the dispose + assert(m_pImpl->m_bIsDisposed); + } + } +} + +void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xTextRange, + sal_uInt16 nWhich) +{ + SolarMutexGuard aGuard; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException("SwXContentControl::AttachImpl(): already attached", + getXWeak()); + } + + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor + = pRange ? nullptr : dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + if (!pRange && !pCursor) + { + throw lang::IllegalArgumentException( + "SwXContentControl::AttachImpl(): argument not supported type", getXWeak(), 0); + } + + SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor->GetDoc(); + if (!pDoc) + { + throw lang::IllegalArgumentException( + "SwXContentControl::AttachImpl(): argument has no SwDoc", getXWeak(), 0); + } + + SwUnoInternalPaM aPam(*pDoc); + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + + UnoActionContext aContext(pDoc); + + auto pTextCursor = dynamic_cast<SwXTextCursor*>(pCursor); + bool bForceExpandHints = pTextCursor && pTextCursor->IsAtEndOfContentControl(); + SetAttrMode nInsertFlags = bForceExpandHints + ? (SetAttrMode::FORCEHINTEXPAND | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND; + + auto pContentControl = std::make_shared<SwContentControl>(nullptr); + + pContentControl->SetShowingPlaceHolder(m_pImpl->m_bShowingPlaceHolder); + pContentControl->SetCheckbox(m_pImpl->m_bCheckbox); + pContentControl->SetChecked(m_pImpl->m_bChecked); + pContentControl->SetCheckedState(m_pImpl->m_aCheckedState); + pContentControl->SetUncheckedState(m_pImpl->m_aUncheckedState); + pContentControl->SetListItems(m_pImpl->m_aListItems); + pContentControl->SetPicture(m_pImpl->m_bPicture); + pContentControl->SetDate(m_pImpl->m_bDate); + pContentControl->SetDateFormat(m_pImpl->m_aDateFormat); + pContentControl->SetDateLanguage(m_pImpl->m_aDateLanguage); + pContentControl->SetCurrentDate(m_pImpl->m_aCurrentDate); + pContentControl->SetPlainText(m_pImpl->m_bPlainText); + pContentControl->SetComboBox(m_pImpl->m_bComboBox); + pContentControl->SetDropDown(m_pImpl->m_bDropDown); + pContentControl->SetPlaceholderDocPart(m_pImpl->m_aPlaceholderDocPart); + pContentControl->SetDataBindingPrefixMappings(m_pImpl->m_aDataBindingPrefixMappings); + pContentControl->SetDataBindingXpath(m_pImpl->m_aDataBindingXpath); + pContentControl->SetDataBindingStoreItemID(m_pImpl->m_aDataBindingStoreItemID); + pContentControl->SetColor(m_pImpl->m_aColor); + pContentControl->SetAppearance(m_pImpl->m_aAppearance); + pContentControl->SetAlias(m_pImpl->m_aAlias); + pContentControl->SetTag(m_pImpl->m_aTag); + pContentControl->SetId(m_pImpl->m_nId); + pContentControl->SetTabIndex(m_pImpl->m_nTabIndex); + pContentControl->SetLock(m_pImpl->m_aLock); + pContentControl->SetMultiLine(m_pImpl->m_aMultiLine); + + SwFormatContentControl aContentControl(pContentControl, nWhich); + bool bSuccess + = pDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aContentControl, nInsertFlags); + SwTextAttr* pTextAttr = pContentControl->GetTextAttr(); + if (!bSuccess) + { + throw lang::IllegalArgumentException( + "SwXContentControl::AttachImpl(): cannot create content control: invalid range", + getXWeak(), 1); + } + if (!pTextAttr) + { + SAL_WARN("sw.core", "content control inserted, but has no text attribute?"); + throw uno::RuntimeException( + "SwXContentControl::AttachImpl(): cannot create content control", getXWeak()); + } + + m_pImpl->EndListeningAll(); + m_pImpl->m_pContentControl = pContentControl.get(); + m_pImpl->StartListening(pContentControl->GetNotifier()); + pContentControl->SetXContentControl(this); + + m_pImpl->m_xParentText = sw::CreateParentXText(*pDoc, *aPam.GetPoint()); + + m_pImpl->m_bIsDescriptor = false; +} + +// XTextContent +void SAL_CALL SwXContentControl::attach(const uno::Reference<text::XTextRange>& xTextRange) +{ + return SwXContentControl::AttachImpl(xTextRange, RES_TXTATR_CONTENTCONTROL); +} + +uno::Reference<text::XTextRange> SAL_CALL SwXContentControl::getAnchor() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException("SwXContentControl::getAnchor(): not inserted", getXWeak()); + } + + SwTextNode* pTextNode; + sal_Int32 nContentControlStart; + sal_Int32 nContentControlEnd; + bool bSuccess = SetContentRange(pTextNode, nContentControlStart, nContentControlEnd); + if (!bSuccess) + { + SAL_WARN("sw.core", "no pam"); + throw lang::DisposedException("SwXContentControl::getAnchor(): not attached", getXWeak()); + } + + SwPosition aStart(*pTextNode, nContentControlStart - 1); // -1 due to CH_TXTATR + SwPosition aEnd(*pTextNode, nContentControlEnd); + return SwXTextRange::CreateXTextRange(pTextNode->GetDoc(), aStart, &aEnd); +} + +// XTextRange +uno::Reference<text::XText> SAL_CALL SwXContentControl::getText() { return this; } + +uno::Reference<text::XTextRange> SAL_CALL SwXContentControl::getStart() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getStart(); +} + +uno::Reference<text::XTextRange> SAL_CALL SwXContentControl::getEnd() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getEnd(); +} + +OUString SAL_CALL SwXContentControl::getString() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getString(); +} + +void SAL_CALL SwXContentControl::setString(const OUString& rString) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->setString(rString); +} + +// XSimpleText +uno::Reference<text::XTextCursor> SAL_CALL SwXContentControl::createTextCursor() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursor(); +} + +uno::Reference<text::XTextCursor> SAL_CALL +SwXContentControl::createTextCursorByRange(const uno::Reference<text::XTextRange>& xTextPosition) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursorByRange(xTextPosition); +} + +void SAL_CALL SwXContentControl::insertString(const uno::Reference<text::XTextRange>& xRange, + const OUString& rString, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertString(xRange, rString, bAbsorb); +} + +void SAL_CALL SwXContentControl::insertControlCharacter( + const uno::Reference<text::XTextRange>& xRange, sal_Int16 nControlCharacter, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertControlCharacter(xRange, nControlCharacter, bAbsorb); +} + +// XText +void SAL_CALL SwXContentControl::insertTextContent( + const uno::Reference<text::XTextRange>& xRange, + const uno::Reference<text::XTextContent>& xContent, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertTextContent(xRange, xContent, bAbsorb); +} + +void SAL_CALL +SwXContentControl::removeTextContent(const uno::Reference<text::XTextContent>& xContent) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->removeTextContent(xContent); +} + +// XPropertySet +uno::Reference<beans::XPropertySetInfo> SAL_CALL SwXContentControl::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + + static uno::Reference<beans::XPropertySetInfo> xRet + = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CONTENTCONTROL)->getPropertySetInfo(); + return xRet; +} + +void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName, + const css::uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + if (rPropertyName == UNO_NAME_SHOWING_PLACE_HOLDER) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bShowingPlaceHolder = bValue; + } + else + { + m_pImpl->m_pContentControl->SetShowingPlaceHolder(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_CHECKBOX) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bCheckbox = bValue; + } + else + { + m_pImpl->m_pContentControl->SetCheckbox(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_CHECKED) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bChecked = bValue; + } + else + { + m_pImpl->m_pContentControl->SetChecked(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_CHECKED_STATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aCheckedState = aValue; + } + else + { + m_pImpl->m_pContentControl->SetCheckedState(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_UNCHECKED_STATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aUncheckedState = aValue; + } + else + { + m_pImpl->m_pContentControl->SetUncheckedState(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_LIST_ITEMS) + { + std::vector<SwContentControlListItem> aItems + = SwContentControlListItem::ItemsFromAny(rValue); + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aListItems = aItems; + + if (!m_pImpl->m_bComboBox && !m_pImpl->m_bDropDown) + { + m_pImpl->m_bDropDown = true; + } + } + else + { + m_pImpl->m_pContentControl->SetListItems(aItems); + + if (!m_pImpl->m_pContentControl->GetComboBox() + && !m_pImpl->m_pContentControl->GetDropDown()) + { + m_pImpl->m_pContentControl->SetDropDown(true); + } + } + } + else if (rPropertyName == UNO_NAME_PICTURE) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bPicture = bValue; + } + else + { + m_pImpl->m_pContentControl->SetPicture(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATE) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bDate = bValue; + } + else + { + m_pImpl->m_pContentControl->SetDate(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATE_FORMAT) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aDateFormat = aValue; + } + else + { + m_pImpl->m_pContentControl->SetDateFormat(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATE_LANGUAGE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aDateLanguage = aValue; + } + else + { + m_pImpl->m_pContentControl->SetDateLanguage(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_CURRENT_DATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aCurrentDate = aValue; + } + else + { + m_pImpl->m_pContentControl->SetCurrentDate(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_PLAIN_TEXT) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bPlainText = bValue; + } + else + { + m_pImpl->m_pContentControl->SetPlainText(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_COMBO_BOX) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bComboBox = bValue; + } + else + { + m_pImpl->m_pContentControl->SetComboBox(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_DROP_DOWN) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bDropDown = bValue; + } + else + { + m_pImpl->m_pContentControl->SetDropDown(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_PLACEHOLDER_DOC_PART) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aPlaceholderDocPart = aValue; + } + else + { + m_pImpl->m_pContentControl->SetPlaceholderDocPart(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_PREFIX_MAPPINGS) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aDataBindingPrefixMappings = aValue; + } + else + { + m_pImpl->m_pContentControl->SetDataBindingPrefixMappings(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_XPATH) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aDataBindingXpath = aValue; + } + else + { + m_pImpl->m_pContentControl->SetDataBindingXpath(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_STORE_ITEM_ID) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aDataBindingStoreItemID = aValue; + } + else + { + m_pImpl->m_pContentControl->SetDataBindingStoreItemID(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_COLOR) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aColor = aValue; + } + else + { + m_pImpl->m_pContentControl->SetColor(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_APPEARANCE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aAppearance = aValue; + } + else + { + m_pImpl->m_pContentControl->SetAppearance(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_ALIAS) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aAlias = aValue; + } + else + { + m_pImpl->m_pContentControl->SetAlias(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_TAG) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aTag = aValue; + } + else + { + m_pImpl->m_pContentControl->SetTag(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_ID) + { + sal_Int32 nValue = 0; + if (rValue >>= nValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_nId = nValue; + } + else + { + m_pImpl->m_pContentControl->SetId(nValue); + } + } + } + else if (rPropertyName == UNO_NAME_TAB_INDEX) + { + sal_uInt32 nValue = 0; + if (rValue >>= nValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_nTabIndex = nValue; + } + else + { + m_pImpl->m_pContentControl->SetTabIndex(nValue); + } + } + } + else if (rPropertyName == UNO_NAME_LOCK) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aLock = aValue; + } + else + { + m_pImpl->m_pContentControl->SetLock(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_MULTILINE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aMultiLine = aValue; + } + else + { + m_pImpl->m_pContentControl->SetMultiLine(aValue); + } + } + } + else + { + throw beans::UnknownPropertyException(); + } +} + +uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + if (rPropertyName == UNO_NAME_SHOWING_PLACE_HOLDER) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bShowingPlaceHolder; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetShowingPlaceHolder(); + } + } + else if (rPropertyName == UNO_NAME_CHECKBOX) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bCheckbox; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCheckbox(); + } + } + else if (rPropertyName == UNO_NAME_CHECKED) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bChecked; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetChecked(); + } + } + else if (rPropertyName == UNO_NAME_CHECKED_STATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aCheckedState; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCheckedState(); + } + } + else if (rPropertyName == UNO_NAME_UNCHECKED_STATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aUncheckedState; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetUncheckedState(); + } + } + else if (rPropertyName == UNO_NAME_LIST_ITEMS) + { + std::vector<SwContentControlListItem> aItems; + if (m_pImpl->m_bIsDescriptor) + { + aItems = m_pImpl->m_aListItems; + } + else + { + aItems = m_pImpl->m_pContentControl->GetListItems(); + } + SwContentControlListItem::ItemsToAny(aItems, aRet); + } + else if (rPropertyName == UNO_NAME_PICTURE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bPicture; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetPicture(); + } + } + else if (rPropertyName == UNO_NAME_DATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bDate; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDate(); + } + } + else if (rPropertyName == UNO_NAME_DATE_FORMAT) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aDateFormat; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDateFormat(); + } + } + else if (rPropertyName == UNO_NAME_DATE_LANGUAGE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aDateLanguage; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDateLanguage(); + } + } + else if (rPropertyName == UNO_NAME_CURRENT_DATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aCurrentDate; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCurrentDate(); + } + } + else if (rPropertyName == UNO_NAME_PLAIN_TEXT) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bPlainText; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetPlainText(); + } + } + else if (rPropertyName == UNO_NAME_COMBO_BOX) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bComboBox; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetComboBox(); + } + } + else if (rPropertyName == UNO_NAME_DROP_DOWN) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bDropDown; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDropDown(); + } + } + else if (rPropertyName == UNO_NAME_PLACEHOLDER_DOC_PART) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aPlaceholderDocPart; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCurrentDate(); + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_PREFIX_MAPPINGS) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aDataBindingPrefixMappings; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDataBindingPrefixMappings(); + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_XPATH) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aDataBindingXpath; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDataBindingXpath(); + } + } + else if (rPropertyName == UNO_NAME_DATA_BINDING_STORE_ITEM_ID) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aDataBindingStoreItemID; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetDataBindingStoreItemID(); + } + } + else if (rPropertyName == UNO_NAME_COLOR) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aColor; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetColor(); + } + } + else if (rPropertyName == UNO_NAME_APPEARANCE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aAppearance; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetAppearance(); + } + } + else if (rPropertyName == UNO_NAME_ALIAS) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aAlias; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetAlias(); + } + } + else if (rPropertyName == UNO_NAME_TAG) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aTag; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetTag(); + } + } + else if (rPropertyName == UNO_NAME_DATE_STRING) + { + if (!m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_pContentControl->GetDateString(); + } + } + else if (rPropertyName == UNO_NAME_ID) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_nId; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetId(); + } + } + else if (rPropertyName == UNO_NAME_TAB_INDEX) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_nTabIndex; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetTabIndex(); + } + } + else if (rPropertyName == UNO_NAME_LOCK) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aLock; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetLock(); + } + } + else if (rPropertyName == UNO_NAME_MULTILINE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aMultiLine; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetMultiLine(); + } + } + else + { + throw beans::UnknownPropertyException(); + } + + return aRet; +} + +void SAL_CALL SwXContentControl::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::addPropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::removePropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::addVetoableChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::removeVetoableChangeListener: not implemented"); +} + +// XElementAccess +uno::Type SAL_CALL SwXContentControl::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXContentControl::hasElements() +{ + SolarMutexGuard g; + return m_pImpl->m_pContentControl != nullptr; +} + +// XEnumerationAccess +uno::Reference<container::XEnumeration> SAL_CALL SwXContentControl::createEnumeration() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException("createEnumeration(): not inserted", getXWeak()); + } + + SwTextNode* pTextNode; + sal_Int32 nContentControlStart; + sal_Int32 nContentControlEnd; + bool bSuccess = SetContentRange(pTextNode, nContentControlStart, nContentControlEnd); + if (!bSuccess) + { + SAL_WARN("sw.core", "no pam"); + throw lang::DisposedException(); + } + + SwPaM aPam(*pTextNode, nContentControlStart); + + if (!m_pImpl->m_pTextPortions) + { + return new SwXTextPortionEnumeration(aPam, GetParentText(), nContentControlStart, + nContentControlEnd); + } + else + { + return new SwXTextPortionEnumeration(aPam, std::deque(*m_pImpl->m_pTextPortions)); + } +} + +SwXContentControls::SwXContentControls(SwDoc* pDoc) + : SwUnoCollection(pDoc) +{ +} + +SwXContentControls::~SwXContentControls() {} + +sal_Int32 SwXContentControls::getCount() +{ + SolarMutexGuard aGuard; + + return GetDoc().GetContentControlManager().GetCount(); +} + +uno::Any SwXContentControls::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + + SwContentControlManager& rManager = GetDoc().GetContentControlManager(); + if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= rManager.GetCount()) + { + throw lang::IndexOutOfBoundsException(); + } + + SwTextContentControl* pTextContentControl = rManager.Get(nIndex); + const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl(); + rtl::Reference<SwXContentControl> xContentControl + = SwXContentControl::CreateXContentControl(*rFormatContentControl.GetContentControl()); + uno::Any aRet; + aRet <<= uno::Reference<text::XTextContent>(xContentControl); + return aRet; +} + +uno::Type SwXContentControls::getElementType() { return cppu::UnoType<text::XTextContent>::get(); } + +sal_Bool SwXContentControls::hasElements() +{ + SolarMutexGuard aGuard; + + return !GetDoc().GetContentControlManager().IsEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unocrsr.cxx b/sw/source/core/unocore/unocrsr.cxx new file mode 100644 index 0000000000..6c10066732 --- /dev/null +++ b/sw/source/core/unocore/unocrsr.cxx @@ -0,0 +1,216 @@ +/* -*- 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 <unocrsr.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <swtable.hxx> +#include <rootfrm.hxx> + +sw::UnoCursorHint::~UnoCursorHint() {} + +SwUnoCursor::SwUnoCursor( const SwPosition &rPos ) + : SwCursor( rPos, nullptr ) + , m_bRemainInSection(true) + , m_bSkipOverHiddenSections(false) + , m_bSkipOverProtectSections(false) +{} + +SwUnoCursor::~SwUnoCursor() +{ + SwDoc& rDoc = GetDoc(); + if( !rDoc.IsInDtor() ) + { + assert(!m_aNotifier.HasListeners()); + } + + // delete the whole ring + while( GetNext() != this ) + { + Ring* pNxt = GetNextInRing(); + // coverity[deref_arg] - the delete moves a new entry into GetNext() + pNxt->MoveTo(nullptr); // remove from chain + delete pNxt; // and delete + } + // coverity[deref_arg] - GetNext() is not a use after free at this point +} + +bool SwUnoCursor::IsReadOnlyAvailable() const +{ + return true; +} + +const SwContentFrame* +SwUnoCursor::DoSetBidiLevelLeftRight( bool &, bool, bool ) +{ + return nullptr; // not for uno cursor +} + +void SwUnoCursor::DoSetBidiLevelUpDown() +{ + // not for uno cursor +} + +bool SwUnoCursor::IsSelOvr( SwCursorSelOverFlags eFlags ) +{ + if (m_bRemainInSection) + { + SwDoc& rDoc = GetDoc(); + SwNodeIndex aOldIdx( *rDoc.GetNodes()[ GetSavePos()->nNode ] ); + SwPosition& rPtPos = *GetPoint(); + SwStartNode *pOldSttNd = aOldIdx.GetNode().StartOfSectionNode(), + *pNewSttNd = rPtPos.GetNode().StartOfSectionNode(); + if( pOldSttNd != pNewSttNd ) + { + bool bMoveDown = GetSavePos()->nNode < rPtPos.GetNodeIndex(); + bool bValidPos = false; + + // search the correct surrounded start node - which the index + // can't leave. + while( pOldSttNd->IsSectionNode() ) + pOldSttNd = pOldSttNd->StartOfSectionNode(); + + // is the new index inside this surrounded section? + if( rPtPos.GetNode() > *pOldSttNd && + rPtPos.GetNode() < *pOldSttNd->EndOfSectionNode() ) + { + // check if it a valid move inside this section + // (only over SwSection's !) + const SwStartNode* pInvalidNode; + do { + pInvalidNode = nullptr; + pNewSttNd = rPtPos.GetNode().StartOfSectionNode(); + + const SwStartNode *pSttNd = pNewSttNd, *pEndNd = pOldSttNd; + if( pSttNd->EndOfSectionIndex() > + pEndNd->EndOfSectionIndex() ) + { + pEndNd = pNewSttNd; + pSttNd = pOldSttNd; + } + + while( pSttNd->GetIndex() > pEndNd->GetIndex() ) + { + if( !pSttNd->IsSectionNode() ) + pInvalidNode = pSttNd; + pSttNd = pSttNd->StartOfSectionNode(); + } + if( pInvalidNode ) + { + if( bMoveDown ) + { + rPtPos.Assign( *pInvalidNode->EndOfSectionNode(), 1 ); + + if( !rPtPos.GetNode().IsContentNode() && + ( !rDoc.GetNodes().GoNextSection( &rPtPos ) || + rPtPos.GetNode() > *pOldSttNd->EndOfSectionNode() ) ) + break; + } + else + { + rPtPos.Assign( *pInvalidNode, -1 ); + + if( !rPtPos.GetNode().IsContentNode() && + ( !SwNodes::GoPrevSection( &rPtPos ) || + rPtPos.GetNode() < *pOldSttNd ) ) + break; + } + } + else + bValidPos = true; + } while ( pInvalidNode ); + } + + if( bValidPos ) + { + SwContentNode* pCNd = GetPointContentNode(); + GetPoint()->SetContent( (pCNd && !bMoveDown) ? pCNd->Len() : 0); + } + else + { + rPtPos.Assign( GetSavePos()->nNode ); + GetPoint()->SetContent( GetSavePos()->nContent ); + return true; + } + } + } + return SwCursor::IsSelOvr( eFlags ); +} + +SwUnoTableCursor::SwUnoTableCursor(const SwPosition& rPos) + : SwCursor(rPos, nullptr) + , SwUnoCursor(rPos) + , SwTableCursor(rPos) + , m_aTableSel(rPos, nullptr) +{ + SetRemainInSection(false); +} + +SwUnoTableCursor::~SwUnoTableCursor() +{ + while (m_aTableSel.GetNext() != &m_aTableSel) + delete m_aTableSel.GetNext(); +} + +bool SwUnoTableCursor::IsSelOvr( SwCursorSelOverFlags eFlags ) +{ + bool bRet = SwUnoCursor::IsSelOvr( eFlags ); + if( !bRet ) + { + const SwTableNode* pTNd = GetPoint()->GetNode().FindTableNode(); + bRet = !(pTNd == GetDoc().GetNodes()[ GetSavePos()->nNode ]-> + FindTableNode() && (!HasMark() || + pTNd == GetMark()->GetNode().FindTableNode() )); + } + return bRet; +} + +void SwUnoTableCursor::MakeBoxSels() +{ + const SwContentNode* pCNd; + bool bMakeTableCursors = true; + if( GetPoint()->GetNodeIndex() && GetMark()->GetNodeIndex() && + nullptr != ( pCNd = GetPointContentNode() ) && pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) && + nullptr != ( pCNd = GetMarkContentNode() ) && pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) ) + bMakeTableCursors = GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()->MakeTableCursors( *this ); + + if ( !bMakeTableCursors ) + { + SwSelBoxes const& rTmpBoxes = GetSelectedBoxes(); + while (!rTmpBoxes.empty()) + { + DeleteBox(0); + } + } + + if( IsChgd() ) + { + SwTableCursor::MakeBoxSels( &m_aTableSel ); + if (!GetSelectedBoxesCount()) + { + const SwTableBox* pBox; + const SwNode* pBoxNd = GetPoint()->GetNode().FindTableBoxStartNode(); + const SwTableNode* pTableNd = pBoxNd ? pBoxNd->FindTableNode() : nullptr; + if( pTableNd && nullptr != ( pBox = pTableNd->GetTable().GetTableBox( pBoxNd->GetIndex() )) ) + InsertBox( *pBox ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx new file mode 100644 index 0000000000..70a724814c --- /dev/null +++ b/sw/source/core/unocore/unocrsrhelper.cxx @@ -0,0 +1,1587 @@ +/* -*- 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 <unocrsrhelper.hxx> + +#include <map> +#include <algorithm> +#include <memory> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include <svx/unoshape.hxx> + +#include <cmdid.h> +#include <hintids.hxx> +#include <unotextrange.hxx> +#include <unodraw.hxx> +#include <unofootnote.hxx> +#include <unobookmark.hxx> +#include <unomap.hxx> +#include <unorefmark.hxx> +#include <unoidx.hxx> +#include <unofield.hxx> +#include <unotbl.hxx> +#include <unosett.hxx> +#include <unoframe.hxx> +#include <unocrsr.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <fmtftn.hxx> +#include <charfmt.hxx> +#include <pagedesc.hxx> +#include <docstyle.hxx> +#include <ndtxt.hxx> +#include <docsh.hxx> +#include <section.hxx> +#include <shellio.hxx> +#include <edimp.hxx> +#include <swundo.hxx> +#include <cntfrm.hxx> +#include <pagefrm.hxx> +#include <svl/eitem.hxx> +#include <svl/lngmisc.hxx> +#include <swtable.hxx> +#include <tox.hxx> +#include <doctxm.hxx> +#include <fchrfmt.hxx> +#include <editeng/editids.hrc> +#include <editeng/flstitem.hxx> +#include <editeng/prntitem.hxx> +#include <vcl/metric.hxx> +#include <svtools/ctrltool.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/fcontnr.hxx> +#include <svl/stritem.hxx> +#include <SwStyleNameMapper.hxx> +#include <redline.hxx> +#include <numrule.hxx> +#include <comphelper/storagehelper.hxx> +#include <unotools/mediadescriptor.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <SwNodeNum.hxx> +#include <fmtmeta.hxx> +#include <txtfld.hxx> +#include <unoparagraph.hxx> +#include <poolfmt.hxx> +#include <paratr.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +namespace SwUnoCursorHelper +{ + +static SwPaM* lcl_createPamCopy(const SwPaM& rPam) +{ + SwPaM *const pRet = new SwPaM(*rPam.GetPoint()); + ::sw::DeepCopyPaM(rPam, *pRet); + return pRet; +} + +void GetSelectableFromAny(uno::Reference<uno::XInterface> const& xIfc, + SwDoc & rTargetDoc, + SwPaM *& o_rpPaM, std::pair<OUString, FlyCntType> & o_rFrame, + OUString & o_rTableName, SwUnoTableCursor const*& o_rpTableCursor, + ::sw::mark::IMark const*& o_rpMark, + std::vector<SdrObject *> & o_rSdrObjects) +{ + uno::Reference<drawing::XShapes> const xShapes(xIfc, UNO_QUERY); + if (xShapes.is()) + { + sal_Int32 nShapes(xShapes->getCount()); + for (sal_Int32 i = 0; i < nShapes; ++i) + { + uno::Reference<lang::XUnoTunnel> xShape; + xShapes->getByIndex(i) >>= xShape; + if (xShape.is()) + { + SvxShape *const pSvxShape( + comphelper::getFromUnoTunnel<SvxShape>(xShape)); + if (pSvxShape) + { + SdrObject *const pSdrObject = pSvxShape->GetSdrObject(); + if (pSdrObject) + { // hmm... needs view to verify it's in right doc... + o_rSdrObjects.push_back(pSdrObject); + } + } + } + } + return; + } + + uno::Reference<lang::XUnoTunnel> const xTunnel(xIfc, UNO_QUERY); + + SwXShape *const pShape(comphelper::getFromUnoTunnel<SwXShape>(xTunnel)); + if (pShape) + { + if (SvxShape * pSvxShape = pShape->GetSvxShape()) + { + SdrObject *const pSdrObject = pSvxShape->GetSdrObject(); + if (pSdrObject) + { // hmm... needs view to verify it's in right doc... + o_rSdrObjects.push_back(pSdrObject); + } + } + return; + } + + OTextCursorHelper *const pCursor( + dynamic_cast<OTextCursorHelper*>(xIfc.get())); + if (pCursor) + { + if (pCursor->GetDoc() == &rTargetDoc) + { + o_rpPaM = lcl_createPamCopy(*pCursor->GetPaM()); + } + return; + } + + SwXTextRanges* const pRanges = dynamic_cast<SwXTextRanges*>(xIfc.get()); + if (pRanges) + { + SwUnoCursor const* pUnoCursor = pRanges->GetCursor(); + if (pUnoCursor && &pUnoCursor->GetDoc() == &rTargetDoc) + { + o_rpPaM = lcl_createPamCopy(*pUnoCursor); + } + return; + } + + // check these before Range to prevent misinterpretation of text frames + // and cells also implement XTextRange + SwXFrame *const pFrame = dynamic_cast<SwXFrame*>(xIfc.get()); + if (pFrame) + { + const SwFrameFormat *const pFrameFormat(pFrame->GetFrameFormat()); + if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc) + { + o_rFrame = std::make_pair(pFrameFormat->GetName(), pFrame->GetFlyCntType()); + } + return; + } + + SwXTextTable *const pTextTable = dynamic_cast<SwXTextTable*>(xIfc.get()); + if (pTextTable) + { + SwFrameFormat *const pFrameFormat(pTextTable->GetFrameFormat()); + if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc) + { + o_rTableName = pFrameFormat->GetName(); + } + return; + } + + SwXCell *const pCell = dynamic_cast<SwXCell*>(xIfc.get()); + if (pCell) + { + SwFrameFormat *const pFrameFormat(pCell->GetFrameFormat()); + if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc) + { + SwTableBox * pBox = pCell->GetTableBox(); + SwTable *const pTable = SwTable::FindTable(pFrameFormat); + // ??? what's the benefit of setting pBox in this convoluted way? + pBox = pCell->FindBox(pTable, pBox); + if (pBox) + { + SwPaM aPam(*pBox->GetSttNd()); + aPam.Move(fnMoveForward, GoInNode); + o_rpPaM = lcl_createPamCopy(aPam); + } + } + return; + } + + uno::Reference<text::XTextRange> const xTextRange(xTunnel, UNO_QUERY); + if (xTextRange.is()) + { + SwUnoInternalPaM aPam(rTargetDoc); + if (::sw::XTextRangeToSwPaM(aPam, xTextRange)) + { + o_rpPaM = lcl_createPamCopy(aPam); + } + return; + } + + SwXCellRange *const pCellRange = dynamic_cast<SwXCellRange*>(xIfc.get()); + if (pCellRange) + { + SwUnoCursor const*const pUnoCursor(pCellRange->GetTableCursor()); + if (pUnoCursor && &pUnoCursor->GetDoc() == &rTargetDoc) + { + // probably can't copy it to o_rpPaM for this since it's + // a SwTableCursor + o_rpTableCursor = dynamic_cast<SwUnoTableCursor const*>(pUnoCursor); + } + return; + } + + ::sw::mark::IMark const*const pMark = + SwXBookmark::GetBookmarkInDoc(& rTargetDoc, xIfc); + if (pMark) + { + o_rpMark = pMark; + return; + } +} + +uno::Reference<text::XTextContent> +GetNestedTextContent(SwTextNode const & rTextNode, sal_Int32 const nIndex, + bool const bParent) +{ + // these should be unambiguous because of the dummy character + auto const eMode( bParent + ? ::sw::GetTextAttrMode::Parent : ::sw::GetTextAttrMode::Expand ); + SwTextAttr *const pMetaTextAttr = + rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_META, eMode); + SwTextAttr *const pMetaFieldTextAttr = + rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_METAFIELD, eMode); + // which is innermost? + SwTextAttr *const pTextAttr = pMetaTextAttr + ? (pMetaFieldTextAttr + ? ((pMetaFieldTextAttr->GetStart() > + pMetaTextAttr->GetStart()) + ? pMetaFieldTextAttr : pMetaTextAttr) + : pMetaTextAttr) + : pMetaFieldTextAttr; + uno::Reference<XTextContent> xRet; + if (pTextAttr) + { + ::sw::Meta *const pMeta( + static_cast<SwFormatMeta &>(pTextAttr->GetAttr()).GetMeta()); + assert(pMeta); + xRet.set(pMeta->MakeUnoObject(), uno::UNO_QUERY); + } + return xRet; +} + +static uno::Any GetParaListAutoFormat(SwTextNode const& rNode) +{ + SwFormatAutoFormat const*const pFormat( + rNode.GetSwAttrSet().GetItem<SwFormatAutoFormat>(RES_PARATR_LIST_AUTOFMT, false)); + if (!pFormat) + { + return uno::Any(); + } + const auto pSet(pFormat->GetStyleHandle()); + if (!pSet) + return {}; + SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + std::vector<beans::NamedValue> props; + // have to iterate the map, not the item set? + for (auto const pEntry : rMap.getPropertyEntries()) + { + if (rPropSet.getPropertyState(*pEntry, *pSet) == PropertyState_DIRECT_VALUE) + { + Any value; + rPropSet.getPropertyValue(*pEntry, *pSet, value); + props.emplace_back(pEntry->aName, value); + } + } + return uno::Any(comphelper::containerToSequence(props)); +} + +// Read the special properties of the cursor +bool getCursorPropertyValue(const SfxItemPropertyMapEntry& rEntry + , SwPaM& rPam + , Any *pAny + , PropertyState& eState + , const SwTextNode* pNode ) +{ + PropertyState eNewState = PropertyState_DIRECT_VALUE; + bool bDone = true; + switch(rEntry.nWID) + { + case FN_UNO_PARA_CONT_PREV_SUBTREE: + if (pAny) + { + const SwTextNode * pTmpNode = pNode; + + if (!pTmpNode) + pTmpNode = rPam.GetPointNode().GetTextNode(); + + bool bRet = false; + + if ( pTmpNode && + pTmpNode->GetNum() && + pTmpNode->GetNum()->IsContinueingPreviousSubTree() ) + { + bRet = true; + } + + *pAny <<= bRet; + } + break; + case FN_UNO_PARA_NUM_STRING: + if (pAny) + { + const SwTextNode * pTmpNode = pNode; + + if (!pTmpNode) + pTmpNode = rPam.GetPointNode().GetTextNode(); + + OUString sRet; + if ( pTmpNode && pTmpNode->GetNum() ) + { + sRet = pTmpNode->GetNumString(); + } + + *pAny <<= sRet; + } + break; + case RES_PARATR_OUTLINELEVEL: + if (pAny) + { + const SwTextNode * pTmpNode = pNode; + + if (!pTmpNode) + pTmpNode = rPam.GetPointNode().GetTextNode(); + + sal_Int16 nRet = -1; + if ( pTmpNode ) + nRet = sal::static_int_cast< sal_Int16 >( pTmpNode->GetAttrOutlineLevel() ); + + *pAny <<= nRet; + } + break; + case FN_UNO_PARA_CONDITIONAL_STYLE_NAME: + case FN_UNO_PARA_STYLE : + { + SwFormatColl* pFormat = nullptr; + if(pNode) + pFormat = FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID + ? pNode->GetFormatColl() : &pNode->GetAnyFormatColl(); + else + { + pFormat = SwUnoCursorHelper::GetCurTextFormatColl(rPam, + FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID); + } + if(pFormat) + { + if( pAny ) + { + OUString sVal; + SwStyleNameMapper::FillProgName(pFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl ); + *pAny <<= sVal; + } + } + else + eNewState = PropertyState_AMBIGUOUS_VALUE; + } + break; + case FN_UNO_PAGE_STYLE : + { + OUString sVal; + GetCurPageStyle(rPam, sVal); + if( pAny ) + *pAny <<= sVal; + if(sVal.isEmpty()) + eNewState = PropertyState_AMBIGUOUS_VALUE; + } + break; + case FN_UNO_NUM_START_VALUE : + if( pAny ) + { + sal_Int16 nValue = IsNodeNumStart(rPam, eNewState); + *pAny <<= nValue; + } + break; + case FN_UNO_NUM_LEVEL : + case FN_UNO_IS_NUMBER : + // #i91601# + case FN_UNO_LIST_ID: + case FN_NUMBER_NEWSTART: + case FN_UNO_PARA_NUM_AUTO_FORMAT: + { + if (!pAny) + { + break; + } + // a multi selection is not considered + const SwTextNode* pTextNd = rPam.GetPointNode().GetTextNode(); + if ( pTextNd && pTextNd->IsInList() ) + { + switch (rEntry.nWID) + { + case FN_UNO_NUM_LEVEL: + { + *pAny <<= static_cast<sal_Int16>(pTextNd->GetActualListLevel()); + break; + } + case FN_UNO_IS_NUMBER: + { + *pAny <<= pTextNd->IsCountedInList(); + break; + } + // #i91601# + case FN_UNO_LIST_ID: + { + *pAny <<= pTextNd->GetListId(); + break; + } + case FN_NUMBER_NEWSTART: + { + *pAny <<= pTextNd->IsListRestart(); + break; + } + case FN_UNO_PARA_NUM_AUTO_FORMAT: + { + *pAny = GetParaListAutoFormat(*pTextNd); + break; + } + default: + assert(false); + } + } + else + { + eNewState = PropertyState_DEFAULT_VALUE; + + // #i30838# set default values for default properties + switch (rEntry.nWID) + { + case FN_UNO_NUM_LEVEL: + { + *pAny <<= static_cast<sal_Int16>( 0 ); + break; + } + case FN_UNO_IS_NUMBER: + { + *pAny <<= false; + break; + } + // #i91601# + case FN_UNO_LIST_ID: + { + *pAny <<= OUString(); + break; + } + case FN_NUMBER_NEWSTART: + { + *pAny <<= false; + break; + } + case FN_UNO_PARA_NUM_AUTO_FORMAT: + { + break; // void + } + default: + assert(false); + } + } + //PROPERTY_MAYBEVOID! + } + break; + case FN_UNO_NUM_RULES : + if( pAny ) + getNumberingProperty(rPam, eNewState, pAny); + else + { + if( !SwDoc::GetNumRuleAtPos( *rPam.GetPoint() ) ) + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_DOCUMENT_INDEX_MARK: + { + std::vector<SwTextAttr *> marks; + if (rPam.GetPointNode().IsTextNode()) + { + marks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_TOXMARK); + } + if (!marks.empty()) + { + if( pAny ) + { // hmm... can only return 1 here + SwTOXMark & rMark = + static_cast<SwTOXMark &>((*marks.begin())->GetAttr()); + const uno::Reference< text::XDocumentIndexMark > xRef = + SwXDocumentIndexMark::CreateXDocumentIndexMark( + rPam.GetDoc(), &rMark); + (*pAny) <<= xRef; + } + } + else + //also here - indistinguishable + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_DOCUMENT_INDEX: + { + SwTOXBase* pBase = SwDoc::GetCurTOX( + *rPam.Start() ); + if( pBase ) + { + if( pAny ) + { + const uno::Reference< text::XDocumentIndex > xRef = + SwXDocumentIndex::CreateXDocumentIndex(rPam.GetDoc(), + static_cast<SwTOXBaseSection *>(pBase)); + (*pAny) <<= xRef; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_TEXT_FIELD: + { + const SwPosition *pPos = rPam.Start(); + const SwTextNode *pTextNd = + rPam.GetDoc().GetNodes()[pPos->GetNodeIndex()]->GetTextNode(); + const SwTextAttr* pTextAttr = pTextNd + ? pTextNd->GetFieldTextAttrAt(pPos->GetContentIndex(), ::sw::GetTextAttrMode::Default) + : nullptr; + if ( pTextAttr != nullptr ) + { + if( pAny ) + { + uno::Reference<text::XTextField> const xField( + SwXTextField::CreateXTextField(&rPam.GetDoc(), + &pTextAttr->GetFormatField())); + *pAny <<= xField; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_TEXT_TABLE: + case FN_UNO_CELL: + { + SwStartNode* pSttNode = rPam.GetPointNode().StartOfSectionNode(); + SwStartNodeType eType = pSttNode->GetStartNodeType(); + if(SwTableBoxStartNode == eType) + { + if( pAny ) + { + const SwTableNode* pTableNode = pSttNode->FindTableNode(); + SwFrameFormat* pTableFormat = pTableNode->GetTable().GetFrameFormat(); + //SwTable& rTable = static_cast<SwTableNode*>(pSttNode)->GetTable(); + if(FN_UNO_TEXT_TABLE == rEntry.nWID) + { + uno::Reference< XTextTable > xTable = SwXTextTables::GetObject(*pTableFormat); + *pAny <<= xTable; + } + else + { + SwTableBox* pBox = pSttNode->GetTableBox(); + uno::Reference< XCell > xCell = SwXCell::CreateXCell(pTableFormat, pBox); + *pAny <<= xCell; + } + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_TEXT_FRAME: + { + SwStartNode* pSttNode = rPam.GetPointNode().StartOfSectionNode(); + SwStartNodeType eType = pSttNode->GetStartNodeType(); + + SwFrameFormat* pFormat; + if(eType == SwFlyStartNode && nullptr != (pFormat = pSttNode->GetFlyFormat())) + { + // Create a wrapper only for text frames, not for graphic or OLE nodes. + if (pAny && !rPam.GetPointNode().IsNoTextNode()) + { + uno::Reference<XTextFrame> const xFrame( + SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat)); + (*pAny) <<= xFrame; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_TEXT_SECTION: + { + SwSection* pSect = SwDoc::GetCurrSection(*rPam.GetPoint()); + if(pSect) + { + if( pAny ) + { + uno::Reference< XTextSection > xSect = SwXTextSections::GetObject( *pSect->GetFormat() ); + *pAny <<= xSect; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_TEXT_PARAGRAPH: + { + SwTextNode* pTextNode = rPam.GetPoint()->GetNode().GetTextNode(); + if (pTextNode) + { + if (pAny) + { + uno::Reference<text::XTextContent> xParagraph = SwXParagraph::CreateXParagraph(pTextNode->GetDoc(), pTextNode, nullptr); + *pAny <<= xParagraph; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_SORTED_TEXT_ID: + { + if( pAny ) + { + sal_Int32 nIndex = -1; + SwTextNode* pTextNode = rPam.GetPoint()->GetNode().GetTextNode(); + if ( pTextNode ) + nIndex = pTextNode->GetIndex().get(); + *pAny <<= nIndex; + } + } + break; + case FN_UNO_ENDNOTE: + case FN_UNO_FOOTNOTE: + { + SwTextAttr *const pTextAttr = rPam.GetPointNode().IsTextNode() ? + rPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_FTN) : nullptr; + if(pTextAttr) + { + const SwFormatFootnote& rFootnote = pTextAttr->GetFootnote(); + if(rFootnote.IsEndNote() == (FN_UNO_ENDNOTE == rEntry.nWID)) + { + if( pAny ) + { + const uno::Reference< text::XFootnote > xFootnote = + SwXFootnote::CreateXFootnote(rPam.GetDoc(), + &const_cast<SwFormatFootnote&>(rFootnote)); + *pAny <<= xFootnote; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_REFERENCE_MARK: + { + std::vector<SwTextAttr *> marks; + if (rPam.GetPointNode().IsTextNode()) + { + marks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK); + } + if (!marks.empty()) + { + if( pAny ) + { // hmm... can only return 1 here + const SwFormatRefMark& rRef = (*marks.begin())->GetRefMark(); + uno::Reference<XTextContent> const xRef = + SwXReferenceMark::CreateXReferenceMark(rPam.GetDoc(), + const_cast<SwFormatRefMark*>(&rRef)); + *pAny <<= xRef; + } + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case FN_UNO_NESTED_TEXT_CONTENT: + { + uno::Reference<XTextContent> const xRet(rPam.GetPointNode().IsTextNode() + ? GetNestedTextContent(*rPam.GetPointNode().GetTextNode(), + rPam.GetPoint()->GetContentIndex(), false) + : nullptr); + if (xRet.is()) + { + if (pAny) + { + (*pAny) <<= xRet; + } + } + else + { + eNewState = PropertyState_DEFAULT_VALUE; + } + } + break; + case FN_UNO_CHARFMT_SEQUENCE: + { + + SwTextNode *const pTextNode = rPam.GetPointNode().GetTextNode(); + if (&rPam.GetPointNode() == &rPam.GetMarkNode() + && pTextNode && pTextNode->GetpSwpHints()) + { + sal_Int32 nPaMStart = rPam.Start()->GetContentIndex(); + sal_Int32 nPaMEnd = rPam.End()->GetContentIndex(); + Sequence< OUString> aCharStyles; + SwpHints* pHints = pTextNode->GetpSwpHints(); + for( size_t nAttr = 0; nAttr < pHints->Count(); ++nAttr ) + { + SwTextAttr* pAttr = pHints->Get( nAttr ); + if(pAttr->Which() != RES_TXTATR_CHARFMT) + continue; + const sal_Int32 nAttrStart = pAttr->GetStart(); + const sal_Int32 nAttrEnd = *pAttr->GetEnd(); + //check if the attribute touches the selection + if( ( nAttrEnd > nPaMStart && nAttrStart < nPaMEnd ) || + ( !nAttrStart && !nAttrEnd && !nPaMStart && !nPaMEnd ) ) + { + //check for overlapping + if(nAttrStart > nPaMStart || + nAttrEnd < nPaMEnd) + { + aCharStyles.realloc(0); + break; + } + else + { + //now the attribute should start before or at the selection + //and it should end at the end of the selection or behind + OSL_ENSURE(nAttrStart <= nPaMStart && nAttrEnd >=nPaMEnd, + "attribute overlaps or is outside"); + //now the name of the style has to be added to the sequence + aCharStyles.realloc(aCharStyles.getLength() + 1); + OSL_ENSURE(pAttr->GetCharFormat().GetCharFormat(), "no character format set"); + aCharStyles.getArray()[aCharStyles.getLength() - 1] = + SwStyleNameMapper::GetProgName( + pAttr->GetCharFormat().GetCharFormat()->GetName(), SwGetPoolIdFromName::ChrFmt); + } + } + + } + eNewState = + aCharStyles.hasElements() ? + PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE; + if(pAny) + (*pAny) <<= aCharStyles; + } + else + eNewState = PropertyState_DEFAULT_VALUE; + } + break; + case RES_TXTATR_CHARFMT: + // no break here! + default: bDone = false; + } + if( bDone ) + eState = eNewState; + return bDone; +}; + +sal_Int16 IsNodeNumStart(SwPaM const & rPam, PropertyState& eState) +{ + const SwTextNode* pTextNd = rPam.GetPointNode().GetTextNode(); + // correction: check, if restart value is set at the text node and use + // new method <SwTextNode::GetAttrListRestartValue()> to retrieve the value + if ( pTextNd && pTextNd->GetNumRule() && pTextNd->IsListRestart() && + pTextNd->HasAttrListRestartValue() ) + { + eState = PropertyState_DIRECT_VALUE; + sal_Int16 nTmp = sal::static_int_cast< sal_Int16 >(pTextNd->GetAttrListRestartValue()); + return nTmp; + } + eState = PropertyState_DEFAULT_VALUE; + return -1; +} + +void setNumberingProperty(const Any& rValue, SwPaM& rPam) +{ + uno::Reference<XIndexReplace> xIndexReplace; + if(rValue >>= xIndexReplace) + { + auto pSwNum = dynamic_cast<SwXNumberingRules*>(xIndexReplace.get()); + if(pSwNum) + { + SwDoc& rDoc = rPam.GetDoc(); + if(pSwNum->GetNumRule()) + { + SwNumRule aRule(*pSwNum->GetNumRule()); + const OUString* pNewCharStyles = pSwNum->GetNewCharStyleNames(); + const OUString* pBulletFontNames = pSwNum->GetBulletFontNames(); + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + SwNumFormat aFormat(aRule.Get( i )); + if (!pNewCharStyles[i].isEmpty() && + !SwXNumberingRules::isInvalidStyle(pNewCharStyles[i]) && + (!aFormat.GetCharFormat() || pNewCharStyles[i] != aFormat.GetCharFormat()->GetName())) + { + if (pNewCharStyles[i].isEmpty()) + { + // FIXME + // Is something missing/wrong here? + // if condition is always false due to outer check! + aFormat.SetCharFormat(nullptr); + } + else + { + + // get CharStyle and set the rule + const size_t nChCount = rDoc.GetCharFormats()->size(); + SwCharFormat* pCharFormat = nullptr; + for(size_t nCharFormat = 0; nCharFormat < nChCount; ++nCharFormat) + { + SwCharFormat& rChFormat = *((*(rDoc.GetCharFormats()))[nCharFormat]); + if(rChFormat.GetName() == pNewCharStyles[i]) + { + pCharFormat = &rChFormat; + break; + } + } + + if(!pCharFormat) + { + SfxStyleSheetBasePool* pPool = rDoc.GetDocShell()->GetStyleSheetPool(); + SfxStyleSheetBase* pBase; + pBase = pPool->Find(pNewCharStyles[i], SfxStyleFamily::Char); + // shall it really be created? + if(!pBase) + pBase = &pPool->Make(pNewCharStyles[i], SfxStyleFamily::Page); + pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + } + if(pCharFormat) + aFormat.SetCharFormat(pCharFormat); + } + } + //Now again for fonts + if( + !pBulletFontNames[i].isEmpty() && + !SwXNumberingRules::isInvalidStyle(pBulletFontNames[i]) && + (!aFormat.GetBulletFont() || aFormat.GetBulletFont()->GetFamilyName() != pBulletFontNames[i]) + ) + { + const SvxFontListItem* pFontListItem = + static_cast<const SvxFontListItem* >(rDoc.GetDocShell() + ->GetItem( SID_ATTR_CHAR_FONTLIST )); + const FontList* pList = pFontListItem->GetFontList(); + + vcl::Font aFont(pList->Get( + pBulletFontNames[i],WEIGHT_NORMAL, ITALIC_NONE)); + aFormat.SetBulletFont(&aFont); + } + aRule.Set( i, aFormat ); + } + UnoActionContext aAction(&rDoc); + + if( rPam.GetNext() != &rPam ) // Multiple selection? + { + rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + SwPamRanges aRangeArr( rPam ); + SwPaM aPam( *rPam.GetPoint() ); + for ( size_t n = 0; n < aRangeArr.Count(); ++n ) + { + // no start of a new list + rDoc.SetNumRule( aRangeArr.SetPam( n, aPam ), aRule, false ); + } + rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } + else + { + // no start of a new list + rDoc.SetNumRule( rPam, aRule, false ); + } + + } + else if(!pSwNum->GetCreatedNumRuleName().isEmpty()) + { + UnoActionContext aAction( &rDoc ); + SwNumRule* pRule = rDoc.FindNumRulePtr( pSwNum->GetCreatedNumRuleName() ); + if ( !pRule ) + throw RuntimeException(); + // no start of a new list + rDoc.SetNumRule( rPam, *pRule, false ); + } + else + { + // #i103817# + // outline numbering + UnoActionContext aAction(&rDoc); + SwNumRule* pRule = rDoc.GetOutlineNumRule(); + if(!pRule) + throw RuntimeException(); + rDoc.SetNumRule( rPam, *pRule, false ); + } + } + } + else if ( rValue.getValueType() == cppu::UnoType<void>::get() ) + { + rPam.GetDoc().DelNumRules(rPam); + } +} + +void getNumberingProperty(SwPaM& rPam, PropertyState& eState, Any * pAny ) +{ + const SwNumRule* pNumRule = SwDoc::GetNumRuleAtPos( *rPam.GetPoint() ); + if(pNumRule) + { + uno::Reference< XIndexReplace > xNum = new SwXNumberingRules(*pNumRule); + if ( pAny ) + *pAny <<= xNum; + eState = PropertyState_DIRECT_VALUE; + } + else + eState = PropertyState_DEFAULT_VALUE; +} + +void GetCurPageStyle(SwPaM const & rPaM, OUString &rString) +{ + if (!rPaM.GetPointContentNode()) + return; // TODO: is there an easy way to get it for tables/sections? + SwRootFrame* pLayout = rPaM.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(); + // Consider the position inside the content node, since the node may span over multiple pages + // with different page styles. + SwContentFrame* pFrame = rPaM.GetPointContentNode()->getLayoutFrame(pLayout, rPaM.GetPoint()); + if(pFrame) + { + const SwPageFrame* pPage = pFrame->FindPageFrame(); + if(pPage) + { + SwStyleNameMapper::FillProgName(pPage->GetPageDesc()->GetName(), + rString, SwGetPoolIdFromName::PageDesc); + } + } +} + +// reset special properties of the cursor +void resetCursorPropertyValue(const SfxItemPropertyMapEntry& rEntry, SwPaM& rPam) +{ + SwDoc& rDoc = rPam.GetDoc(); + switch(rEntry.nWID) + { + case FN_UNO_PARA_STYLE : + break; + case FN_UNO_PAGE_STYLE : + break; + case FN_UNO_NUM_START_VALUE : + { + UnoActionContext aAction(&rDoc); + + if( rPam.GetNext() != &rPam ) // Multiple selection? + { + rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + SwPamRanges aRangeArr( rPam ); + SwPaM aPam( *rPam.GetPoint() ); + for( size_t n = 0; n < aRangeArr.Count(); ++n ) + rDoc.SetNodeNumStart( *aRangeArr.SetPam( n, aPam ).GetPoint(), 1 ); + rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } + else + rDoc.SetNodeNumStart( *rPam.GetPoint(), 0 ); + } + + break; + case FN_UNO_NUM_LEVEL : + break; + case FN_UNO_NUM_RULES: + break; + case FN_UNO_CHARFMT_SEQUENCE: + { + rDoc.ResetAttrs(rPam, true, { RES_TXTATR_CHARFMT }); + } + break; + } +} + +void InsertFile(SwUnoCursor* pUnoCursor, const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rOptions) +{ + if (SwTextNode const*const pTextNode = pUnoCursor->GetPoint()->GetNode().GetTextNode()) + { + // TODO: check meta field here too in case it ever grows a 2nd char + if (pTextNode->GetTextAttrAt(pUnoCursor->GetPoint()->GetContentIndex(), + RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent)) + { + throw uno::RuntimeException("cannot insert file inside input field"); + } + + if (pTextNode->GetTextAttrAt(pUnoCursor->GetPoint()->GetContentIndex(), + RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent)) + { + throw uno::RuntimeException("cannot insert file inside content controls"); + } + } + + std::unique_ptr<SfxMedium> pMed; + SwDoc& rDoc = pUnoCursor->GetDoc(); + SwDocShell* pDocSh = rDoc.GetDocShell(); + utl::MediaDescriptor aMediaDescriptor( rOptions ); + OUString sFileName = rURL; + OUString sFilterName, sFilterOptions, sPassword, sBaseURL; + uno::Reference < io::XStream > xStream; + uno::Reference < io::XInputStream > xInputStream; + + if( sFileName.isEmpty() ) + aMediaDescriptor[utl::MediaDescriptor::PROP_URL] >>= sFileName; + if( sFileName.isEmpty() ) + aMediaDescriptor[utl::MediaDescriptor::PROP_FILENAME] >>= sFileName; + aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream; + aMediaDescriptor[utl::MediaDescriptor::PROP_STREAM] >>= xStream; + aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream; + aMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] >>= sFilterName; + aMediaDescriptor[utl::MediaDescriptor::PROP_FILTEROPTIONS] >>= sFilterOptions; + aMediaDescriptor[utl::MediaDescriptor::PROP_PASSWORD] >>= sPassword; + aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL ] >>= sBaseURL; + if ( !xInputStream.is() && xStream.is() ) + xInputStream = xStream->getInputStream(); + + if(!pDocSh || (sFileName.isEmpty() && !xInputStream.is())) + return; + + SfxObjectFactory& rFact = pDocSh->GetFactory(); + std::shared_ptr<const SfxFilter> pFilter = rFact.GetFilterContainer()->GetFilter4FilterName( sFilterName ); + uno::Reference < embed::XStorage > xReadStorage; + if( xInputStream.is() ) + { + uno::Sequence< uno::Any > aArgs{ uno::Any(xInputStream), + uno::Any(embed::ElementModes::READ) }; + try + { + xReadStorage.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ), + uno::UNO_QUERY ); + } + catch( const io::IOException&) {} + } + if ( !pFilter ) + { + if( xInputStream.is() && !xReadStorage.is()) + { + pMed.reset(new SfxMedium); + pMed->setStreamToLoadFrom(xInputStream, true ); + } + else + pMed.reset(xReadStorage.is() ? + new SfxMedium(xReadStorage, sBaseURL ) : + new SfxMedium(sFileName, StreamMode::READ )); + if( !sBaseURL.isEmpty() ) + pMed->GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) ); + + SfxFilterMatcher aMatcher( rFact.GetFilterContainer()->GetName() ); + ErrCode nErr = aMatcher.GuessFilter(*pMed, pFilter, SfxFilterFlags::NONE); + if ( nErr || !pFilter) + return; + pMed->SetFilter( pFilter ); + } + else + { + if( xInputStream.is() && !xReadStorage.is()) + { + pMed.reset(new SfxMedium); + pMed->setStreamToLoadFrom(xInputStream, true ); + pMed->SetFilter( pFilter ); + } + else + { + if( xReadStorage.is() ) + { + pMed.reset(new SfxMedium(xReadStorage, sBaseURL )); + pMed->SetFilter( pFilter ); + } + else + pMed.reset(new SfxMedium(sFileName, StreamMode::READ, pFilter, nullptr)); + } + if(!sFilterOptions.isEmpty()) + pMed->GetItemSet().Put( SfxStringItem( SID_FILE_FILTEROPTIONS, sFilterOptions ) ); + if(!sBaseURL.isEmpty()) + pMed->GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) ); + } + + // this sourcecode is not responsible for the lifetime of the shell, SfxObjectShellLock should not be used + SfxObjectShellRef aRef( pDocSh ); + + pMed->Download(); // if necessary: start the download + if( !(aRef.is() && 1 < aRef->GetRefCount()) ) // Ref still valid? + return; + + SwReaderPtr pRdr; + SfxItemSet& rSet = pMed->GetItemSet(); + rSet.Put(SfxBoolItem(FN_API_CALL, true)); + if(!sPassword.isEmpty()) + rSet.Put(SfxStringItem(SID_PASSWORD, sPassword)); + Reader *pRead = pDocSh->StartConvertFrom( *pMed, pRdr, nullptr, pUnoCursor); + if( !pRead ) + return; + + UnoActionContext aContext(&rDoc); + + if(pUnoCursor->HasMark()) + rDoc.getIDocumentContentOperations().DeleteAndJoin(*pUnoCursor); + + SwNodeIndex aSave( pUnoCursor->GetPoint()->GetNode(), -1 ); + sal_Int32 nContent = pUnoCursor->GetPoint()->GetContentIndex(); + + ErrCodeMsg nErrno = pRdr->Read( *pRead ); // and paste the document + + if(!nErrno) + { + ++aSave; + pUnoCursor->SetMark(); + pUnoCursor->GetMark()->Assign( aSave ); + + SwContentNode* pCntNode = aSave.GetNode().GetContentNode(); + if( !pCntNode ) + nContent = 0; + pUnoCursor->GetMark()->SetContent( nContent ); + } +} + +// insert text and scan for CR characters in order to insert +// paragraph breaks at those positions by calling SplitNode +bool DocInsertStringSplitCR( + SwDoc &rDoc, + const SwPaM &rNewCursor, + std::u16string_view rText, + const bool bForceExpandHints ) +{ + bool bOK = true; + + for (size_t i = 0; i < rText.size(); ++i) + { + sal_Unicode const ch(rText[i]); + if (linguistic::IsControlChar(ch) + && ch != '\r' && ch != '\n' && ch != '\t') + { + SAL_WARN("sw.uno", "DocInsertStringSplitCR: refusing to insert control character " << int(ch)); + return false; + } + } + + const SwInsertFlags nInsertFlags = + bForceExpandHints + ? ( SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND) + : SwInsertFlags::EMPTYEXPAND; + + // grouping done in InsertString is intended for typing, not API calls + ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + SwTextNode* const pTextNd = + rNewCursor.GetPoint()->GetNode().GetTextNode(); + if (!pTextNd) + { + SAL_INFO("sw.uno", "DocInsertStringSplitCR: need a text node"); + return false; + } + OUString aText; + sal_Int32 nStartIdx = 0; + const sal_Int32 nMaxLength = COMPLETE_STRING - pTextNd->GetText().getLength(); + + size_t nIdx = rText.find( '\r', nStartIdx ); + if( ( nIdx == std::u16string_view::npos && nMaxLength < sal_Int32(rText.size()) ) || + ( nIdx != std::u16string_view::npos && nMaxLength < sal_Int32(nIdx) ) ) + { + nIdx = nMaxLength; + } + while (nIdx != std::u16string_view::npos ) + { + OSL_ENSURE( sal_Int32(nIdx) - nStartIdx >= 0, "index negative!" ); + aText = rText.substr( nStartIdx, nIdx - nStartIdx ); + if (!aText.isEmpty() && + !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags )) + { + OSL_FAIL( "Doc->Insert(Str) failed." ); + bOK = false; + } + if (!rDoc.getIDocumentContentOperations().SplitNode( *rNewCursor.GetPoint(), false ) ) + { + OSL_FAIL( "SplitNode failed" ); + bOK = false; + } + nStartIdx = nIdx + 1; + nIdx = rText.find( '\r', nStartIdx ); + } + aText = rText.substr( nStartIdx ); + if (!aText.isEmpty() && + !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags )) + { + OSL_FAIL( "Doc->Insert(Str) failed." ); + bOK = false; + } + + return bOK; +} + +void makeRedline( SwPaM const & rPaM, + std::u16string_view rRedlineType, + const uno::Sequence< beans::PropertyValue >& rRedlineProperties ) +{ + IDocumentRedlineAccess& rRedlineAccess = rPaM.GetDoc().getIDocumentRedlineAccess(); + + RedlineType eType; + if ( rRedlineType == u"Insert" ) + eType = RedlineType::Insert; + else if ( rRedlineType == u"Delete" ) + eType = RedlineType::Delete; + else if ( rRedlineType == u"Format" ) + eType = RedlineType::Format; + else if ( rRedlineType == u"TextTable" ) + eType = RedlineType::Table; + else if ( rRedlineType == u"ParagraphFormat" ) + eType = RedlineType::ParagraphFormat; + else + throw lang::IllegalArgumentException(); + + //todo: what about REDLINE_FMTCOLL? + std::size_t nAuthor = 0; + OUString sAuthor; + OUString sComment; + ::util::DateTime aStamp; + uno::Sequence< beans::PropertyValue > aRevertProperties; + sal_uInt32 nMovedID = 0; + bool bFoundComment = false; + bool bFoundStamp = false; + bool bFoundRevertProperties = false; + for (const css::beans::PropertyValue & rProp : rRedlineProperties ) + { + if (rProp.Name == "RedlineAuthor") + { + if( rProp.Value >>= sAuthor ) + nAuthor = rRedlineAccess.InsertRedlineAuthor(sAuthor); + } + else if (rProp.Name == "RedlineComment") + bFoundComment = rProp.Value >>= sComment; + else if (rProp.Name == "RedlineDateTime") + bFoundStamp = rProp.Value >>= aStamp; + else if (rProp.Name == "RedlineRevertProperties") + bFoundRevertProperties = rProp.Value >>= aRevertProperties; + else if (rProp.Name == "RedlineMoved") + rProp.Value >>= nMovedID; + } + + SwRedlineData aRedlineData( eType, nAuthor ); + if( bFoundComment ) + aRedlineData.SetComment( sComment ); + if( bFoundStamp ) + aRedlineData.SetTimeStamp( DateTime( aStamp)); + + std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData; + + // Read the 'Redline Revert Properties' from the parameters + // Check if the value exists + if ( bFoundRevertProperties ) + { + int nMap = 0; + // Make sure that paragraph format gets its own map, otherwise e.g. fill attributes are not preserved. + if (eType == RedlineType::ParagraphFormat) + { + nMap = PROPERTY_MAP_PARAGRAPH; + if (!aRevertProperties.hasElements()) + { + // to reject the paragraph style change, use standard style + xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl( "", RES_POOLCOLL_STANDARD, nullptr )); + } + } + else + nMap = PROPERTY_MAP_TEXTPORTION_EXTENSIONS; + SfxItemPropertySet const& rPropSet = *aSwMapProvider.GetPropertySet(nMap); + + // Check if there are any properties + if (aRevertProperties.hasElements()) + { + SwDoc& rDoc = rPaM.GetDoc(); + + // Build set of attributes we want to fetch + WhichRangesContainer aWhichPairs; + std::vector<SfxItemPropertyMapEntry const*> aEntries; + std::vector<uno::Any> aValues; + aEntries.reserve(aRevertProperties.getLength()); + sal_uInt16 nStyleId = USHRT_MAX; + sal_uInt16 nNumId = USHRT_MAX; + for (const auto& rRevertProperty : std::as_const(aRevertProperties)) + { + const OUString &rPropertyName = rRevertProperty.Name; + SfxItemPropertyMapEntry const* pEntry = rPropSet.getPropertyMap().getByName(rPropertyName); + + if (!pEntry) + { + // unknown property + break; + } + else if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + break; + } + else if (rPropertyName == "NumberingRules") + { + aWhichPairs = aWhichPairs.MergeRange(RES_PARATR_NUMRULE, RES_PARATR_NUMRULE); + nNumId = aEntries.size(); + } + else + { + aWhichPairs = aWhichPairs.MergeRange(pEntry->nWID, pEntry->nWID); + if (rPropertyName == "ParaStyleName") + nStyleId = aEntries.size(); + } + aEntries.push_back(pEntry); + aValues.push_back(rRevertProperty.Value); + } + + if (!aWhichPairs.empty()) + { + sal_uInt16 nStylePoolId = USHRT_MAX; + OUString sParaStyleName, sUIStyle; + SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aWhichPairs)); + + for (size_t i = 0; i < aEntries.size(); ++i) + { + const uno::Any &rValue = aValues[i]; + if (i == nNumId) + { + uno::Reference<container::XNamed> xNumberingRules; + rValue >>= xNumberingRules; + if (xNumberingRules.is()) + { + aItemSet.Put( SwNumRuleItem( xNumberingRules->getName() )); + // keep it during export + SwNumRule* pRule = rDoc.FindNumRulePtr( + xNumberingRules->getName()); + if (pRule) + pRule->SetUsedByRedline(true); + } + } + else + { + SfxItemPropertyMapEntry const*const pEntry = aEntries[i]; + rPropSet.setPropertyValue(*pEntry, rValue, aItemSet); + if (i == nStyleId) + rValue >>= sParaStyleName; + } + } + + if (eType == RedlineType::ParagraphFormat && sParaStyleName.isEmpty()) + nStylePoolId = RES_POOLCOLL_STANDARD; + + // tdf#149747 Get UI style name from programmatic style name + SwStyleNameMapper::FillUIName(sParaStyleName, sUIStyle, + SwGetPoolIdFromName::TxtColl); + xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl( + sUIStyle.isEmpty() ? sParaStyleName : sUIStyle, nStylePoolId, &aItemSet)); + } + else if (eType == RedlineType::ParagraphFormat) + xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl( "", RES_POOLCOLL_STANDARD, nullptr )); + } + } + + SwRangeRedline* pRedline = new SwRangeRedline( aRedlineData, rPaM ); + + // set IsMoved bit of the redline to show and handle moved text + if ( nMovedID > 0 ) + { + pRedline->SetMoved( nMovedID ); + rRedlineAccess.GetRedlineTable().setMovedIDIfNeeded(nMovedID); + } + + RedlineFlags nPrevMode = rRedlineAccess.GetRedlineFlags( ); + // xRedlineExtraData is copied here + pRedline->SetExtraData( xRedlineExtraData.get() ); + + rRedlineAccess.SetRedlineFlags_intern(RedlineFlags::On); + auto const result(rRedlineAccess.AppendRedline(pRedline, false)); + rRedlineAccess.SetRedlineFlags_intern( nPrevMode ); + if (IDocumentRedlineAccess::AppendResult::IGNORED == result) + throw lang::IllegalArgumentException(); +} + +void makeTableRowRedline( SwTableLine& rTableLine, + std::u16string_view rRedlineType, + const uno::Sequence< beans::PropertyValue >& rRedlineProperties ) +{ + SwDoc* pDoc = rTableLine.GetFrameFormat()->GetDoc(); + IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess(); + + RedlineType eType; + if ( rRedlineType == u"TableRowInsert" ) + { + eType = RedlineType::TableRowInsert; + } + else if ( rRedlineType == u"TableRowDelete" ) + { + eType = RedlineType::TableRowDelete; + } + else + { + throw lang::IllegalArgumentException(); + } + + // set table row property "HasTextChangesOnly" to false + // to handle tracked deletion or insertion of the table row on the UI + const SvxPrintItem *pHasTextChangesOnlyProp = + rTableLine.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); + if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() ) + { + SvxPrintItem aSetTracking(RES_PRINT, false); + SwNodeIndex aInsPos( *(rTableLine.GetTabBoxes()[0]->GetSttNd()), 1 ); + // as a workaround for the rows without text content, + // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR + if ( rTableLine.IsEmpty() ) + { + SwPaM aPaM(aInsPos); + pDoc->getIDocumentContentOperations().InsertString( aPaM, + OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) ); + aPaM.SetMark(); + aPaM.GetMark()->SetContent(0); + makeRedline(aPaM, RedlineType::TableRowInsert == eType + ? u"Insert" + : u"Delete", rRedlineProperties); + } + SwCursor aCursor( SwPosition(aInsPos), nullptr ); + pDoc->SetRowNotTracked( aCursor, aSetTracking ); + } + + comphelper::SequenceAsHashMap aPropMap( rRedlineProperties ); + std::size_t nAuthor = 0; + OUString sAuthor; + if( aPropMap.getValue("RedlineAuthor") >>= sAuthor ) + nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor); + + OUString sComment; + SwRedlineData aRedlineData( eType, nAuthor ); + if( aPropMap.getValue("RedlineComment") >>= sComment ) + aRedlineData.SetComment( sComment ); + + ::util::DateTime aStamp; + if( aPropMap.getValue("RedlineDateTime") >>= aStamp ) + { + aRedlineData.SetTimeStamp( + DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) ); + } + + SwTableRowRedline* pRedline = new SwTableRowRedline( aRedlineData, rTableLine ); + RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( ); + pRedline->SetExtraData( nullptr ); + + pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On); + bool bRet = pRedlineAccess->AppendTableRowRedline( pRedline ); + pRedlineAccess->SetRedlineFlags_intern( nPrevMode ); + if( !bRet ) + throw lang::IllegalArgumentException(); +} + +void makeTableCellRedline( SwTableBox& rTableBox, + std::u16string_view rRedlineType, + const uno::Sequence< beans::PropertyValue >& rRedlineProperties ) +{ + SwDoc* pDoc = rTableBox.GetFrameFormat()->GetDoc(); + IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess(); + + RedlineType eType; + if ( rRedlineType == u"TableCellInsert" ) + { + eType = RedlineType::TableCellInsert; + } + else if ( rRedlineType == u"TableCellDelete" ) + { + eType = RedlineType::TableCellDelete; + } + else + { + throw lang::IllegalArgumentException(); + } + + // set table row property "HasTextChangesOnly" to false + // to handle tracked deletion or insertion of the table row on the UI + const SvxPrintItem *pHasTextChangesOnlyProp = + rTableBox.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); + if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() ) + { + SvxPrintItem aSetTracking(RES_PRINT, false); + SwNodeIndex aInsPos( *rTableBox.GetSttNd(), 1 ); + // as a workaround for the cells without text content, + // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR + if ( rTableBox.IsEmpty() ) + { + SwPaM aPaM(aInsPos); + pDoc->getIDocumentContentOperations().InsertString( aPaM, + OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) ); + aPaM.SetMark(); + aPaM.GetMark()->SetContent(0); + makeRedline(aPaM, RedlineType::TableCellInsert == eType + ? u"Insert" + : u"Delete", rRedlineProperties); + } + SwCursor aCursor( SwPosition(aInsPos), nullptr ); + pDoc->SetBoxAttr( aCursor, aSetTracking ); + } + + comphelper::SequenceAsHashMap aPropMap( rRedlineProperties ); + std::size_t nAuthor = 0; + OUString sAuthor; + if( aPropMap.getValue("RedlineAuthor") >>= sAuthor ) + nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor); + + OUString sComment; + SwRedlineData aRedlineData( eType, nAuthor ); + if( aPropMap.getValue("RedlineComment") >>= sComment ) + aRedlineData.SetComment( sComment ); + + ::util::DateTime aStamp; + if( aPropMap.getValue("RedlineDateTime") >>= aStamp ) + { + aRedlineData.SetTimeStamp( + DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) ); + } + + SwTableCellRedline* pRedline = new SwTableCellRedline( aRedlineData, rTableBox ); + RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( ); + pRedline->SetExtraData( nullptr ); + + pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On); + bool bRet = pRedlineAccess->AppendTableCellRedline( pRedline ); + pRedlineAccess->SetRedlineFlags_intern( nPrevMode ); + if( !bRet ) + throw lang::IllegalArgumentException(); +} + +void SwAnyMapHelper::SetValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rAny ) +{ + sal_uInt32 nKey = (nWhichId << 16) + nMemberId; + m_Map[nKey] = rAny; +} + +bool SwAnyMapHelper::FillValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& pAny ) +{ + bool bRet = false; + sal_uInt32 nKey = (nWhichId << 16) + nMemberId; + auto aIt = m_Map.find( nKey ); + if (aIt != m_Map.end()) + { + pAny = & aIt->second; + bRet = true; + } + return bRet; +} + +}//namespace SwUnoCursorHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx new file mode 100644 index 0000000000..5bb5621d95 --- /dev/null +++ b/sw/source/core/unocore/unodraw.cxx @@ -0,0 +1,2876 @@ +/* -*- 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 <sal/config.h> + +#include <initializer_list> +#include <memory> +#include <string_view> + +#include <sal/log.hxx> + +#include <cmdid.h> +#include <unomid.h> + +#include <drawdoc.hxx> +#include <unodraw.hxx> +#include <unoframe.hxx> +#include <unoparagraph.hxx> +#include <unotextrange.hxx> +#include <svx/svditer.hxx> +#include <swunohelper.hxx> +#include <textboxhelper.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <fmtcntnt.hxx> +#include <fmtflcnt.hxx> +#include <txatbase.hxx> +#include <docsh.hxx> +#include <unomap.hxx> +#include <unoport.hxx> +#include <TextCursorHelper.hxx> +#include <dflyobj.hxx> +#include <ndtxt.hxx> +#include <svx/svdview.hxx> +#include <svx/unoshape.hxx> +#include <dcontact.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <fmtfollowtextflow.hxx> +#include <rootfrm.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <crstate.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/profilezone.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svx/scene3d.hxx> +#include <tools/UnitConversion.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <docmodel/uno/UnoTheme.hxx> + +using namespace ::com::sun::star; + +class SwShapeDescriptor_Impl +{ + bool m_isInReading; + std::unique_ptr<SwFormatHoriOrient> m_pHOrient; + std::unique_ptr<SwFormatVertOrient> m_pVOrient; + std::unique_ptr<SwFormatAnchor> m_pAnchor; + std::unique_ptr<SwFormatSurround> m_pSurround; + std::unique_ptr<SvxULSpaceItem> m_pULSpace; + std::unique_ptr<SvxLRSpaceItem> m_pLRSpace; + bool m_bOpaque; + uno::Reference< text::XTextRange > m_xTextRange; + // #i26791# + std::unique_ptr<SwFormatFollowTextFlow> m_pFollowTextFlow; + // #i28701# + std::unique_ptr<SwFormatWrapInfluenceOnObjPos> m_pWrapInfluenceOnObjPos; + // #i28749# + sal_Int16 mnPositionLayoutDir; + + SwShapeDescriptor_Impl(const SwShapeDescriptor_Impl&) = delete; + SwShapeDescriptor_Impl& operator=(const SwShapeDescriptor_Impl&) = delete; + +public: + SwShapeDescriptor_Impl(SwDoc const*const pDoc) + : m_isInReading(pDoc && pDoc->IsInReading()) + // #i32349# - no defaults, in order to determine on + // adding a shape, if positioning attributes are set or not. + , m_bOpaque(false) + // #i26791# + , m_pFollowTextFlow( new SwFormatFollowTextFlow(false) ) + // #i28701# #i35017# + , m_pWrapInfluenceOnObjPos( new SwFormatWrapInfluenceOnObjPos( + text::WrapInfluenceOnPosition::ONCE_CONCURRENT) ) + // #i28749# + , mnPositionLayoutDir(text::PositionLayoutDir::PositionInLayoutDirOfAnchor) + {} + + SwFormatAnchor* GetAnchor(bool bCreate = false) + { + if (bCreate && !m_pAnchor) + { + m_pAnchor.reset(new SwFormatAnchor(RndStdIds::FLY_AS_CHAR)); + } + return m_pAnchor.get(); + } + SwFormatHoriOrient* GetHOrient(bool bCreate = false) + { + if (bCreate && !m_pHOrient) + { + // #i26791# + m_pHOrient.reset(new SwFormatHoriOrient(0, text::HoriOrientation::NONE, text::RelOrientation::FRAME)); + } + return m_pHOrient.get(); + } + SwFormatVertOrient* GetVOrient(bool bCreate = false) + { + if (bCreate && !m_pVOrient) + { + if (m_isInReading && // tdf#113938 extensions might rely on old default + (!GetAnchor(true) || m_pAnchor->GetAnchorId() == RndStdIds::FLY_AS_CHAR)) + { // for as-char, NONE ("from-top") is not a good default + m_pVOrient.reset(new SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME)); + } + else + { // #i26791# + m_pVOrient.reset(new SwFormatVertOrient(0, text::VertOrientation::NONE, text::RelOrientation::FRAME)); + } + } + return m_pVOrient.get(); + } + + SwFormatSurround* GetSurround(bool bCreate = false) + { + if (bCreate && !m_pSurround) + { + m_pSurround.reset(new SwFormatSurround()); + } + return m_pSurround.get(); + } + SvxLRSpaceItem* GetLRSpace(bool bCreate = false) + { + if (bCreate && !m_pLRSpace) + { + m_pLRSpace.reset(new SvxLRSpaceItem(RES_LR_SPACE)); + } + return m_pLRSpace.get(); + } + SvxULSpaceItem* GetULSpace(bool bCreate = false) + { + if (bCreate && !m_pULSpace) + { + m_pULSpace.reset(new SvxULSpaceItem(RES_UL_SPACE)); + } + return m_pULSpace.get(); + } + uno::Reference< text::XTextRange > & GetTextRange() + { + return m_xTextRange; + } + bool IsOpaque() const + { + return m_bOpaque; + } + const bool& GetOpaque() const + { + return m_bOpaque; + } + void RemoveHOrient() { m_pHOrient.reset(); } + void RemoveVOrient() { m_pVOrient.reset(); } + void RemoveAnchor() { m_pAnchor.reset(); } + void RemoveSurround() { m_pSurround.reset(); } + void RemoveULSpace() { m_pULSpace.reset(); } + void RemoveLRSpace() { m_pLRSpace.reset(); } + void SetOpaque(bool bSet){m_bOpaque = bSet;} + + // #i26791# + SwFormatFollowTextFlow* GetFollowTextFlow( bool _bCreate = false ) + { + if (_bCreate && !m_pFollowTextFlow) + { + m_pFollowTextFlow.reset(new SwFormatFollowTextFlow(false)); + } + return m_pFollowTextFlow.get(); + } + void RemoveFollowTextFlow() + { + m_pFollowTextFlow.reset(); + } + + // #i28749# + sal_Int16 GetPositionLayoutDir() const + { + return mnPositionLayoutDir; + } + void SetPositionLayoutDir( sal_Int16 _nPositionLayoutDir ) + { + switch ( _nPositionLayoutDir ) + { + case text::PositionLayoutDir::PositionInHoriL2R: + case text::PositionLayoutDir::PositionInLayoutDirOfAnchor: + { + mnPositionLayoutDir = _nPositionLayoutDir; + } + break; + default: + { + OSL_FAIL( "<SwShapeDescriptor_Impl::SetPositionLayoutDir(..)> - invalid attribute value." ); + } + } + } + + // #i28701# + SwFormatWrapInfluenceOnObjPos* GetWrapInfluenceOnObjPos( + const bool _bCreate = false ) + { + if (_bCreate && !m_pWrapInfluenceOnObjPos) + { + m_pWrapInfluenceOnObjPos.reset(new SwFormatWrapInfluenceOnObjPos( + // #i35017# + text::WrapInfluenceOnPosition::ONCE_CONCURRENT)); + } + return m_pWrapInfluenceOnObjPos.get(); + } + void RemoveWrapInfluenceOnObjPos() + { + m_pWrapInfluenceOnObjPos.reset(); + } +}; + +SwFmDrawPage::SwFmDrawPage( SwDoc* pDoc, SdrPage* pPage ) + : SwFmDrawPage_Base(pPage) + , m_pDoc(pDoc) + , m_pPageView(nullptr) + , m_pPropertySet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_PAGE)) +{ +} + +SwFmDrawPage::~SwFmDrawPage() noexcept +{ + while (!m_vShapes.empty()) + m_vShapes.back()->dispose(); + RemovePageView(); +} + +const SdrMarkList& SwFmDrawPage::PreGroup(const uno::Reference< drawing::XShapes > & xShapes) +{ + SelectObjectsInView( xShapes, GetPageView() ); + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + return rMarkList; +} + +void SwFmDrawPage::PreUnGroup(const uno::Reference< drawing::XShapeGroup >& rShapeGroup) +{ + SelectObjectInView( rShapeGroup, GetPageView() ); +} + +SdrPageView* SwFmDrawPage::GetPageView() +{ + if(!m_pPageView) + m_pPageView = mpView->ShowSdrPage( mpPage ); + return m_pPageView; +} + +void SwFmDrawPage::RemovePageView() +{ + if(m_pPageView && mpView) + mpView->HideSdrPage(); + m_pPageView = nullptr; +} + +uno::Reference<drawing::XShape> SwFmDrawPage::GetShape(SdrObject* pObj) +{ + if(!pObj) + return nullptr; + SwFrameFormat* pFormat = ::FindFrameFormat( pObj ); + // TODO see comment at + // <https://gerrit.libreoffice.org/c/core/+/78734/4#message-5ee4e724a8073c5c475f07da0b5d79bc34e61de5> + // "make page bookkeep the SwXShapes" [-loplugin:crosscast]: + SwFmDrawPage* pPage = dynamic_cast<SwFmDrawPage*>(pFormat); + if(!pPage || pPage->m_vShapes.empty()) + return uno::Reference<drawing::XShape>(pObj->getUnoShape(), uno::UNO_QUERY); + for(const auto & pShape : pPage->m_vShapes) + { + SvxShape* pSvxShape = pShape->GetSvxShape(); + if (pSvxShape && pSvxShape->GetSdrObject() == pObj) + return pShape; + } + return nullptr; +} + +uno::Reference<drawing::XShapeGroup> SwFmDrawPage::GetShapeGroup(SdrObject* pObj) +{ + return uno::Reference<drawing::XShapeGroup>(GetShape(pObj), uno::UNO_QUERY); +} + +uno::Reference< drawing::XShape > SwFmDrawPage::CreateShape( SdrObject *pObj ) const +{ + uno::Reference< drawing::XShape > xRet; + if(dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr || pObj->GetObjInventor() == SdrInventor::Swg) + { + SwFlyDrawContact* pFlyContact = static_cast<SwFlyDrawContact*>(pObj->GetUserCall()); + if(pFlyContact) + { + SwFrameFormat* pFlyFormat = pFlyContact->GetFormat(); + SwDoc* pDoc = pFlyFormat->GetDoc(); + const SwNodeIndex* pIdx; + if( RES_FLYFRMFMT == pFlyFormat->Which() + && nullptr != ( pIdx = pFlyFormat->GetContent().GetContentIdx() ) + && pIdx->GetNodes().IsDocNodes() + ) + { + const SwNode* pNd = pDoc->GetNodes()[ pIdx->GetIndex() + 1 ]; + if(!pNd->IsNoTextNode()) + { + xRet.set(cppu::getXWeak(SwXTextFrame::CreateXTextFrame(*pDoc, pFlyFormat).get()), + uno::UNO_QUERY); + } + else if( pNd->IsGrfNode() ) + { + xRet.set(cppu::getXWeak(SwXTextGraphicObject::CreateXTextGraphicObject( + *pDoc, pFlyFormat).get()), uno::UNO_QUERY); + } + else if( pNd->IsOLENode() ) + { + xRet.set(cppu::getXWeak(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + *pDoc, pFlyFormat).get()), uno::UNO_QUERY); + } + } + else + { + OSL_FAIL( "<SwFmDrawPage::CreateShape(..)> - could not retrieve type. Thus, no shape created." ); + return xRet; + } + } + } + else + { + // own block - temporary object has to be destroyed before + // the delegator is set #81670# + { + xRet = SvxDrawPage::CreateShape( pObj ); + } + uno::Reference< XUnoTunnel > xShapeTunnel(xRet, uno::UNO_QUERY); + //don't create an SwXShape if it already exists + rtl::Reference<SwXShape> pShape = comphelper::getFromUnoTunnel<SwXShape>(xShapeTunnel); + if(!pShape) + { + xShapeTunnel = nullptr; + uno::Reference< uno::XInterface > xCreate(xRet, uno::UNO_QUERY); + xRet = nullptr; + if ( pObj->IsGroupObject() && (!pObj->Is3DObj() || DynCastE3dScene(pObj)) ) + pShape = new SwXGroupShape(xCreate, nullptr); + else + pShape = new SwXShape(xCreate, nullptr); + xRet = pShape; + } + const_cast<std::vector<rtl::Reference<SwXShape>>*>(&m_vShapes)->push_back(pShape); + pShape->m_pPage = this; + } + return xRet; +} + +uno::Reference<beans::XPropertySetInfo> SwFmDrawPage::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRet = m_pPropertySet->getPropertySetInfo(); + return xRet; +} + +void SwFmDrawPage::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName(rPropertyName); + + switch (pEntry ? pEntry->nWID : -1) + { + case WID_PAGE_THEME: + { + SdrPage* pPage = GetSdrPage(); + css::uno::Reference<css::util::XTheme> xTheme; + if (aValue >>= xTheme) + { + auto& rUnoTheme = dynamic_cast<UnoTheme&>(*xTheme); + pPage->getSdrModelFromSdrPage().setTheme(rUnoTheme.getTheme()); + } + } + break; + case WID_PAGE_BOTTOM: + case WID_PAGE_LEFT: + case WID_PAGE_RIGHT: + case WID_PAGE_TOP: + case WID_PAGE_WIDTH: + case WID_PAGE_HEIGHT: + case WID_PAGE_NUMBER: + case WID_PAGE_ORIENT: + case WID_PAGE_USERATTRIBS: + case WID_PAGE_ISDARK: + case WID_NAVORDER: + case WID_PAGE_BACKFULL: + break; + + default: + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + } +} + +uno::Any SwFmDrawPage::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName); + + uno::Any aAny; + + switch (pEntry ? pEntry->nWID : -1) + { + case WID_PAGE_THEME: + { + css::uno::Reference<css::util::XTheme> xTheme; + + auto pTheme = GetSdrPage()->getSdrModelFromSdrPage().getTheme(); + if (pTheme) + xTheme = model::theme::createXTheme(pTheme); + aAny <<= xTheme; + } + break; + + case WID_PAGE_NUMBER: + { + const sal_uInt16 nPageNumber(GetSdrPage()->GetPageNum()); + aAny <<= o3tl::narrowing<sal_Int16>(nPageNumber); + } + break; + + case WID_PAGE_BOTTOM: + case WID_PAGE_LEFT: + case WID_PAGE_RIGHT: + case WID_PAGE_TOP: + case WID_PAGE_WIDTH: + case WID_PAGE_HEIGHT: + case WID_PAGE_ORIENT: + case WID_PAGE_USERATTRIBS: + case WID_PAGE_ISDARK: + case WID_NAVORDER: + case WID_PAGE_BACKFULL: + break; + + default: + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + } + return aAny; +} + +void SwFmDrawPage::addPropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XPropertyChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::removePropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XPropertyChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::addVetoableChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XVetoableChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::removeVetoableChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XVetoableChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +namespace +{ + class SwXShapesEnumeration + : public SwSimpleEnumeration_Base + { + private: + std::vector< css::uno::Any > m_aShapes; + protected: + virtual ~SwXShapesEnumeration() override {}; + public: + explicit SwXShapesEnumeration(SwFmDrawPage* const pDrawPage); + + //XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual uno::Any SAL_CALL nextElement() override; + + //XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + }; +} + +SwXShapesEnumeration::SwXShapesEnumeration(SwFmDrawPage* const pDrawPage) +{ + SolarMutexGuard aGuard; + sal_Int32 nCount = pDrawPage->getCount(); + m_aShapes.reserve(nCount); + for(sal_Int32 nIdx = 0; nIdx < nCount; nIdx++) + { + uno::Reference<drawing::XShape> xShape(pDrawPage->getByIndex(nIdx), uno::UNO_QUERY); + m_aShapes.push_back(uno::Any(xShape)); + } +} + +sal_Bool SwXShapesEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + return !m_aShapes.empty(); +} + +uno::Any SwXShapesEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + if(m_aShapes.empty()) + throw container::NoSuchElementException(); + uno::Any aResult = m_aShapes.back(); + m_aShapes.pop_back(); + return aResult; +} + +OUString SwXShapesEnumeration::getImplementationName() +{ + return "SwXShapeEnumeration"; +} + +sal_Bool SwXShapesEnumeration::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence< OUString > SwXShapesEnumeration::getSupportedServiceNames() +{ + return { OUString("com.sun.star.container.XEnumeration") }; +} + +uno::Reference< container::XEnumeration > SwFmDrawPage::createEnumeration() +{ + SolarMutexGuard aGuard; + return uno::Reference< container::XEnumeration >( + new SwXShapesEnumeration(this)); +} + +OUString SwFmDrawPage::getImplementationName() +{ + return "SwFmDrawPage"; +} + +sal_Bool SwFmDrawPage::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwFmDrawPage::getSupportedServiceNames() +{ + return { "com.sun.star.drawing.GenericDrawPage" }; +} + +sal_Int32 SwFmDrawPage::getCount() +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + return 0; + else + return SwTextBoxHelper::getCount(GetSdrPage()); +} + +uno::Any SwFmDrawPage::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + throw lang::IndexOutOfBoundsException(); + + return SwTextBoxHelper::getByIndex(GetSdrPage(), nIndex); +} + +uno::Type SwFmDrawPage::getElementType() +{ + return cppu::UnoType<drawing::XShape>::get(); +} + +sal_Bool SwFmDrawPage::hasElements() +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + return false; + return SvxDrawPage::hasElements(); +} + +void SwFmDrawPage::add(const uno::Reference< drawing::XShape > & xShape) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + uno::Reference< lang::XUnoTunnel > xShapeTunnel(xShape, uno::UNO_QUERY); + SwXShape* pShape = comphelper::getFromUnoTunnel<SwXShape>(xShapeTunnel); + SvxShape* pSvxShape = comphelper::getFromUnoTunnel<SvxShape>(xShapeTunnel); + + // this is not a writer shape + if(!pShape) + throw uno::RuntimeException("illegal object", + getXWeak() ); + + // we're already registered in the model / SwXDrawPage::add() already called + if(pShape->m_pPage || !pShape->m_bDescriptor ) + return; + + // we're inserted elsewhere already + if ( pSvxShape->GetSdrObject() ) + { + if ( pSvxShape->GetSdrObject()->IsInserted() ) + { + return; + } + } + SvxDrawPage::add(xShape); + + OSL_ENSURE(pSvxShape, "Why is here no SvxShape?"); + // this position is definitely in 1/100 mm + awt::Point aMM100Pos(pSvxShape->getPosition()); + + // now evaluate the properties of SwShapeDescriptor_Impl + SwShapeDescriptor_Impl* pDesc = pShape->GetDescImpl(); + + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aSet( m_pDoc->GetAttrPool() ); + SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR ); + bool bOpaque = false; + if( pDesc ) + { + if(pDesc->GetSurround()) + aSet.Put( *pDesc->GetSurround()); + // all items are already in Twip + if(pDesc->GetLRSpace()) + { + aSet.Put(*pDesc->GetLRSpace()); + } + if(pDesc->GetULSpace()) + { + aSet.Put(*pDesc->GetULSpace()); + } + if(pDesc->GetAnchor()) + aAnchor = *pDesc->GetAnchor(); + + // #i32349# - if no horizontal position exists, create one + if ( !pDesc->GetHOrient() ) + { + SwFormatHoriOrient* pHori = pDesc->GetHOrient( true ); + SwTwips nHoriPos = o3tl::toTwips(aMM100Pos.X, o3tl::Length::mm100); + pHori->SetPos( nHoriPos ); + } + { + if(pDesc->GetHOrient()->GetHoriOrient() == text::HoriOrientation::NONE) + aMM100Pos.X = convertTwipToMm100(pDesc->GetHOrient()->GetPos()); + aSet.Put( *pDesc->GetHOrient() ); + } + // #i32349# - if no vertical position exists, create one + if ( !pDesc->GetVOrient() ) + { + SwFormatVertOrient* pVert = pDesc->GetVOrient( true ); + SwTwips nVertPos = o3tl::toTwips(aMM100Pos.Y, o3tl::Length::mm100); + pVert->SetPos( nVertPos ); + } + { + if(pDesc->GetVOrient()->GetVertOrient() == text::VertOrientation::NONE) + aMM100Pos.Y = convertTwipToMm100(pDesc->GetVOrient()->GetPos()); + aSet.Put( *pDesc->GetVOrient() ); + } + + if(pDesc->GetSurround()) + aSet.Put( *pDesc->GetSurround()); + bOpaque = pDesc->IsOpaque(); + + // #i26791# + if ( pDesc->GetFollowTextFlow() ) + { + aSet.Put( *pDesc->GetFollowTextFlow() ); + } + + // #i28701# + if ( pDesc->GetWrapInfluenceOnObjPos() ) + { + aSet.Put( *pDesc->GetWrapInfluenceOnObjPos() ); + } + } + + pSvxShape->setPosition(aMM100Pos); + SdrObject* pObj = pSvxShape->GetSdrObject(); + // #108784# - set layer of new drawing object to corresponding + // invisible layer. + if(SdrInventor::FmForm != pObj->GetObjInventor()) + pObj->SetLayer( bOpaque ? m_pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() : m_pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + else + pObj->SetLayer(m_pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + + std::optional<SwPaM> pPam(m_pDoc->GetNodes().GetEndOfContent()); + std::unique_ptr<SwUnoInternalPaM> pInternalPam; + uno::Reference< text::XTextRange > xRg; + if( pDesc && (xRg = pDesc->GetTextRange()).is() ) + { + pInternalPam.reset(new SwUnoInternalPaM(*m_pDoc)); + if (!::sw::XTextRangeToSwPaM(*pInternalPam, xRg)) + throw uno::RuntimeException(); + + if(RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId() && + !pInternalPam->GetPointNode().FindFlyStartNode()) + { + aAnchor.SetType(RndStdIds::FLY_AS_CHAR); + } + else if (RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() + && 0 == aAnchor.GetPageNum()) + { + aAnchor.SetAnchor(pInternalPam->Start()); + aAnchor.SetType(RndStdIds::FLY_AT_CHAR); // convert invalid at-page + } + + } + else if ((aAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp(o3tl::toTwips(aMM100Pos.X, o3tl::Length::mm100), o3tl::toTwips(aMM100Pos.Y, o3tl::Length::mm100)); + m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( pPam->GetPoint(), aTmp, &aState ); + aAnchor.SetAnchor( pPam->GetPoint() ); + + // #i32349# - adjustment of vertical positioning + // attributes no longer needed, because it's already got a default. + } + else + { + aAnchor.SetType(RndStdIds::FLY_AT_PAGE); + + // #i32349# - adjustment of vertical positioning + // attributes no longer needed, because it's already got a default. + } + aSet.Put(aAnchor); + SwPaM* pTemp = pInternalPam.get(); + if ( !pTemp ) + pTemp = &*pPam; + UnoActionContext aAction(m_pDoc); + m_pDoc->getIDocumentContentOperations().InsertDrawObj( *pTemp, *pObj, aSet ); + + if (pSvxShape->GetSdrObject()->GetName().isEmpty()) + { + pSvxShape->GetSdrObject()->SetName(m_pDoc->GetUniqueShapeName()); + } + + SwFrameFormat* pFormat = ::FindFrameFormat( pObj ); + if (pFormat) + { + if (pFormat->GetName().isEmpty()) + { + pFormat->SetFormatName(pSvxShape->GetSdrObject()->GetName(), false); + } + } + pShape->m_bDescriptor = false; + + pPam.reset(); + pInternalPam.reset(); +} + +void SwFmDrawPage::remove(const uno::Reference< drawing::XShape > & xShape) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + // tdf#41466 remove TextFrame too which is belonged to the actual shape + auto xTextFrame = SwTextBoxHelper::getUnoTextFrame(xShape); + if (xTextFrame) + { + uno::Reference<lang::XComponent> xComp(xTextFrame, uno::UNO_QUERY); + if (xComp) + xComp->dispose(); + } + // remove shape + uno::Reference<lang::XComponent> xComp(xShape, uno::UNO_QUERY); + xComp->dispose(); +} + +uno::Reference< drawing::XShapeGroup > SwFmDrawPage::group(const uno::Reference< drawing::XShapes > & xShapes) +{ + SolarMutexGuard aGuard; + if(!m_pDoc || !xShapes.is()) + throw uno::RuntimeException(); + uno::Reference< drawing::XShapeGroup > xRet; + // mark and return MarkList + const SdrMarkList& rMarkList = PreGroup(xShapes); + if ( rMarkList.GetMarkCount() > 0 ) + { + for (size_t i = 0; i < rMarkList.GetMarkCount(); ++i) + { + const SdrObject *pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if (RndStdIds::FLY_AS_CHAR == ::FindFrameFormat(const_cast<SdrObject*>( + pObj))->GetAnchor().GetAnchorId()) + { + throw lang::IllegalArgumentException( + "Shape must not have 'as character' anchor!", nullptr, 0); + } + } + + UnoActionContext aContext(m_pDoc); + m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + + SwDrawContact* pContact = m_pDoc->GroupSelection( *GetDrawView() ); + m_pDoc->ChgAnchor( + GetDrawView()->GetMarkedObjectList(), + RndStdIds::FLY_AT_PARA, + true, false ); + + GetDrawView()->UnmarkAll(); + if(pContact) + xRet = SwFmDrawPage::GetShapeGroup( pContact->GetMaster() ); + m_pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } + RemovePageView(); + return xRet; +} + +void SwFmDrawPage::ungroup(const uno::Reference< drawing::XShapeGroup > & rShapeGroup) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + + PreUnGroup(rShapeGroup); + UnoActionContext aContext(m_pDoc); + m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + + m_pDoc->UnGroupSelection( *GetDrawView() ); + m_pDoc->ChgAnchor( GetDrawView()->GetMarkedObjectList(), + RndStdIds::FLY_AT_PARA, + true, false ); + m_pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + RemovePageView(); +} + +/** + * Renamed and outlined to detect where it's called + */ +void SwFmDrawPage::InvalidateSwDoc() +{ + m_pDoc = nullptr; +} + +const uno::Sequence< sal_Int8 > & SwXShape::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theSwXShapeUnoTunnelId; + return theSwXShapeUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SwXShape::getSomething( const uno::Sequence< sal_Int8 >& rId ) +{ + if( comphelper::isUnoTunnelId<SwXShape>(rId) ) + { + return comphelper::getSomething_cast(this); + } + + if( m_xShapeAgg.is() ) + { + const uno::Type& rTunnelType = cppu::UnoType<lang::XUnoTunnel>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rTunnelType ); + if(auto xAggTunnel = o3tl::tryAccess<uno::Reference<lang::XUnoTunnel>>( + aAgg)) + { + if(xAggTunnel->is()) + return (*xAggTunnel)->getSomething(rId); + } + } + return 0; +} + +SwXShape::SwXShape( + uno::Reference<uno::XInterface> & xShape, + SwDoc const*const pDoc) + : m_pPage(nullptr) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_SHAPE)) + , m_pPropertyMapEntries(aSwMapProvider.GetPropertyMapEntries(PROPERTY_MAP_TEXT_SHAPE)) + , m_pImpl(new SwShapeDescriptor_Impl(pDoc)) + , m_bDescriptor(true) +{ + if(!xShape.is()) // default Ctor + return; + + const uno::Type& rAggType = cppu::UnoType<uno::XAggregation>::get(); + //aAgg contains a reference of the SvxShape! + { + uno::Any aAgg = xShape->queryInterface(rAggType); + aAgg >>= m_xShapeAgg; + // #i31698# + if ( m_xShapeAgg.is() ) + { + m_xShapeAgg->queryAggregation( cppu::UnoType<drawing::XShape>::get()) >>= mxShape; + OSL_ENSURE( mxShape.is(), + "<SwXShape::SwXShape(..)> - no XShape found at <xShapeAgg>" ); + } + } + xShape = nullptr; + osl_atomic_increment(&m_refCount); + if( m_xShapeAgg.is() ) + m_xShapeAgg->setDelegator( getXWeak() ); + osl_atomic_decrement(&m_refCount); +} + +SwFrameFormat* SwXShape::GetFrameFormat() const +{ + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(m_xShapeAgg); + if(pObj) + return ::FindFrameFormat( pObj ); + return nullptr; +} + +void SwXShape::AddExistingShapeToFormat( SdrObject const & _rObj ) +{ + SdrObjListIter aIter( _rObj, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pCurrent = aIter.Next(); + OSL_ENSURE( pCurrent, "SwXShape::AddExistingShapeToFormat: invalid object list element!" ); + if ( !pCurrent ) + continue; + + auto pSwShape = comphelper::getFromUnoTunnel<SwXShape>(pCurrent->getWeakUnoShape()); + if ( pSwShape ) + { + if ( pSwShape->m_bDescriptor ) + pSwShape->m_bDescriptor = false; + } + } +} + +SwXShape::~SwXShape() +{ + SolarMutexGuard aGuard; + + if (m_xShapeAgg.is()) + { + uno::Reference< uno::XInterface > xRef; + m_xShapeAgg->setDelegator(xRef); + } + m_pImpl.reset(); + if(m_pPage) + const_cast<SwFmDrawPage*>(m_pPage)->RemoveShape(this); +} + +uno::Any SwXShape::queryInterface( const uno::Type& aType ) +{ + uno::Any aRet; + SdrObject* pObj = nullptr; + + if ((aType == cppu::UnoType<text::XText>::get()) + || (aType == cppu::UnoType<text::XTextRange>::get()) + || (aType == cppu::UnoType<text::XTextAppend>::get())) + { + pObj = SdrObject::getSdrObjectFromXShape(mxShape); + + aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType, pObj); + if (aRet.hasValue()) + return aRet; + } + aRet = SwXShapeBaseClass::queryInterface(aType); + // #i53320# - follow-up of #i31698# + // interface drawing::XShape is overloaded. Thus, provide + // correct object instance. + if(!aRet.hasValue() && m_xShapeAgg.is()) + { + if(aType == cppu::UnoType<XShape>::get()) + aRet <<= uno::Reference<XShape>(this); + else + aRet = m_xShapeAgg->queryAggregation(aType); + } + return aRet; +} + +uno::Sequence< uno::Type > SwXShape::getTypes( ) +{ + uno::Sequence< uno::Type > aRet = SwXShapeBaseClass::getTypes(); + if(m_xShapeAgg.is()) + { + uno::Any aProv = m_xShapeAgg->queryAggregation(cppu::UnoType<XTypeProvider>::get()); + if(aProv.hasValue()) + { + uno::Reference< XTypeProvider > xAggProv; + aProv >>= xAggProv; + return comphelper::concatSequences(aRet, xAggProv->getTypes()); + } + } + return aRet; +} + +uno::Sequence< sal_Int8 > SwXShape::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Reference< beans::XPropertySetInfo > SwXShape::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + if (!mxPropertySetInfo) + { + if(m_xShapeAgg.is()) + { + const uno::Type& rPropSetType = cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation( rPropSetType ); + if(auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>( + aPSet)) + { + uno::Reference< beans::XPropertySetInfo > xInfo = (*xPrSet)->getPropertySetInfo(); + // Expand PropertySetInfo! + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + mxPropertySetInfo = new SfxExtItemPropertySetInfo( m_pPropertyMapEntries, aPropSeq ); + } + } + if(!mxPropertySetInfo) + mxPropertySetInfo = m_pPropSet->getPropertySetInfo(); + } + return mxPropertySetInfo; +} + +void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(!m_xShapeAgg.is()) + return; + + if(pEntry) + { + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException ("Property is read-only: " + rPropertyName, getXWeak() ); + // with the layout it is possible to move the anchor without changing the position + if(pFormat) + { + SwAttrSet aSet(pFormat->GetAttrSet()); + SwDoc* pDoc = pFormat->GetDoc(); + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORFRAME == pEntry->nMemberId) + { + bool bDone = false; + uno::Reference<text::XTextFrame> xFrame; + if(aValue >>= xFrame) + { + SwXFrame* pFrame = dynamic_cast<SwXFrame*>(xFrame.get()); + if(pFrame && pFrame->GetFrameFormat() && + pFrame->GetFrameFormat()->GetDoc() == pDoc) + { + UnoActionContext aCtx(pDoc); + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aItemSet( pDoc->GetAttrPool() ); + aItemSet.SetParent(&pFormat->GetAttrSet()); + SwFormatAnchor aAnchor = static_cast<const SwFormatAnchor&>(aItemSet.Get(pEntry->nWID)); + SwPosition aPos(*pFrame->GetFrameFormat()->GetContent().GetContentIdx()); + aAnchor.SetAnchor(&aPos); + aAnchor.SetType(RndStdIds::FLY_AT_FLY); + aItemSet.Put(aAnchor); + pFormat->SetFormatAttr(aItemSet); + bDone = true; + } + } + if(!bDone) + throw lang::IllegalArgumentException(); + } + else if(RES_OPAQUE == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + // set layer of new drawing + // object to corresponding invisible layer. + bool bIsVisible = pDoc->getIDocumentDrawModelAccess().IsVisibleLayerId( pObj->GetLayer() ); + if(SdrInventor::FmForm != pObj->GetObjInventor()) + { + pObj->SetLayer( *o3tl::doAccess<bool>(aValue) + ? ( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetHeavenId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() ) + : ( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetHellId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() )); + } + else + { + pObj->SetLayer( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetControlsId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + } + + } + + } + // #i26791# - special handling for property FN_TEXT_RANGE + else if ( FN_TEXT_RANGE == pEntry->nWID ) + { + SwFormatAnchor aAnchor( aSet.Get( RES_ANCHOR ) ); + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + // set property <TextRange> not valid for to-page anchored shapes + throw lang::IllegalArgumentException(); + } + + std::unique_ptr<SwUnoInternalPaM> pInternalPam( + new SwUnoInternalPaM( *(pFormat->GetDoc()) )); + uno::Reference< text::XTextRange > xRg; + aValue >>= xRg; + if (!::sw::XTextRangeToSwPaM(*pInternalPam, xRg) ) + { + throw uno::RuntimeException(); + } + + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + //delete old SwFormatFlyCnt + //With AnchorAsCharacter the current TextAttribute has to be deleted. + //Tbis removes the frame format too. + //To prevent this the connection between format and attribute has to be broken before. + SwTextNode *pTextNode = aAnchor.GetAnchorNode()->GetTextNode(); + SAL_WARN_IF( !pTextNode->HasHints(), "sw.uno", "Missing FlyInCnt-Hint." ); + const sal_Int32 nIdx = aAnchor.GetAnchorContentOffset(); + SwTextAttr * const pHint = + pTextNode->GetTextAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + assert(pHint && "Missing Hint."); + SAL_WARN_IF( pHint->Which() != RES_TXTATR_FLYCNT, + "sw.uno", "Missing FlyInCnt-Hint." ); + SAL_WARN_IF( pHint->GetFlyCnt().GetFrameFormat() != pFormat, + "sw.uno", "Wrong TextFlyCnt-Hint." ); + const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()) + .SetFlyFormat(); + + //The connection is removed now the attribute can be deleted. + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx ); + //create a new one + SwTextNode *pNd = pInternalPam->GetPointNode().GetTextNode(); + SAL_WARN_IF( !pNd, "sw.uno", "Cursor not at TextNode." ); + SwFormatFlyCnt aFormat( pFormat ); + pNd->InsertItem(aFormat, pInternalPam->GetPoint() + ->GetContentIndex(), 0 ); + //Refetch in case SwTextNode::InsertItem causes it to be deleted + pFormat = GetFrameFormat(); + } + else + { + aAnchor.SetAnchor( pInternalPam->GetPoint() ); + aSet.Put(aAnchor); + pFormat->SetFormatAttr(aSet); + } + } + else if (pEntry->nWID == FN_TEXT_BOX) + { + auto pObj = SdrObject::getSdrObjectFromXShape(mxShape); + if (pEntry->nMemberId == MID_TEXT_BOX) + { + bool bValue(false); + aValue >>= bValue; + + if (bValue) + SwTextBoxHelper::create(pFormat, pObj); + else + SwTextBoxHelper::destroy(pFormat, pObj); + } + else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT) + { + if (aValue.getValueType() + == cppu::UnoType<uno::Reference<text::XTextFrame>>::get()) + SwTextBoxHelper::set(pFormat, pObj, + aValue.get<uno::Reference<text::XTextFrame>>()); + else + SAL_WARN( "sw.uno", "This is not a TextFrame!" ); + } + } + else if (pEntry->nWID == RES_CHAIN) + { + if (pEntry->nMemberId == MID_CHAIN_NEXTNAME || pEntry->nMemberId == MID_CHAIN_PREVNAME) + SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + // #i28749# + else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID ) + { + sal_Int16 nPositionLayoutDir = 0; + aValue >>= nPositionLayoutDir; + pFormat->SetPositionLayoutDir( nPositionLayoutDir ); + } + else if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout()) + { + UnoActionContext aCtx(pDoc); + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORTYPE == pEntry->nMemberId) + { + SdrObject* pObj = pFormat->FindSdrObject(); + SdrMarkList aList; + SdrMark aMark(pObj); + aList.InsertEntry(aMark); + sal_Int32 nAnchor = 0; + cppu::enum2int( nAnchor, aValue ); + pDoc->ChgAnchor( aList, static_cast<RndStdIds>(nAnchor), + false, true ); + } + else + { + m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + pFormat->SetFormatAttr(aSet); + } + } + else if( RES_FRM_SIZE == pEntry->nWID && + ( pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT || pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH + || pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION + || pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION ) ) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + sal_Int16 nPercent(100); + aValue >>= nPercent; + switch (pEntry->nMemberId) + { + case MID_FRMSIZE_REL_WIDTH: + pObj->SetRelativeWidth( nPercent / 100.0 ); + break; + case MID_FRMSIZE_REL_HEIGHT: + pObj->SetRelativeHeight( nPercent / 100.0 ); + break; + case MID_FRMSIZE_REL_WIDTH_RELATION: + pObj->SetRelativeWidthRelation(nPercent); + break; + case MID_FRMSIZE_REL_HEIGHT_RELATION: + pObj->SetRelativeHeightRelation(nPercent); + break; + } + } + } + else if (pEntry->nWID == RES_HORI_ORIENT + && pEntry->nMemberId == MID_HORIORIENT_RELATION + && aSet.Get(RES_ANCHOR).GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + uno::Any value(aValue); + sal_Int16 nRelOrient(text::RelOrientation::PAGE_FRAME); + aValue >>= nRelOrient; + if (sw::GetAtPageRelOrientation(nRelOrient, true)) + { + SAL_WARN("sw.core", "SwXShape: fixing invalid horizontal RelOrientation for at-page anchor"); + value <<= nRelOrient; + } + m_pPropSet->setPropertyValue( *pEntry, value, aSet ); + pFormat->SetFormatAttr(aSet); + } + else + { + m_pPropSet->setPropertyValue( *pEntry, aValue, aSet ); + + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORTYPE == pEntry->nMemberId) + { + bool bSetAttr = true; + text::TextContentAnchorType eNewAnchor = static_cast<text::TextContentAnchorType>(SWUnoHelper::GetEnumAsInt32( aValue )); + + //if old anchor was in_cntnt the related text attribute has to be removed + const SwFormatAnchor& rOldAnchor = pFormat->GetAnchor(); + RndStdIds eOldAnchorId = rOldAnchor.GetAnchorId(); + SdrObject* pObj = pFormat->FindSdrObject(); + SwFrameFormat *pFlyFormat = FindFrameFormat( pObj ); + pFlyFormat->DelFrames(); + if( text::TextContentAnchorType_AS_CHARACTER != eNewAnchor && + (RndStdIds::FLY_AS_CHAR == eOldAnchorId)) + { + //With AnchorAsCharacter the current TextAttribute has to be deleted. + //Tbis removes the frame format too. + //To prevent this the connection between format and attribute has to be broken before. + SwTextNode *pTextNode = rOldAnchor.GetAnchorNode()->GetTextNode(); + SAL_WARN_IF( !pTextNode->HasHints(), "sw.uno", "Missing FlyInCnt-Hint." ); + const sal_Int32 nIdx = rOldAnchor.GetAnchorContentOffset(); + SwTextAttr * const pHint = + pTextNode->GetTextAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + assert(pHint && "Missing Hint."); + SAL_WARN_IF( pHint->Which() != RES_TXTATR_FLYCNT, + "sw.uno", "Missing FlyInCnt-Hint." ); + SAL_WARN_IF( pHint->GetFlyCnt().GetFrameFormat() != pFlyFormat, + "sw.uno", "Wrong TextFlyCnt-Hint." ); + const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()) + .SetFlyFormat(); + + //The connection is removed now the attribute can be deleted. + pTextNode->DeleteAttributes(RES_TXTATR_FLYCNT, nIdx); + } + else if( text::TextContentAnchorType_AT_PAGE != eNewAnchor && + (RndStdIds::FLY_AT_PAGE == eOldAnchorId)) + { + SwFormatAnchor aNewAnchor( aSet.Get( RES_ANCHOR ) ); + //if the fly has been anchored at page then it needs to be connected + //to the content position + SwPaM aPam(pDoc->GetNodes().GetEndOfContent()); + if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp( pObj->GetSnapRect().TopLeft() ); + pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmp, &aState ); + } + else + { + //without access to the layout the last node of the body will be used as anchor position + aPam.Move( fnMoveBackward, GoInDoc ); + } + //anchor position has to be inserted after the text attribute has been inserted + aNewAnchor.SetAnchor( aPam.GetPoint() ); + aSet.Put( aNewAnchor ); + pFormat->SetFormatAttr(aSet); + bSetAttr = false; + } + if( text::TextContentAnchorType_AS_CHARACTER == eNewAnchor && + (RndStdIds::FLY_AS_CHAR != eOldAnchorId)) + { + SwPaM aPam(pDoc->GetNodes().GetEndOfContent()); + if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp( pObj->GetSnapRect().TopLeft() ); + pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmp, &aState ); + } + else + { + //without access to the layout the last node of the body will be used as anchor position + aPam.Move( fnMoveBackward, GoInDoc ); + } + //the RES_TXTATR_FLYCNT needs to be added now + SwTextNode *pNd = aPam.GetPointNode().GetTextNode(); + SAL_WARN_IF( !pNd, "sw.uno", "Cursor is not in a TextNode." ); + SwFormatFlyCnt aFormat( pFlyFormat ); + pNd->InsertItem(aFormat, + aPam.GetPoint()->GetContentIndex(), 0 ); + aPam.GetPoint()->AdjustContent(-1); // InsertItem moved it + SwFormatAnchor aNewAnchor( + aSet.Get(RES_ANCHOR)); + aNewAnchor.SetAnchor( aPam.GetPoint() ); + aSet.Put( aNewAnchor ); + } + if( bSetAttr ) + pFormat->SetFormatAttr(aSet); + + // If this property is an anchor change, and there is a group shape with textboxes + // do anchor sync in time unless the anchor sync in the porfly will cause crash during + // layout calculation (When importing an inline shape in docx via dmapper). + if (pFormat->Which() == RES_DRAWFRMFMT && pFormat->GetOtherTextBoxFormats()) + { + SwTextBoxHelper::synchronizeGroupTextBoxProperty( + SwTextBoxHelper::changeAnchor, pFormat, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + } + else + pFormat->SetFormatAttr(aSet); + } + + // We have a pFormat and a pEntry as well: try to sync TextBox property. + SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(true); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(true); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(true); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(true); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(true); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(true); + break; + case FN_TEXT_RANGE: + if(auto tr = o3tl::tryAccess< + uno::Reference<text::XTextRange>>(aValue)) + { + uno::Reference< text::XTextRange > & rRange = m_pImpl->GetTextRange(); + rRange = *tr; + } + break; + case RES_OPAQUE : + m_pImpl->SetOpaque(*o3tl::doAccess<bool>(aValue)); + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW: + { + pItem = m_pImpl->GetFollowTextFlow( true ); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos( true ); + } + break; + // #i28749# + case FN_SHAPE_POSITION_LAYOUT_DIR : + { + sal_Int16 nPositionLayoutDir = 0; + aValue >>= nPositionLayoutDir; + m_pImpl->SetPositionLayoutDir( nPositionLayoutDir ); + } + break; + } + if(pItem) + pItem->PutValue(aValue, pEntry->nMemberId); + } + } + else + { + const uno::Type& rPSetType = + cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation(rPSetType); + auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>( + aPSet); + if(!xPrSet) + throw uno::RuntimeException(); + // #i31698# - setting the caption point of a + // caption object doesn't have to change the object position. + // Thus, keep the position, before the caption point is set and + // restore it afterwards. + awt::Point aKeepedPosition( 0, 0 ); + if ( rPropertyName == "CaptionPoint" && getShapeType() == "com.sun.star.drawing.CaptionShape" ) + { + aKeepedPosition = getPosition(); + } + if( pFormat && pFormat->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() ) + { + UnoActionContext aCtx(pFormat->GetDoc()); + (*xPrSet)->setPropertyValue(rPropertyName, aValue); + } + else + (*xPrSet)->setPropertyValue(rPropertyName, aValue); + + if (pFormat) + { + // We have a pFormat (but no pEntry): try to sync TextBox property. + SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + + // #i31698# - restore object position, if caption point is set. + if ( rPropertyName == "CaptionPoint" && getShapeType() == "com.sun.star.drawing.CaptionShape" ) + { + setPosition( aKeepedPosition ); + } + } +} + +uno::Any SwXShape::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat* pFormat = GetFrameFormat(); + if(m_xShapeAgg.is()) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if(pFormat) + { + if(RES_OPAQUE == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE(pSvxShape, "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + // consider invisible layers + aRet <<= + ( pObj->GetLayer() != pFormat->GetDoc()->getIDocumentDrawModelAccess().GetHellId() && + pObj->GetLayer() != pFormat->GetDoc()->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + } + } + else if(FN_ANCHOR_POSITION == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE(pSvxShape, "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + Point aPt = pObj->GetAnchorPos(); + awt::Point aPoint( convertTwipToMm100( aPt.X() ), + convertTwipToMm100( aPt.Y() ) ); + aRet <<= aPoint; + } + } + // #i26791# - special handling for FN_TEXT_RANGE + else if ( FN_TEXT_RANGE == pEntry->nWID ) + { + const SwFormatAnchor aAnchor = pFormat->GetAnchor(); + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + // return nothing, because property <TextRange> isn't + // valid for to-page anchored shapes + uno::Any aAny; + aRet = aAny; + } + else + { + if ( aAnchor.GetAnchorNode() ) + { + const rtl::Reference<SwXTextRange> xTextRange + = SwXTextRange::CreateXTextRange( + *pFormat->GetDoc(), + *aAnchor.GetContentAnchor(), + nullptr ); + aRet <<= uno::Reference<text::XTextRange>(xTextRange); + } + else + { + // return nothing + uno::Any aAny; + aRet = aAny; + } + } + } + else if (pEntry->nWID == FN_TEXT_BOX) + { + if (pEntry->nMemberId == MID_TEXT_BOX) + { + auto pSvxShape = GetSvxShape(); + bool bValue = SwTextBoxHelper::isTextBox( + pFormat, RES_DRAWFRMFMT, + ((pSvxShape && pSvxShape->GetSdrObject()) ? pSvxShape->GetSdrObject() + : pFormat->FindRealSdrObject())); + aRet <<= bValue; + } + else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT) + { + auto pObj = SdrObject::getSdrObjectFromXShape(mxShape); + auto xRange = SwTextBoxHelper::queryInterface( + pFormat, cppu::UnoType<text::XText>::get(), + pObj ? pObj : pFormat->FindRealSdrObject()); + uno::Reference<text::XTextFrame> xFrame(xRange, uno::UNO_QUERY); + if (xFrame.is()) + aRet <<= xFrame; + } + } + else if (pEntry->nWID == RES_CHAIN) + { + switch (pEntry->nMemberId) + { + case MID_CHAIN_PREVNAME: + case MID_CHAIN_NEXTNAME: + case MID_CHAIN_NAME: + SwTextBoxHelper::getProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aRet); + break; + } + } + // #i28749# + else if ( FN_SHAPE_TRANSFORMATION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::Transformation> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "Transformation" ); + } + else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID ) + { + aRet <<= pFormat->GetPositionLayoutDir(); + } + // #i36248# + else if ( FN_SHAPE_STARTPOSITION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "StartPosition" ); + } + else if ( FN_SHAPE_ENDPOSITION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::EndPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "EndPosition" ); + } + else if (pEntry->nWID == RES_FRM_SIZE && + (pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH || + pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION)) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + sal_Int16 nRet = 0; + if (pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + switch (pEntry->nMemberId) + { + case MID_FRMSIZE_REL_WIDTH: + if (pObj->GetRelativeWidth()) + nRet = *pObj->GetRelativeWidth() * 100; + break; + case MID_FRMSIZE_REL_HEIGHT: + if (pObj->GetRelativeHeight()) + nRet = *pObj->GetRelativeHeight() * 100; + break; + case MID_FRMSIZE_REL_WIDTH_RELATION: + nRet = pObj->GetRelativeWidthRelation(); + break; + case MID_FRMSIZE_REL_HEIGHT_RELATION: + nRet = pObj->GetRelativeHeightRelation(); + break; + } + } + aRet <<= nRet; + } + else + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); + } + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(); + break; + case FN_TEXT_RANGE : + aRet <<= m_pImpl->GetTextRange(); + break; + case RES_OPAQUE : + aRet <<= m_pImpl->GetOpaque(); + break; + case FN_ANCHOR_POSITION : + { + aRet <<= awt::Point(); + } + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW : + { + pItem = m_pImpl->GetFollowTextFlow(); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos(); + } + break; + // #i28749# + case FN_SHAPE_TRANSFORMATION_IN_HORI_L2R: + { + // get property <::drawing::Shape::Transformation> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "Transformation" ); + } + break; + case FN_SHAPE_POSITION_LAYOUT_DIR: + { + aRet <<= m_pImpl->GetPositionLayoutDir(); + } + break; + // #i36248# + case FN_SHAPE_STARTPOSITION_IN_HORI_L2R: + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "StartPosition" ); + } + break; + case FN_SHAPE_ENDPOSITION_IN_HORI_L2R: + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "EndPosition" ); + } + break; + } + if(pItem) + pItem->QueryValue(aRet, pEntry->nMemberId); + } + } + else + { + aRet = _getPropAtAggrObj( rPropertyName ); + + // #i31698# - convert the position (translation) + // of the drawing object in the transformation + if ( rPropertyName == "Transformation" ) + { + drawing::HomogenMatrix3 aMatrix; + aRet >>= aMatrix; + aRet <<= ConvertTransformationToLayoutDir( aMatrix ); + } + // #i36248# + else if ( rPropertyName == "StartPosition" ) + { + awt::Point aStartPos; + aRet >>= aStartPos; + // #i59051# + aRet <<= ConvertStartOrEndPosToLayoutDir( aStartPos ); + } + else if ( rPropertyName == "EndPosition" ) + { + awt::Point aEndPos; + aRet >>= aEndPos; + // #i59051# + aRet <<= ConvertStartOrEndPosToLayoutDir( aEndPos ); + } + // #i59051# + else if ( rPropertyName == "PolyPolygonBezier" ) + { + drawing::PolyPolygonBezierCoords aPath; + aRet >>= aPath; + aRet <<= ConvertPolyPolygonBezierToLayoutDir( aPath ); + } + else if (rPropertyName == "ZOrder") + { + // Convert the real draw page position to the logical one that ignores textboxes. + if (pFormat) + { + const SdrObject* pObj = pFormat->FindRealSdrObject(); + if (pObj) + { + bool bConvert = true; + if (SvxShape* pSvxShape = GetSvxShape()) + // In case of group shapes, pSvxShape points to the child shape, while pObj points to the outermost group shape. + if (pSvxShape->GetSdrObject() != pObj) + // Textboxes are not expected inside group shapes, so no conversion is necessary there. + bConvert = false; + if (bConvert) + { + aRet <<= SwTextBoxHelper::getOrdNum(pObj); + } + } + } + } + } + } + return aRet; +} + +uno::Any SwXShape::_getPropAtAggrObj( const OUString& _rPropertyName ) +{ + uno::Any aRet; + + const uno::Type& rPSetType = + cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation(rPSetType); + auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>(aPSet); + if ( !xPrSet ) + { + throw uno::RuntimeException(); + } + aRet = (*xPrSet)->getPropertyValue( _rPropertyName ); + + return aRet; +} + +beans::PropertyState SwXShape::getPropertyState( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Sequence< OUString > aNames { rPropertyName }; + uno::Sequence< beans::PropertyState > aStates = getPropertyStates(aNames); + return aStates.getConstArray()[0]; +} + +uno::Sequence< beans::PropertyState > SwXShape::getPropertyStates( + const uno::Sequence< OUString >& aPropertyNames ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + uno::Sequence< beans::PropertyState > aRet(aPropertyNames.getLength()); + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + SvxShape* pSvxShape = GetSvxShape(); + bool bGroupMember = false; + bool bFormControl = false; + SdrObject* pObject = pSvxShape ? pSvxShape->GetSdrObject() : nullptr; + if(pObject) + { + bGroupMember = pObject->getParentSdrObjectFromSdrObject() != nullptr; + bFormControl = pObject->GetObjInventor() == SdrInventor::FmForm; + } + const OUString* pNames = aPropertyNames.getConstArray(); + beans::PropertyState* pRet = aRet.getArray(); + uno::Reference< XPropertyState > xShapePrState; + for(sal_Int32 nProperty = 0; nProperty < aPropertyNames.getLength(); nProperty++) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( pNames[nProperty] ); + if(pEntry) + { + if(RES_OPAQUE == pEntry->nWID) + pRet[nProperty] = bFormControl ? + beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + else if(FN_ANCHOR_POSITION == pEntry->nWID) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(FN_TEXT_RANGE == pEntry->nWID) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(bGroupMember) + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + else if (pEntry->nWID == RES_FRM_SIZE && + (pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION)) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if (pEntry->nWID == FN_TEXT_BOX) + { + // The TextBox property is set, if we can find a textbox for this shape. + if (pFormat + && SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, + SdrObject::getSdrObjectFromXShape(mxShape))) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + } + else if(pFormat) + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + SfxItemState eItemState = rSet.GetItemState(pEntry->nWID, false); + + if(SfxItemState::SET == eItemState) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(SfxItemState::DEFAULT == eItemState) + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + else + pRet[nProperty] = beans::PropertyState_AMBIGUOUS_VALUE; + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(); + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos(); + } + break; + } + if(pItem) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + } + } + else + { + if(!xShapePrState.is()) + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto ps = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!ps) + throw uno::RuntimeException(); + xShapePrState = *ps; + } + pRet[nProperty] = xShapePrState->getPropertyState(pNames[nProperty]); + } + } + + return aRet; +} + +void SwXShape::setPropertyToDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw uno::RuntimeException("Property is read-only: " + rPropertyName, getXWeak() ); + if(pFormat) + { + const SfxItemSet& rSet = pFormat->GetAttrSet(); + SfxItemSet aSet(pFormat->GetDoc()->GetAttrPool(), pEntry->nWID, pEntry->nWID); + aSet.SetParent(&rSet); + aSet.ClearItem(pEntry->nWID); + pFormat->GetDoc()->SetAttr(aSet, *pFormat); + } + else + { + switch(pEntry->nWID) + { + case RES_ANCHOR: m_pImpl->RemoveAnchor(); break; + case RES_HORI_ORIENT: m_pImpl->RemoveHOrient(); break; + case RES_VERT_ORIENT: m_pImpl->RemoveVOrient(); break; + case RES_LR_SPACE: m_pImpl->RemoveLRSpace(); break; + case RES_UL_SPACE: m_pImpl->RemoveULSpace(); break; + case RES_SURROUND: m_pImpl->RemoveSurround();break; + case RES_OPAQUE : m_pImpl->SetOpaque(false); break; + case FN_TEXT_RANGE : + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW: + { + m_pImpl->RemoveFollowTextFlow(); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + m_pImpl->RemoveWrapInfluenceOnObjPos(); + } + break; + } + } + } + else + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto xShapePrState = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!xShapePrState) + throw uno::RuntimeException(); + (*xShapePrState)->setPropertyToDefault( rPropertyName ); + } + +} + +uno::Any SwXShape::getPropertyDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + uno::Any aRet; + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if(!(pEntry->nWID < RES_FRMATR_END && pFormat)) + throw uno::RuntimeException(); + + const SfxPoolItem& rDefItem = + pFormat->GetDoc()->GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(aRet, pEntry->nMemberId); + + } + else + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto xShapePrState = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!xShapePrState) + throw uno::RuntimeException(); + (*xShapePrState)->getPropertyDefault( rPropertyName ); + } + + return aRet; +} + +void SwXShape::addPropertyChangeListener( + const OUString& _propertyName, + const uno::Reference< beans::XPropertyChangeListener > & _listener ) +{ + if ( !m_xShapeAgg.is() ) + throw uno::RuntimeException("no shape aggregate", *this ); + + // must be handled by the aggregate + uno::Reference< beans::XPropertySet > xShapeProps; + if ( m_xShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get() ) >>= xShapeProps ) + xShapeProps->addPropertyChangeListener( _propertyName, _listener ); +} + +void SwXShape::removePropertyChangeListener( + const OUString& _propertyName, + const uno::Reference< beans::XPropertyChangeListener > & _listener) +{ + if ( !m_xShapeAgg.is() ) + throw uno::RuntimeException("no shape aggregate", *this ); + + // must be handled by the aggregate + uno::Reference< beans::XPropertySet > xShapeProps; + if ( m_xShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get() ) >>= xShapeProps ) + xShapeProps->removePropertyChangeListener( _propertyName, _listener ); +} + +void SwXShape::addVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +void SwXShape::removeVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXShape::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + // get access to SwDoc + // (see also SwXTextRange::XTextRangeToSwPaM) + const SwDoc* pDoc = nullptr; + if (auto pRange = dynamic_cast<SwXTextRange*>(xTextRange.get())) + pDoc = &pRange->GetDoc(); + else if (auto pText = dynamic_cast<SwXText*>(xTextRange.get())) + pDoc = pText->GetDoc(); + else if (auto pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get())) + pDoc = pCursor->GetDoc(); + else if (auto pPortion = dynamic_cast<SwXTextPortion*>(xTextRange.get())) + pDoc = &pPortion->GetCursor().GetDoc(); + else if (auto pParagraph = dynamic_cast<SwXParagraph*>(xTextRange.get()); + pParagraph && pParagraph->GetTextNode()) + pDoc = &pParagraph->GetTextNode()->GetDoc(); + + if(!pDoc) + throw uno::RuntimeException(); + const SwDocShell* pDocSh = pDoc->GetDocShell(); + if (!pDocSh) + return; + + uno::Reference<frame::XModel> xModel = pDocSh->GetModel(); + uno::Reference< drawing::XDrawPageSupplier > xDPS(xModel, uno::UNO_QUERY); + if (xDPS.is()) + { + uno::Reference< drawing::XDrawPage > xDP( xDPS->getDrawPage() ); + if (xDP.is()) + { + uno::Any aPos; + aPos <<= xTextRange; + setPropertyValue("TextRange", aPos); + uno::Reference< drawing::XShape > xTemp( getXWeak(), uno::UNO_QUERY ); + xDP->add( xTemp ); + } + } +} + +uno::Reference< text::XTextRange > SwXShape::getAnchor() +{ + SolarMutexGuard aGuard; + uno::Reference< text::XTextRange > aRef; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); + // return an anchor for non-page bound frames + // and for page bound frames that have a page no == NULL and a content position + if ((rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) || + (rAnchor.GetAnchorNode() && !rAnchor.GetPageNum())) + { + if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) + { // ensure that SwXTextRange has SwContentIndex + const SwNode* pAnchorNode = rAnchor.GetAnchorNode(); + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), SwPosition(*pAnchorNode), nullptr); + } + else + { + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), *rAnchor.GetContentAnchor(), nullptr); + } + } + } + else + aRef = m_pImpl->GetTextRange().get(); + return aRef; +} + +void SwXShape::dispose() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + // determine correct <SdrObject> + SvxShape* pSvxShape = GetSvxShape(); + SdrObject* pObj = pSvxShape ? pSvxShape->GetSdrObject() : nullptr; + // safety assertion: + // <pObj> must be the same as <pFormat->FindSdrObject()>, if <pObj> isn't + // a 'virtual' drawing object. + // correct assertion and refine it for safety reason. + OSL_ENSURE( !pObj || + dynamic_cast<const SwDrawVirtObj*>( pObj) != nullptr || + pObj->getParentSdrObjectFromSdrObject() || + pObj == pFormat->FindSdrObject(), + "<SwXShape::dispose(..) - different 'master' drawing objects!!" ); + // perform delete of draw frame format *not* + // for 'virtual' drawing objects. + // no delete of draw format for members + // of a group + if ( pObj && + dynamic_cast<const SwDrawVirtObj*>( pObj) == nullptr && + !pObj->getParentSdrObjectFromSdrObject() && + pObj->IsInserted() ) + { + const SwFormatAnchor& rFormatAnchor = pFormat->GetAnchor(); + if (rFormatAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + SwTextNode *pTextNode = rFormatAnchor.GetAnchorNode()->GetTextNode(); + const sal_Int32 nIdx = rFormatAnchor.GetAnchorContentOffset(); + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx ); + } + else + pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); + } + } + if(m_xShapeAgg.is()) + { + uno::Any aAgg(m_xShapeAgg->queryAggregation( cppu::UnoType<XComponent>::get())); + uno::Reference<XComponent> xComp; + aAgg >>= xComp; + if(xComp.is()) + xComp->dispose(); + } + if(m_pPage) + { + auto pPage = const_cast<SwFmDrawPage*>(m_pPage); + m_pPage = nullptr; + pPage->RemoveShape(this); + } +} + +void SwXShape::addEventListener( + const uno::Reference< lang::XEventListener > & aListener) +{ + SvxShape* pSvxShape = GetSvxShape(); + if(pSvxShape) + pSvxShape->addEventListener(aListener); +} + +void SwXShape::removeEventListener( + const uno::Reference< lang::XEventListener > & aListener) +{ + SvxShape* pSvxShape = GetSvxShape(); + if(pSvxShape) + pSvxShape->removeEventListener(aListener); +} + +OUString SwXShape::getImplementationName() +{ + return "SwXShape"; +} + +sal_Bool SwXShape::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXShape::getSupportedServiceNames() +{ + uno::Sequence< OUString > aSeq; + if (SvxShape* pSvxShape = GetSvxShape()) + aSeq = pSvxShape->getSupportedServiceNames(); + return comphelper::concatSequences( + aSeq, std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape" }); +} + +SvxShape* SwXShape::GetSvxShape() +{ + if(m_xShapeAgg.is()) + return comphelper::getFromUnoTunnel<SvxShape>(m_xShapeAgg); + return nullptr; +} + +// #i31698# +// implementation of virtual methods from drawing::XShape +awt::Point SAL_CALL SwXShape::getPosition() +{ + awt::Point aPos( GetAttrPosition() ); + + // handle group members + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + SdrObject* pTopGroupObj = GetTopGroupObj( pSvxShape ); + if ( pTopGroupObj ) + { + // #i34750# - get attribute position of top group + // shape and add offset between top group object and group member + uno::Reference< drawing::XShape > xGroupShape( pTopGroupObj->getUnoShape(), uno::UNO_QUERY ); + aPos = xGroupShape->getPosition(); + // add offset between top group object and group member + // to the determined attribute position + // #i34750#: + // consider the layout direction + const tools::Rectangle aMemberObjRect = GetSvxShape()->GetSdrObject()->GetSnapRect(); + const tools::Rectangle aGroupObjRect = pTopGroupObj->GetSnapRect(); + // #i53320# - relative position of group member and + // top group object is always given in horizontal left-to-right layout. + awt::Point aOffset( 0, 0 ); + { + aOffset.X = ( aMemberObjRect.Left() - aGroupObjRect.Left() ); + aOffset.Y = ( aMemberObjRect.Top() - aGroupObjRect.Top() ); + } + aOffset.X = convertTwipToMm100(aOffset.X); + aOffset.Y = convertTwipToMm100(aOffset.Y); + aPos.X += aOffset.X; + aPos.Y += aOffset.Y; + } + } + + return aPos; +} + +void SAL_CALL SwXShape::setPosition( const awt::Point& aPosition ) +{ + SdrObject* pTopGroupObj = GetTopGroupObj(); + if ( !pTopGroupObj ) + { + // #i37877# - no adjustment of position attributes, + // if the position also has to be applied at the drawing object and + // a contact object is already registered at the drawing object. + bool bApplyPosAtDrawObj(false); + bool bNoAdjustOfPosProp(false); + // #i35798# - apply position also to drawing object, + // if drawing object has no anchor position set. + if ( mxShape.is() ) + { + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + if ( pObj && + pObj->GetAnchorPos().X() == 0 && + pObj->GetAnchorPos().Y() == 0 ) + { + bApplyPosAtDrawObj = true; + if ( pObj->GetUserCall() && + dynamic_cast<const SwDrawContact*>( pObj->GetUserCall()) != nullptr ) + { + bNoAdjustOfPosProp = true; + } + } + } + } + // shape isn't a group member. Thus, set positioning attributes + if ( !bNoAdjustOfPosProp ) + { + AdjustPositionProperties( aPosition ); + } + if ( bApplyPosAtDrawObj ) + { + mxShape->setPosition( aPosition ); + } + } + else if ( mxShape.is() ) + { + // shape is a member of a group. Thus, set its position. + awt::Point aNewPos( aPosition ); + // The given position is given in the according layout direction. Thus, + // it has to be converted to a position in horizontal left-to-right + // layout. + // convert given absolute attribute position in layout direction into + // position in horizontal left-to-right layout. + { + aNewPos = ConvertPositionToHoriL2R( aNewPos, getSize() ); + } + // Convert given absolute position in horizontal left-to-right + // layout into relative position in horizontal left-to-right layout. + uno::Reference< drawing::XShape > xGroupShape( pTopGroupObj->getUnoShape(), uno::UNO_QUERY ); + { + // #i34750# + // use method <xGroupShape->getPosition()> to get the correct + // position of the top group object. + awt::Point aAttrPosInHoriL2R( + ConvertPositionToHoriL2R( xGroupShape->getPosition(), + xGroupShape->getSize() ) ); + aNewPos.X = o3tl::saturating_sub(aNewPos.X, aAttrPosInHoriL2R.X); + aNewPos.Y = o3tl::saturating_sub(aNewPos.Y, aAttrPosInHoriL2R.Y); + } + // convert relative position in horizontal left-to-right layout into + // absolute position in horizontal left-to-right layout + { + // #i34750# + // use method <SvxShape->getPosition()> to get the correct + // 'Drawing layer' position of the top group shape. + auto pSvxGroupShape = comphelper::getFromUnoTunnel<SvxShape>(pTopGroupObj->getUnoShape()); + const awt::Point aGroupPos = pSvxGroupShape->getPosition(); + aNewPos.X = o3tl::saturating_add(aNewPos.X, aGroupPos.X); + aNewPos.Y = o3tl::saturating_add(aNewPos.Y, aGroupPos.Y); + } + // set position + mxShape->setPosition( aNewPos ); + } +} + +awt::Size SAL_CALL SwXShape::getSize() +{ + awt::Size aSize; + if ( mxShape.is() ) + { + aSize = mxShape->getSize(); + } + return aSize; +} + +void SAL_CALL SwXShape::setSize( const awt::Size& aSize ) +{ + comphelper::ProfileZone aZone("SwXShape::setSize"); + + if ( mxShape.is() ) + { + mxShape->setSize( aSize ); + } + SwTextBoxHelper::syncProperty(GetFrameFormat(), RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any(aSize)); +} +// #i31698# +// implementation of virtual methods from drawing::XShapeDescriptor +OUString SAL_CALL SwXShape::getShapeType() +{ + if ( mxShape.is() ) + { + return mxShape->getShapeType(); + } + return OUString(); +} +/** method to determine top group object + #i31698# +*/ +SdrObject* SwXShape::GetTopGroupObj( SvxShape* _pSvxShape ) +{ + SdrObject* pTopGroupObj( nullptr ); + + SvxShape* pSvxShape = _pSvxShape ? _pSvxShape : GetSvxShape(); + if ( pSvxShape ) + { + SdrObject* pSdrObj = pSvxShape->GetSdrObject(); + if ( pSdrObj && pSdrObj->getParentSdrObjectFromSdrObject() ) + { + pTopGroupObj = pSdrObj->getParentSdrObjectFromSdrObject(); + while ( pTopGroupObj->getParentSdrObjectFromSdrObject() ) + { + pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject(); + } + } + } + + return pTopGroupObj; +} + +/** method to determine position according to the positioning attributes + #i31698# +*/ +awt::Point SwXShape::GetAttrPosition() +{ + awt::Point aAttrPos; + + uno::Any aHoriPos( getPropertyValue("HoriOrientPosition") ); + aHoriPos >>= aAttrPos.X; + uno::Any aVertPos( getPropertyValue("VertOrientPosition") ); + aVertPos >>= aAttrPos.Y; + // #i35798# - fallback, if attribute position is (0,0) + // and no anchor position is applied to the drawing object + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + if ( pObj && + pObj->GetAnchorPos().X() == 0 && + pObj->GetAnchorPos().Y() == 0 && + aAttrPos.X == 0 && aAttrPos.Y == 0 ) + { + const tools::Rectangle aObjRect = pObj->GetSnapRect(); + aAttrPos.X = convertTwipToMm100(aObjRect.Left()); + aAttrPos.Y = convertTwipToMm100(aObjRect.Top()); + } + } + // #i35007# - If drawing object is anchored as-character, + // it's x-position isn't sensible. Thus, return the x-position as zero in this case. + text::TextContentAnchorType eTextAnchorType = + text::TextContentAnchorType_AT_PARAGRAPH; + { + uno::Any aAny = getPropertyValue( "AnchorType" ); + aAny >>= eTextAnchorType; + } + if ( eTextAnchorType == text::TextContentAnchorType_AS_CHARACTER ) + { + aAttrPos.X = 0; + } + + return aAttrPos; +} + +/** method to convert the position (translation) of the drawing object to + the layout direction horizontal left-to-right. + #i31698# +*/ +awt::Point SwXShape::ConvertPositionToHoriL2R( const awt::Point& rObjPos, + const awt::Size& rObjSize ) +{ + awt::Point aObjPosInHoriL2R( rObjPos ); + + SwFrameFormat* pFrameFormat = GetFrameFormat(); + if ( pFrameFormat ) + { + SwFrameFormat::tLayoutDir eLayoutDir = pFrameFormat->GetLayoutDir(); + switch ( eLayoutDir ) + { + case SwFrameFormat::HORI_L2R: + { + // nothing to do + } + break; + case SwFrameFormat::HORI_R2L: + { + aObjPosInHoriL2R.X = -rObjPos.X - rObjSize.Width; + } + break; + case SwFrameFormat::VERT_R2L: + { + aObjPosInHoriL2R.X = -rObjPos.Y - rObjSize.Width; + aObjPosInHoriL2R.Y = rObjPos.X; + } + break; + default: + { + OSL_FAIL( "<SwXShape::ConvertPositionToHoriL2R(..)> - unsupported layout direction" ); + } + } + } + + return aObjPosInHoriL2R; +} + +/** method to convert the transformation of the drawing object to the layout + direction, the drawing object is in + #i31698# +*/ +drawing::HomogenMatrix3 SwXShape::ConvertTransformationToLayoutDir( + const drawing::HomogenMatrix3& rMatrixInHoriL2R ) +{ + drawing::HomogenMatrix3 aMatrix(rMatrixInHoriL2R); + + // #i44334#, #i44681# - direct manipulation of the + // transformation structure isn't valid, if it contains rotation. + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertTransformationToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertTransformationToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to transformation matrix. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + // #i73079# - use correct matrix type + ::basegfx::B2DHomMatrix aTempMatrix; + + aTempMatrix.set(0, 0, aMatrix.Line1.Column1 ); + aTempMatrix.set(0, 1, aMatrix.Line1.Column2 ); + aTempMatrix.set(0, 2, aMatrix.Line1.Column3 ); + aTempMatrix.set(1, 0, aMatrix.Line2.Column1 ); + aTempMatrix.set(1, 1, aMatrix.Line2.Column2 ); + aTempMatrix.set(1, 2, aMatrix.Line2.Column3 ); + // For this to be a valid 2D transform matrix, the last row must be [0,0,1] + assert( aMatrix.Line3.Column1 == 0 ); + assert( aMatrix.Line3.Column2 == 0 ); + assert( aMatrix.Line3.Column3 == 1 ); + // #i73079# + aTempMatrix.translate( aTranslateDiff.X, aTranslateDiff.Y ); + aMatrix.Line1.Column1 = aTempMatrix.get(0, 0); + aMatrix.Line1.Column2 = aTempMatrix.get(0, 1); + aMatrix.Line1.Column3 = aTempMatrix.get(0, 2); + aMatrix.Line2.Column1 = aTempMatrix.get(1, 0); + aMatrix.Line2.Column2 = aTempMatrix.get(1, 1); + aMatrix.Line2.Column3 = aTempMatrix.get(1, 2); + aMatrix.Line3.Column1 = 0; + aMatrix.Line3.Column2 = 0; + aMatrix.Line3.Column3 = 1; + } + } + } + + return aMatrix; +} + +/** method to adjust the positioning properties + #i31698# +*/ +void SwXShape::AdjustPositionProperties( const awt::Point& rPosition ) +{ + // handle x-position + // #i35007# - no handling of x-position, if drawing + // object is anchored as-character, because it doesn't make sense. + text::TextContentAnchorType eTextAnchorType = + text::TextContentAnchorType_AT_PARAGRAPH; + { + uno::Any aAny = getPropertyValue( "AnchorType" ); + aAny >>= eTextAnchorType; + } + if ( eTextAnchorType != text::TextContentAnchorType_AS_CHARACTER ) + { + // determine current x-position + static constexpr OUString aHoriPosPropStr(u"HoriOrientPosition"_ustr); + uno::Any aHoriPos( getPropertyValue( aHoriPosPropStr ) ); + sal_Int32 dCurrX = 0; + aHoriPos >>= dCurrX; + // change x-position attribute, if needed + if ( dCurrX != rPosition.X ) + { + // adjust x-position orientation to text::HoriOrientation::NONE, if needed + // Note: has to be done before setting x-position attribute + static constexpr OUString aHoriOrientPropStr(u"HoriOrient"_ustr); + uno::Any aHoriOrient( getPropertyValue( aHoriOrientPropStr ) ); + sal_Int16 eHoriOrient; + if (aHoriOrient >>= eHoriOrient) // may be void + { + if ( eHoriOrient != text::HoriOrientation::NONE ) + { + eHoriOrient = text::HoriOrientation::NONE; + aHoriOrient <<= eHoriOrient; + setPropertyValue( aHoriOrientPropStr, aHoriOrient ); + } + } + // set x-position attribute + aHoriPos <<= rPosition.X; + setPropertyValue( aHoriPosPropStr, aHoriPos ); + } + } + + // handle y-position + { + // determine current y-position + static constexpr OUString aVertPosPropStr(u"VertOrientPosition"_ustr); + uno::Any aVertPos( getPropertyValue( aVertPosPropStr ) ); + sal_Int32 dCurrY = 0; + aVertPos >>= dCurrY; + // change y-position attribute, if needed + if ( dCurrY != rPosition.Y ) + { + // adjust y-position orientation to text::VertOrientation::NONE, if needed + // Note: has to be done before setting y-position attribute + static constexpr OUString aVertOrientPropStr(u"VertOrient"_ustr); + uno::Any aVertOrient( getPropertyValue( aVertOrientPropStr ) ); + sal_Int16 eVertOrient; + if (aVertOrient >>= eVertOrient) // may be void + { + if ( eVertOrient != text::VertOrientation::NONE ) + { + eVertOrient = text::VertOrientation::NONE; + aVertOrient <<= eVertOrient; + setPropertyValue( aVertOrientPropStr, aVertOrient ); + } + } + // set y-position attribute + aVertPos <<= rPosition.Y; + setPropertyValue( aVertPosPropStr, aVertPos ); + } + } +} + +/** method to convert start or end position of the drawing object to the + Writer specific position, which is the attribute position in layout direction + #i59051# +*/ +css::awt::Point SwXShape::ConvertStartOrEndPosToLayoutDir( + const css::awt::Point& aStartOrEndPos ) +{ + awt::Point aConvertedPos( aStartOrEndPos ); + + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to transformation matrix. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + aConvertedPos.X = aConvertedPos.X + aTranslateDiff.X; + aConvertedPos.Y = aConvertedPos.Y + aTranslateDiff.Y; + } + } + } + + return aConvertedPos; +} + +css::drawing::PolyPolygonBezierCoords SwXShape::ConvertPolyPolygonBezierToLayoutDir( + const css::drawing::PolyPolygonBezierCoords& aPath ) +{ + drawing::PolyPolygonBezierCoords aConvertedPath( aPath ); + + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to PolyPolygonBezier. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix( + aTranslateDiff.X, aTranslateDiff.Y)); + + for(drawing::PointSequence& rInnerSequence : asNonConstRange(aConvertedPath.Coordinates)) + { + for(awt::Point& rPoint : asNonConstRange(rInnerSequence)) + { + basegfx::B2DPoint aNewCoordinatePair(rPoint.X, rPoint.Y); + aNewCoordinatePair *= aMatrix; + rPoint.X = basegfx::fround(aNewCoordinatePair.getX()); + rPoint.Y = basegfx::fround(aNewCoordinatePair.getY()); + } + } + } + } + } + + return aConvertedPath; +} + +SwXGroupShape::SwXGroupShape(uno::Reference<XInterface> & xShape, + SwDoc const*const pDoc) + : SwXShape(xShape, pDoc) +{ +#if OSL_DEBUG_LEVEL > 0 + uno::Reference<XShapes> xShapes(m_xShapeAgg, uno::UNO_QUERY); + OSL_ENSURE(xShapes.is(), "no SvxShape found or shape is not a group shape"); +#endif +} + +SwXGroupShape::~SwXGroupShape() +{ +} + +uno::Any SwXGroupShape::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet; + if(rType == cppu::UnoType<XShapes>::get()) + aRet <<= uno::Reference<XShapes>(this); + else + aRet = SwXShape::queryInterface(rType); + return aRet; +} + +void SwXGroupShape::acquire( ) noexcept +{ + SwXShape::acquire(); +} + +void SwXGroupShape::release( ) noexcept +{ + SwXShape::release(); +} + +void SwXGroupShape::add( const uno::Reference< XShape >& xShape ) +{ + SolarMutexGuard aGuard; + SvxShape* pSvxShape = GetSvxShape(); + SwFrameFormat* pFormat = GetFrameFormat(); + if(!(pSvxShape && pFormat)) + throw uno::RuntimeException(); + + uno::Reference<XShapes> xShapes; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XShapes>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xShapes; + } + if(!xShapes.is()) + throw uno::RuntimeException(); + + xShapes->add(xShape); + + + uno::Reference<lang::XUnoTunnel> xTunnel(xShape, uno::UNO_QUERY); + SwXShape* pSwShape = comphelper::getFromUnoTunnel<SwXShape>(xTunnel); + if(!(pSwShape && pSwShape->m_bDescriptor)) + return; + + SvxShape* pAddShape = comphelper::getFromUnoTunnel<SvxShape>(xTunnel); + if(pAddShape) + { + SdrObject* pObj = pAddShape->GetSdrObject(); + if(pObj) + { + SwDoc* pDoc = pFormat->GetDoc(); + // set layer of new drawing + // object to corresponding invisible layer. + if( SdrInventor::FmForm != pObj->GetObjInventor()) + { + pObj->SetLayer( pSwShape->m_pImpl->GetOpaque() + ? pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() + : pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + } + else + { + pObj->SetLayer(pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + } + } + } + pSwShape->m_bDescriptor = false; +} + +void SwXGroupShape::remove( const uno::Reference< XShape >& xShape ) +{ + SolarMutexGuard aGuard; + uno::Reference<XShapes> xShapes; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XShapes>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xShapes; + } + if(!xShapes.is()) + throw uno::RuntimeException(); + xShapes->remove(xShape); +} + +sal_Int32 SwXGroupShape::getCount() +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getCount(); +} + +uno::Any SwXGroupShape::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getByIndex(nIndex); +} + +uno::Type SwXGroupShape::getElementType( ) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getElementType(); +} + +sal_Bool SwXGroupShape::hasElements( ) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->hasElements(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoevent.cxx b/sw/source/core/unocore/unoevent.cxx new file mode 100644 index 0000000000..09b1a089f8 --- /dev/null +++ b/sw/source/core/unocore/unoevent.cxx @@ -0,0 +1,233 @@ +/* -*- 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 . + */ + +// HINTIDs must be on top; it is required for the macitem.hxx header +#include <hintids.hxx> +#include <unoevent.hxx> +#include <unoframe.hxx> +#include <unostyle.hxx> +#include <fmtinfmt.hxx> +#include <svl/macitem.hxx> +#include <sfx2/event.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using ::com::sun::star::container::XNameReplace; + +// tables of allowed events for specific objects + +const struct SvEventDescription aGraphicEvents[] = +{ + { SvMacroItemId::SwObjectSelect, "OnSelect" }, + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnClick, "OnClick" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::OnImageLoadDone, "OnLoadDone" }, + { SvMacroItemId::OnImageLoadCancel, "OnLoadCancel" }, + { SvMacroItemId::OnImageLoadError, "OnLoadError" }, + { SvMacroItemId::NONE, nullptr } +}; + +const struct SvEventDescription aFrameEvents[] = +{ + { SvMacroItemId::SwObjectSelect, "OnSelect" }, + { SvMacroItemId::SwFrmKeyInputAlpha, "OnAlphaCharInput" }, + { SvMacroItemId::SwFrmKeyInputNoAlpha, "OnNonAlphaCharInput" }, + { SvMacroItemId::SwFrmResize, "OnResize" }, + { SvMacroItemId::SwFrmMove, "OnMove" }, + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnClick, "OnClick" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::NONE, nullptr } +}; + +const struct SvEventDescription aOLEEvents[] = +{ + { SvMacroItemId::SwObjectSelect, "OnSelect" }, + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnClick, "OnClick" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::NONE, nullptr } +}; + +const struct SvEventDescription aHyperlinkEvents[] = +{ + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnClick, "OnClick" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::NONE, nullptr } +}; + +const struct SvEventDescription aFrameStyleEvents[] = +{ + { SvMacroItemId::SwObjectSelect, "OnSelect" }, + { SvMacroItemId::SwFrmKeyInputAlpha, "OnAlphaCharInput" }, + { SvMacroItemId::SwFrmKeyInputNoAlpha, "OnNonAlphaCharInput" }, + { SvMacroItemId::SwFrmResize, "OnResize" }, + { SvMacroItemId::SwFrmMove, "OnMove" }, + { SvMacroItemId::OnMouseOver, "OnMouseOver" }, + { SvMacroItemId::OnClick, "OnClick" }, + { SvMacroItemId::OnMouseOut, "OnMouseOut" }, + { SvMacroItemId::OnImageLoadDone, "OnLoadDone" }, + { SvMacroItemId::OnImageLoadCancel, "OnLoadCancel" }, + { SvMacroItemId::OnImageLoadError, "OnLoadError" }, + { SvMacroItemId::NONE, nullptr } +}; + +SwHyperlinkEventDescriptor::SwHyperlinkEventDescriptor() : + SvDetachedEventDescriptor(aHyperlinkEvents) +{ +} + +SwHyperlinkEventDescriptor::~SwHyperlinkEventDescriptor() +{ +} + +OUString SwHyperlinkEventDescriptor::getImplementationName() +{ + return "SwHyperlinkEventDescriptor"; +} + +void SwHyperlinkEventDescriptor::copyMacrosFromINetFormat( + const SwFormatINetFormat& aFormat) +{ + for(sal_uInt16 i = 0; mpSupportedMacroItems[i].mnEvent != SvMacroItemId::NONE; ++i) + { + const SvMacroItemId nEvent = mpSupportedMacroItems[i].mnEvent; + const SvxMacro* aMacro = aFormat.GetMacro(nEvent); + if (nullptr != aMacro) + replaceByName(nEvent, *aMacro); + } +} + +void SwHyperlinkEventDescriptor::copyMacrosIntoINetFormat( + SwFormatINetFormat& aFormat) +{ + for(sal_uInt16 i = 0; mpSupportedMacroItems[i].mnEvent != SvMacroItemId::NONE; ++i) + { + const SvMacroItemId nEvent = mpSupportedMacroItems[i].mnEvent; + if (hasById(nEvent)) + { + SvxMacro aMacro("", ""); + getByName(aMacro, nEvent); + aFormat.SetMacro(nEvent, aMacro); + } + } +} + +void SwHyperlinkEventDescriptor::copyMacrosFromNameReplace( + uno::Reference< + container::XNameReplace> const & xReplace) +{ + // iterate over all names (all names that *we* support) + const Sequence<OUString> aNames = getElementNames(); + for(const OUString& rName : aNames) + { + // copy element for that name + if (xReplace->hasByName(rName)) + { + SvBaseEventDescriptor::replaceByName(rName, + xReplace->getByName(rName)); + } + } +} + +// use double cast in superclass constructor to avoid ambiguous cast +SwFrameEventDescriptor::SwFrameEventDescriptor( + SwXTextFrame& rFrameRef ) : + SvEventDescriptor(static_cast<text::XTextFrame&>(rFrameRef), aFrameEvents), + m_rFrame(rFrameRef) +{ +} + +SwFrameEventDescriptor::SwFrameEventDescriptor( + SwXTextGraphicObject& rGraphicRef ) : + SvEventDescriptor(static_cast<text::XTextContent&>(rGraphicRef), aGraphicEvents), + m_rFrame(static_cast<SwXFrame&>(rGraphicRef)) +{ +} + +SwFrameEventDescriptor::SwFrameEventDescriptor( + SwXTextEmbeddedObject& rObjectRef ) : + SvEventDescriptor(static_cast<text::XTextContent&>(rObjectRef), aOLEEvents), + m_rFrame(static_cast<SwXFrame&>(rObjectRef)) +{ +} + +SwFrameEventDescriptor::~SwFrameEventDescriptor() +{ +} + +void SwFrameEventDescriptor::setMacroItem(const SvxMacroItem& rItem) +{ + m_rFrame.GetFrameFormat()->SetFormatAttr(rItem); +} + +const SvxMacroItem& SwFrameEventDescriptor::getMacroItem() +{ + return m_rFrame.GetFrameFormat()->GetFormatAttr(RES_FRMMACRO); +} + +sal_uInt16 SwFrameEventDescriptor::getMacroItemWhich() const +{ + return RES_FRMMACRO; +} + +OUString SwFrameEventDescriptor::getImplementationName() +{ + return "SwFrameEventDescriptor"; +} + +SwFrameStyleEventDescriptor::SwFrameStyleEventDescriptor( + sw::ICoreFrameStyle& rStyle ) : + SvEventDescriptor(rStyle.GetEventsSupplier(), + aFrameStyleEvents), + m_rStyle(rStyle) +{ +} + +SwFrameStyleEventDescriptor::~SwFrameStyleEventDescriptor() +{ +} + +void SwFrameStyleEventDescriptor::setMacroItem(const SvxMacroItem& rItem) +{ + m_rStyle.SetItem(RES_FRMMACRO, rItem); +} + +const SvxMacroItem aEmptyMacroItem(RES_FRMMACRO); + +const SvxMacroItem& SwFrameStyleEventDescriptor::getMacroItem() +{ + const SfxPoolItem* pItem(m_rStyle.GetItem(RES_FRMMACRO)); + return pItem ? static_cast<const SvxMacroItem&>(*pItem) : aEmptyMacroItem; +} + +OUString SwFrameStyleEventDescriptor::getImplementationName() +{ + return "SwFrameStyleEventDescriptor"; +} + +sal_uInt16 SwFrameStyleEventDescriptor::getMacroItemWhich() const +{ + return RES_FRMMACRO; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx new file mode 100644 index 0000000000..d73c0b59b3 --- /dev/null +++ b/sw/source/core/unocore/unofield.cxx @@ -0,0 +1,3024 @@ +/* -*- 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 <sal/config.h> +#include <algorithm> +#include <memory> + +#include <unofield.hxx> +#include <unofieldcoll.hxx> +#include <unobookmark.hxx> +#include <swtypes.hxx> +#include <cmdid.h> +#include <doc.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentStatistics.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentState.hxx> +#include <fmtfld.hxx> +#include <txtfld.hxx> +#include <ndtxt.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unocoll.hxx> +#include <sfx2/linkmgr.hxx> +#include <editsh.hxx> +#include <viewsh.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +//undef to prevent error (from sfx2/docfile.cxx) +#undef SEQUENCE +#include <com/sun/star/text/SetVariableType.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <authfld.hxx> +#include <flddat.hxx> +#include <dbfld.hxx> +#include <usrfld.hxx> +#include <docufld.hxx> +#include <expfld.hxx> +#include <chpfld.hxx> +#include <flddropdown.hxx> +#include <poolfmt.hxx> +#include <strings.hrc> +#include <pagedesc.hxx> +#include <docary.hxx> +#include <reffld.hxx> +#include <ddefld.hxx> +#include <SwStyleNameMapper.hxx> +#include <swunohelper.hxx> +#include <unofldmid.h> +#include <scriptinfo.hxx> +#include <tools/datetime.hxx> +#include <tools/urlobj.hxx> +#include <svl/itemprop.hxx> +#include <svl/listener.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <mutex> +#include <vcl/svapp.hxx> +#include <textapi.hxx> +#include <fmtmeta.hxx> +#include <vector> + +using namespace ::com::sun::star; +using namespace nsSwDocInfoSubType; + +// case-corrected version of the first part for the service names (see #i67811) +constexpr OUString COM_TEXT_FLDMASTER_CC = u"com.sun.star.text.fieldmaster."_ustr; + +// note: this thing is indexed as an array, so do not insert/remove entries! +const sal_uInt16 aDocInfoSubTypeFromService[] = +{ + DI_CHANGE | DI_SUB_AUTHOR, //PROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_AUTHOR + DI_CHANGE | DI_SUB_DATE, //PROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_DATE_TIME + DI_EDIT | DI_SUB_TIME, //PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME + DI_COMMENT, //PROPERTY_MAP_FLDTYP_DOCINFO_DESCRIPTION + DI_CREATE | DI_SUB_AUTHOR, //PROPERTY_MAP_FLDTYP_DOCINFO_CREATE_AUTHOR + DI_CREATE | DI_SUB_DATE, //PROPERTY_MAP_FLDTYP_DOCINFO_CREATE_DATE_TIME + 0, //DUMMY + 0, //DUMMY + 0, //DUMMY + 0, //DUMMY + DI_CUSTOM, //PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM + DI_PRINT | DI_SUB_AUTHOR, //PROPERTY_MAP_FLDTYP_DOCINFO_PRINT_AUTHOR + DI_PRINT | DI_SUB_DATE, //PROPERTY_MAP_FLDTYP_DOCINFO_PRINT_DATE_TIME + DI_KEYS, //PROPERTY_MAP_FLDTYP_DOCINFO_KEY_WORDS + DI_SUBJECT, //PROPERTY_MAP_FLDTYP_DOCINFO_SUBJECT + DI_TITLE, //PROPERTY_MAP_FLDTYP_DOCINFO_TITLE + DI_DOCNO //PROPERTY_MAP_FLDTYP_DOCINFO_REVISION +}; + +namespace { + +struct ServiceIdResId +{ + SwFieldIds nResId; + SwServiceType nServiceId; +}; + +} + +const ServiceIdResId aServiceToRes[] = +{ + {SwFieldIds::DateTime, SwServiceType::FieldTypeDateTime }, + {SwFieldIds::User, SwServiceType::FieldTypeUser }, + {SwFieldIds::SetExp, SwServiceType::FieldTypeSetExp }, + {SwFieldIds::GetExp, SwServiceType::FieldTypeGetExp }, + {SwFieldIds::Filename, SwServiceType::FieldTypeFileName }, + {SwFieldIds::PageNumber, SwServiceType::FieldTypePageNum }, + {SwFieldIds::Author, SwServiceType::FieldTypeAuthor }, + {SwFieldIds::Chapter, SwServiceType::FieldTypeChapter }, + {SwFieldIds::GetRef, SwServiceType::FieldTypeGetReference }, + {SwFieldIds::HiddenText, SwServiceType::FieldTypeConditionedText }, + {SwFieldIds::Postit, SwServiceType::FieldTypeAnnotation }, + {SwFieldIds::Input, SwServiceType::FieldTypeInput }, + {SwFieldIds::Macro, SwServiceType::FieldTypeMacro }, + {SwFieldIds::Dde, SwServiceType::FieldTypeDDE }, + {SwFieldIds::HiddenPara, SwServiceType::FieldTypeHiddenPara }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfo }, + {SwFieldIds::TemplateName, SwServiceType::FieldTypeTemplateName }, + {SwFieldIds::ExtUser, SwServiceType::FieldTypeUserExt }, + {SwFieldIds::RefPageSet, SwServiceType::FieldTypeRefPageSet }, + {SwFieldIds::RefPageGet, SwServiceType::FieldTypeRefPageGet }, + {SwFieldIds::JumpEdit, SwServiceType::FieldTypeJumpEdit }, + {SwFieldIds::Script, SwServiceType::FieldTypeScript }, + {SwFieldIds::DbNextSet, SwServiceType::FieldTypeDatabaseNextSet }, + {SwFieldIds::DbNumSet, SwServiceType::FieldTypeDatabaseNumSet }, + {SwFieldIds::DbSetNumber, SwServiceType::FieldTypeDatabaseSetNum }, + {SwFieldIds::Database, SwServiceType::FieldTypeDatabase }, + {SwFieldIds::DatabaseName, SwServiceType::FieldTypeDatabaseName }, + {SwFieldIds::DocStat, SwServiceType::FieldTypePageCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeParagraphCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeWordCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeCharacterCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeTableCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeGraphicObjectCount }, + {SwFieldIds::DocStat, SwServiceType::FieldTypeEmbeddedObjectCount }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoChangeAuthor }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoChangeDateTime }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoEditTime }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoDescription }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCreateAuthor }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCreateDateTime }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoCustom }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoPrintAuthor }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoPrintDateTime }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoKeywords }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoSubject }, + {SwFieldIds::DocInfo, SwServiceType::FieldTypeDocInfoTitle }, + {SwFieldIds::Input, SwServiceType::FieldTypeInputUser }, + {SwFieldIds::HiddenText, SwServiceType::FieldTypeHiddenText }, + {SwFieldIds::TableOfAuthorities, SwServiceType::FieldTypeBibliography }, + {SwFieldIds::CombinedChars, SwServiceType::FieldTypeCombinedCharacters }, + {SwFieldIds::Dropdown, SwServiceType::FieldTypeDropdown }, + {SwFieldIds::Table, SwServiceType::FieldTypeTableFormula } +}; + +static SwFieldIds lcl_ServiceIdToResId(SwServiceType nServiceId) +{ + for (auto const& aEntry : aServiceToRes) + if (aEntry.nServiceId == nServiceId) + return aEntry.nResId; +#if OSL_DEBUG_LEVEL > 0 + OSL_FAIL("service id not found"); +#endif + return SwFieldIds::Unknown; +} + +static SwServiceType lcl_GetServiceForField( const SwField& rField ) +{ + const SwFieldIds nWhich = rField.Which(); + SwServiceType nSrvId = SwServiceType::Invalid; + //special handling for some fields + switch( nWhich ) + { + case SwFieldIds::Input: + if( INP_USR == (rField.GetSubType() & 0x00ff) ) + nSrvId = SwServiceType::FieldTypeInputUser; + break; + + case SwFieldIds::DocInfo: + { + const sal_uInt16 nSubType = rField.GetSubType(); + switch( nSubType & 0xff ) + { + case DI_CHANGE: + nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR) + ? SwServiceType::FieldTypeDocInfoChangeAuthor + : SwServiceType::FieldTypeDocInfoChangeDateTime; + break; + case DI_CREATE: + nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR) + ? SwServiceType::FieldTypeDocInfoCreateAuthor + : SwServiceType::FieldTypeDocInfoCreateDateTime; + break; + case DI_PRINT: + nSrvId = ((nSubType&0x300) == DI_SUB_AUTHOR) + ? SwServiceType::FieldTypeDocInfoPrintAuthor + : SwServiceType::FieldTypeDocInfoPrintDateTime; + break; + case DI_EDIT: nSrvId = SwServiceType::FieldTypeDocInfoEditTime;break; + case DI_COMMENT:nSrvId = SwServiceType::FieldTypeDocInfoDescription;break; + case DI_KEYS: nSrvId = SwServiceType::FieldTypeDocInfoKeywords;break; + case DI_SUBJECT:nSrvId = SwServiceType::FieldTypeDocInfoSubject; break; + case DI_TITLE: nSrvId = SwServiceType::FieldTypeDocInfoTitle; break; + case DI_DOCNO: nSrvId = SwServiceType::FieldTypeDocInfoRevision; break; + case DI_CUSTOM: nSrvId = SwServiceType::FieldTypeDocInfoCustom; break; + } + } + break; + + case SwFieldIds::HiddenText: + nSrvId = SwFieldTypesEnum::ConditionalText == static_cast<SwFieldTypesEnum>(rField.GetSubType()) + ? SwServiceType::FieldTypeConditionedText + : SwServiceType::FieldTypeHiddenText; + break; + + case SwFieldIds::DocStat: + { + switch( rField.GetSubType() ) + { + case DS_PAGE: nSrvId = SwServiceType::FieldTypePageCount; break; + case DS_PARA: nSrvId = SwServiceType::FieldTypeParagraphCount; break; + case DS_WORD: nSrvId = SwServiceType::FieldTypeWordCount ; break; + case DS_CHAR: nSrvId = SwServiceType::FieldTypeCharacterCount; break; + case DS_TBL: nSrvId = SwServiceType::FieldTypeTableCount ; break; + case DS_GRF: nSrvId = SwServiceType::FieldTypeGraphicObjectCount; break; + case DS_OLE: nSrvId = SwServiceType::FieldTypeEmbeddedObjectCount; break; + } + } + break; + default: break; + } + if( SwServiceType::Invalid == nSrvId ) + { + for( const ServiceIdResId* pMap = aServiceToRes; + SwFieldIds::Unknown != pMap->nResId; ++pMap ) + if( nWhich == pMap->nResId ) + { + nSrvId = pMap->nServiceId; + break; + } + } +#if OSL_DEBUG_LEVEL > 0 + if( SwServiceType::Invalid == nSrvId ) + OSL_FAIL("resid not found"); +#endif + return nSrvId; +} + +static sal_uInt16 lcl_GetPropMapIdForFieldType( SwFieldIds nWhich ) +{ + sal_uInt16 nId; + switch( nWhich ) + { + case SwFieldIds::User: nId = PROPERTY_MAP_FLDMSTR_USER; break; + case SwFieldIds::Database: nId = PROPERTY_MAP_FLDMSTR_DATABASE; break; + case SwFieldIds::SetExp: nId = PROPERTY_MAP_FLDMSTR_SET_EXP; break; + case SwFieldIds::Dde: nId = PROPERTY_MAP_FLDMSTR_DDE; break; + case SwFieldIds::TableOfAuthorities: + nId = PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY; break; + default: nId = PROPERTY_MAP_FLDMSTR_DUMMY0; + } + return nId; +} + +static sal_Int32 lcl_PropName2TokenPos(std::u16string_view rPropertyName) +{ + if (rPropertyName == UNO_NAME_DDE_COMMAND_TYPE) + return 0; + + if (rPropertyName == UNO_NAME_DDE_COMMAND_FILE) + return 1; + + if (rPropertyName == UNO_NAME_DDE_COMMAND_ELEMENT) + return 2; + + if (rPropertyName == UNO_NAME_IS_AUTOMATIC_UPDATE) + return 3; + + return SAL_MAX_INT32; +} + +static sal_uInt16 GetFieldTypeMId( std::u16string_view rProperty, const SwFieldType& rTyp ) +{ + sal_uInt16 nId = lcl_GetPropMapIdForFieldType( rTyp.Which() ); + const SfxItemPropertySet* pSet = aSwMapProvider.GetPropertySet( nId ); + if( !pSet ) + nId = USHRT_MAX; + else + { + const SfxItemPropertyMapEntry* pEntry = pSet->getPropertyMap().getByName(rProperty); + nId = pEntry ? pEntry->nWID : USHRT_MAX; + } + return nId; +} + +static sal_uInt16 lcl_GetPropertyMapOfService( SwServiceType nServiceId ) +{ + sal_uInt16 nRet; + switch ( nServiceId) + { + case SwServiceType::FieldTypeDateTime: nRet = PROPERTY_MAP_FLDTYP_DATETIME; break; + case SwServiceType::FieldTypeUser: nRet = PROPERTY_MAP_FLDTYP_USER; break; + case SwServiceType::FieldTypeSetExp: nRet = PROPERTY_MAP_FLDTYP_SET_EXP; break; + case SwServiceType::FieldTypeGetExp: nRet = PROPERTY_MAP_FLDTYP_GET_EXP; break; + case SwServiceType::FieldTypeFileName: nRet = PROPERTY_MAP_FLDTYP_FILE_NAME; break; + case SwServiceType::FieldTypePageNum: nRet = PROPERTY_MAP_FLDTYP_PAGE_NUM; break; + case SwServiceType::FieldTypeAuthor: nRet = PROPERTY_MAP_FLDTYP_AUTHOR; break; + case SwServiceType::FieldTypeChapter: nRet = PROPERTY_MAP_FLDTYP_CHAPTER; break; + case SwServiceType::FieldTypeGetReference: nRet = PROPERTY_MAP_FLDTYP_GET_REFERENCE; break; + case SwServiceType::FieldTypeConditionedText: nRet = PROPERTY_MAP_FLDTYP_CONDITIONED_TEXT; break; + case SwServiceType::FieldTypeAnnotation: nRet = PROPERTY_MAP_FLDTYP_ANNOTATION; break; + case SwServiceType::FieldTypeInputUser: + case SwServiceType::FieldTypeInput: nRet = PROPERTY_MAP_FLDTYP_INPUT; break; + case SwServiceType::FieldTypeMacro: nRet = PROPERTY_MAP_FLDTYP_MACRO; break; + case SwServiceType::FieldTypeDDE: nRet = PROPERTY_MAP_FLDTYP_DDE; break; + case SwServiceType::FieldTypeHiddenPara: nRet = PROPERTY_MAP_FLDTYP_HIDDEN_PARA; break; + case SwServiceType::FieldTypeDocInfo: nRet = PROPERTY_MAP_FLDTYP_DOC_INFO; break; + case SwServiceType::FieldTypeTemplateName: nRet = PROPERTY_MAP_FLDTYP_TEMPLATE_NAME; break; + case SwServiceType::FieldTypeUserExt: nRet = PROPERTY_MAP_FLDTYP_USER_EXT; break; + case SwServiceType::FieldTypeRefPageSet: nRet = PROPERTY_MAP_FLDTYP_REF_PAGE_SET; break; + case SwServiceType::FieldTypeRefPageGet: nRet = PROPERTY_MAP_FLDTYP_REF_PAGE_GET; break; + case SwServiceType::FieldTypeJumpEdit: nRet = PROPERTY_MAP_FLDTYP_JUMP_EDIT; break; + case SwServiceType::FieldTypeScript: nRet = PROPERTY_MAP_FLDTYP_SCRIPT; break; + case SwServiceType::FieldTypeDatabaseNextSet: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET; break; + case SwServiceType::FieldTypeDatabaseNumSet: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NUM_SET; break; + case SwServiceType::FieldTypeDatabaseSetNum: nRet = PROPERTY_MAP_FLDTYP_DATABASE_SET_NUM; break; + case SwServiceType::FieldTypeDatabase: nRet = PROPERTY_MAP_FLDTYP_DATABASE; break; + case SwServiceType::FieldTypeDatabaseName: nRet = PROPERTY_MAP_FLDTYP_DATABASE_NAME; break; + case SwServiceType::FieldTypeTableFormula: nRet = PROPERTY_MAP_FLDTYP_TABLE_FORMULA; break; + case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypeParagraphCount: + case SwServiceType::FieldTypeWordCount: + case SwServiceType::FieldTypeCharacterCount: + case SwServiceType::FieldTypeTableCount: + case SwServiceType::FieldTypeGraphicObjectCount: + case SwServiceType::FieldTypeEmbeddedObjectCount: nRet = PROPERTY_MAP_FLDTYP_DOCSTAT; break; + case SwServiceType::FieldTypeDocInfoChangeAuthor: + case SwServiceType::FieldTypeDocInfoCreateAuthor: + case SwServiceType::FieldTypeDocInfoPrintAuthor: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR; break; + case SwServiceType::FieldTypeDocInfoChangeDateTime: + case SwServiceType::FieldTypeDocInfoCreateDateTime: + case SwServiceType::FieldTypeDocInfoPrintDateTime: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME; break; + case SwServiceType::FieldTypeDocInfoEditTime: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME; break; + case SwServiceType::FieldTypeDocInfoCustom: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM; break; + case SwServiceType::FieldTypeDocInfoDescription: + case SwServiceType::FieldTypeDocInfoKeywords: + case SwServiceType::FieldTypeDocInfoSubject: + case SwServiceType::FieldTypeDocInfoTitle: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_MISC; break; + case SwServiceType::FieldTypeDocInfoRevision: nRet = PROPERTY_MAP_FLDTYP_DOCINFO_REVISION; break; + case SwServiceType::FieldTypeBibliography: nRet = PROPERTY_MAP_FLDTYP_BIBLIOGRAPHY; break; + case SwServiceType::FieldTypeDummy0: + case SwServiceType::FieldTypeCombinedCharacters: nRet = PROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS; break; + case SwServiceType::FieldTypeDropdown: nRet = PROPERTY_MAP_FLDTYP_DROPDOWN; break; + case SwServiceType::FieldTypeDummy4: + case SwServiceType::FieldTypeDummy5: + case SwServiceType::FieldTypeDummy6: + case SwServiceType::FieldTypeDummy7: + nRet = PROPERTY_MAP_FLDTYP_DUMMY_0; break; + case SwServiceType::FieldMasterUser: nRet = PROPERTY_MAP_FLDMSTR_USER; break; + case SwServiceType::FieldMasterDDE: nRet = PROPERTY_MAP_FLDMSTR_DDE; break; + case SwServiceType::FieldMasterSetExp: nRet = PROPERTY_MAP_FLDMSTR_SET_EXP; break; + case SwServiceType::FieldMasterDatabase: nRet = PROPERTY_MAP_FLDMSTR_DATABASE; break; + case SwServiceType::FieldMasterBibliography: nRet = PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY; break; + case SwServiceType::FieldMasterDummy2: + case SwServiceType::FieldMasterDummy3: + case SwServiceType::FieldMasterDummy4: + case SwServiceType::FieldMasterDummy5: nRet = PROPERTY_MAP_FLDMSTR_DUMMY0; break; + case SwServiceType::FieldTypeHiddenText: nRet = PROPERTY_MAP_FLDTYP_HIDDEN_TEXT; break; + default: + nRet = USHRT_MAX; + } + assert(nRet != USHRT_MAX && "wrong service id"); + return nRet; +} + +class SwXFieldMaster::Impl + : public SvtListener +{ +public: + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + + unotools::WeakReference<SwXFieldMaster> m_wThis; + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + + SwDoc* m_pDoc; + SwFieldType* m_pType; + + SwFieldIds m_nResTypeId; + + OUString m_sParam1; // Content / Database / NumberingSeparator + OUString m_sParam2; // - /DataTablename + OUString m_sParam3; // - /DataFieldName + OUString m_sParam5; // - /DataBaseURL + double m_fParam1; // Value / - + sal_Int8 m_nParam1; // ChapterNumberingLevel + bool m_bParam1; // IsExpression + sal_Int32 m_nParam2; + + Impl(SwPageDesc* const pPageDesc, SwDoc* pDoc, SwFieldIds nResId) + : m_pDoc(pDoc) + , m_pType(nullptr) + , m_nResTypeId(nResId) + , m_fParam1(0.0) + , m_nParam1(-1) + , m_bParam1(false) + , m_nParam2(0) + { + StartListening(pPageDesc->GetNotifier()); + } + + Impl(SwFieldType* const pType, SwDoc* pDoc, SwFieldIds nResId) + : m_pDoc(pDoc) + , m_pType(pType) + , m_nResTypeId(nResId) + , m_fParam1(0.0) + , m_nParam1(-1) + , m_bParam1(false) + , m_nParam2(0) + { + StartListening(m_pType->GetNotifier()); + } + void SetFieldType(SwFieldType* pType) + { + EndListeningAll(); + m_pType = pType; + StartListening(m_pType->GetNotifier()); + } +protected: + virtual void Notify(const SfxHint& rHint) override; +}; + +OUString SAL_CALL +SwXFieldMaster::getImplementationName() +{ + return "SwXFieldMaster"; +} + +namespace +{ + +OUString getServiceName(const SwFieldIds aId) +{ + const char* pEntry; + switch (aId) + { + case SwFieldIds::User: + pEntry = "User"; + break; + case SwFieldIds::Database: + pEntry = "Database"; + break; + case SwFieldIds::SetExp: + pEntry = "SetExpression"; + break; + case SwFieldIds::Dde: + pEntry = "DDE"; + break; + case SwFieldIds::TableOfAuthorities: + pEntry = "Bibliography"; + break; + default: + return OUString(); + } + + return "com.sun.star.text.fieldmaster." + OUString::createFromAscii(pEntry); +} + +} + +sal_Bool SAL_CALL SwXFieldMaster::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXFieldMaster::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextFieldMaster", getServiceName(m_pImpl->m_nResTypeId) }; +} + +SwXFieldMaster::SwXFieldMaster(SwDoc& rDoc, SwFieldIds const nResId) + : m_pImpl(new Impl(rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD), &rDoc, nResId)) +{ +} + +SwXFieldMaster::SwXFieldMaster(SwFieldType& rType, SwDoc * pDoc) + : m_pImpl(new Impl(&rType, pDoc, rType.Which())) +{ +} + +SwXFieldMaster::~SwXFieldMaster() +{ +} + +rtl::Reference<SwXFieldMaster> +SwXFieldMaster::CreateXFieldMaster(SwDoc * pDoc, SwFieldType *const pType, + SwFieldIds nResId) +{ + // re-use existing SwXFieldMaster + rtl::Reference<SwXFieldMaster> xFM; + if (pType) + { + xFM = pType->GetXObject().get(); + } + if (!xFM.is()) + { + SwXFieldMaster *const pFM( pType + ? new SwXFieldMaster(*pType, pDoc) + : new SwXFieldMaster(*pDoc, nResId)); + xFM.set(pFM); + if (pType) + { + pType->SetXObject(xFM); + } + // need a permanent Reference to initialize m_wThis + pFM->m_pImpl->m_wThis = xFM.get(); + } + return xFM; +} + +uno::Reference<beans::XPropertySetInfo> SAL_CALL +SwXFieldMaster::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + uno::Reference< beans::XPropertySetInfo > aRef = + aSwMapProvider.GetPropertySet( + lcl_GetPropMapIdForFieldType(m_pImpl->m_nResTypeId))->getPropertySetInfo(); + return aRef; +} + +void SAL_CALL SwXFieldMaster::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + SwFieldType* pType = GetFieldType(true); + if(pType) + { + bool bSetValue = true; + if( rPropertyName == UNO_NAME_SUB_TYPE ) + { + const std::vector<OUString>& rExtraArr( + SwStyleNameMapper::GetExtraUINameArray()); + const OUString sTypeName = pType->GetName(); + static sal_uInt16 nIds[] = + { + RES_POOLCOLL_LABEL_DRAWING - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_ABB - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_TABLE - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_FRAME- RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_FIGURE - RES_POOLCOLL_EXTRA_BEGIN, + 0 + }; + for(const sal_uInt16 * pIds = nIds; *pIds; ++pIds) + { + if(sTypeName == rExtraArr[ *pIds ] ) + { + bSetValue = false; + break; + } + } + } + if ( bSetValue ) + { + // nothing special to be done here for the properties + // UNO_NAME_DATA_BASE_NAME and UNO_NAME_DATA_BASE_URL. + // We just call PutValue (empty string is allowed). + // Thus the last property set will be used as Data Source. + + const sal_uInt16 nMemberValueId = GetFieldTypeMId( rPropertyName, *pType ); + if ( USHRT_MAX == nMemberValueId ) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak() ); + } + + pType->PutValue( rValue, nMemberValueId ); + if ( pType->Which() == SwFieldIds::User ) + { + // trigger update of User field in order to get depending Input Fields updated. + pType->UpdateFields(); + } + + } + } + else if (m_pImpl->m_pDoc && rPropertyName == UNO_NAME_NAME) + { + OUString sTypeName; + rValue >>= sTypeName; + SwFieldType * pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().GetFieldType( + m_pImpl->m_nResTypeId, sTypeName, false); + + if(pType2 || + (SwFieldIds::SetExp == m_pImpl->m_nResTypeId && + ( sTypeName == SwResId(STR_POOLCOLL_LABEL_TABLE) || + sTypeName == SwResId(STR_POOLCOLL_LABEL_DRAWING) || + sTypeName == SwResId(STR_POOLCOLL_LABEL_FRAME) || + sTypeName == SwResId(STR_POOLCOLL_LABEL_ABB) || + sTypeName == SwResId(STR_POOLCOLL_LABEL_FIGURE) ))) + { + throw lang::IllegalArgumentException(); + } + + switch (m_pImpl->m_nResTypeId) + { + case SwFieldIds::User : + { + SwUserFieldType aType(m_pImpl->m_pDoc, sTypeName); + pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType); + static_cast<SwUserFieldType*>(pType2)->SetContent(m_pImpl->m_sParam1); + static_cast<SwUserFieldType*>(pType2)->SetValue(m_pImpl->m_fParam1); + static_cast<SwUserFieldType*>(pType2)->SetType(m_pImpl->m_bParam1 + ? nsSwGetSetExpType::GSE_EXPR : nsSwGetSetExpType::GSE_STRING); + } + break; + case SwFieldIds::Dde : + { + SwDDEFieldType aType(sTypeName, m_pImpl->m_sParam1, + m_pImpl->m_bParam1 ? SfxLinkUpdateMode::ALWAYS : SfxLinkUpdateMode::ONCALL); + pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType); + } + break; + case SwFieldIds::SetExp : + { + SwSetExpFieldType aType(m_pImpl->m_pDoc, sTypeName); + if (!m_pImpl->m_sParam1.isEmpty()) + aType.SetDelimiter(OUString(m_pImpl->m_sParam1[0])); + if (m_pImpl->m_nParam1 > -1 && m_pImpl->m_nParam1 < MAXLEVEL) + aType.SetOutlineLvl(m_pImpl->m_nParam1); + pType2 = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType); + } + break; + case SwFieldIds::Database : + { + rValue >>= m_pImpl->m_sParam3; + pType2 = GetFieldType(); + } + break; + default: break; + } + if (!pType2) + { + throw uno::RuntimeException("no field type found!", *this); + } + m_pImpl->SetFieldType(pType2); + } + else + { + switch (m_pImpl->m_nResTypeId) + { + case SwFieldIds::User: + if(rPropertyName == UNO_NAME_CONTENT) + rValue >>= m_pImpl->m_sParam1; + else if(rPropertyName == UNO_NAME_VALUE) + { + if(rValue.getValueType() != ::cppu::UnoType<double>::get()) + throw lang::IllegalArgumentException(); + rValue >>= m_pImpl->m_fParam1; + } + else if(rPropertyName == UNO_NAME_IS_EXPRESSION) + { + if(rValue.getValueType() != cppu::UnoType<bool>::get()) + throw lang::IllegalArgumentException(); + rValue >>= m_pImpl->m_bParam1; + } + + break; + case SwFieldIds::Database: + if(rPropertyName == UNO_NAME_DATA_BASE_NAME) + rValue >>= m_pImpl->m_sParam1; + else if(rPropertyName == UNO_NAME_DATA_TABLE_NAME) + rValue >>= m_pImpl->m_sParam2; + else if(rPropertyName == UNO_NAME_DATA_COLUMN_NAME) + rValue >>= m_pImpl->m_sParam3; + else if(rPropertyName == UNO_NAME_DATA_COMMAND_TYPE) + rValue >>= m_pImpl->m_nParam2; + if(rPropertyName == UNO_NAME_DATA_BASE_URL) + rValue >>= m_pImpl->m_sParam5; + + if ( ( !m_pImpl->m_sParam1.isEmpty() + || !m_pImpl->m_sParam5.isEmpty()) + && !m_pImpl->m_sParam2.isEmpty() + && !m_pImpl->m_sParam3.isEmpty()) + { + GetFieldType(); + } + break; + case SwFieldIds::SetExp: + if(rPropertyName == UNO_NAME_NUMBERING_SEPARATOR) + rValue >>= m_pImpl->m_sParam1; + else if(rPropertyName == UNO_NAME_CHAPTER_NUMBERING_LEVEL) + rValue >>= m_pImpl->m_nParam1; + break; + case SwFieldIds::Dde: + { + sal_Int32 nPart = lcl_PropName2TokenPos(rPropertyName); + if(nPart < 3 ) + { + if (m_pImpl->m_sParam1.isEmpty()) + { + m_pImpl->m_sParam1 + = OUStringChar(sfx2::cTokenSeparator) + + OUStringChar(sfx2::cTokenSeparator); + } + OUString sTmp; + rValue >>= sTmp; + sal_Int32 nIndex(0); + sal_Int32 nStart(0); + while (nIndex < m_pImpl->m_sParam1.getLength()) + { + if (m_pImpl->m_sParam1[nIndex] == sfx2::cTokenSeparator) + { + if (0 == nPart) + break; + nStart = nIndex + 1; + --nPart; + } + ++nIndex; + } + assert(0 == nPart); + m_pImpl->m_sParam1 = m_pImpl->m_sParam1.replaceAt( + nStart, nIndex - nStart, sTmp); + } + else if(3 == nPart) + { + rValue >>= m_pImpl->m_bParam1; + } + } + break; + default: + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + } + } +} + +SwFieldType* SwXFieldMaster::GetFieldType(bool const bDontCreate) const +{ + if (!bDontCreate && SwFieldIds::Database == m_pImpl->m_nResTypeId + && !m_pImpl->m_pType && m_pImpl->m_pDoc) + { + SwDBData aData; + + // set DataSource + svx::ODataAccessDescriptor aAcc; + if (!m_pImpl->m_sParam1.isEmpty()) + aAcc[svx::DataAccessDescriptorProperty::DataSource] <<= m_pImpl->m_sParam1; // DataBaseName + else if (!m_pImpl->m_sParam5.isEmpty()) + aAcc[svx::DataAccessDescriptorProperty::DatabaseLocation] <<= m_pImpl->m_sParam5; // DataBaseURL + aData.sDataSource = aAcc.getDataSource(); + + aData.sCommand = m_pImpl->m_sParam2; + aData.nCommandType = m_pImpl->m_nParam2; + + SwDBFieldType aType(m_pImpl->m_pDoc, m_pImpl->m_sParam3, std::move(aData)); + SwFieldType *const pType = m_pImpl->m_pDoc->getIDocumentFieldsAccess().InsertFieldType(aType); + m_pImpl->SetFieldType(pType); + } + return m_pImpl->m_pType; +} + +uno::Any SAL_CALL +SwXFieldMaster::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFieldType* pType = GetFieldType(true); + if( rPropertyName == UNO_NAME_INSTANCE_NAME ) + { + OUString sName; + if(pType) + SwXTextFieldMasters::getInstanceName(*pType, sName); + aRet <<= sName; + } + else if(pType) + { + if(rPropertyName == UNO_NAME_NAME) + { + aRet <<= SwXFieldMaster::GetProgrammaticName(*pType, *m_pImpl->m_pDoc); + } + else if(rPropertyName == UNO_NAME_DEPENDENT_TEXT_FIELDS) + { + //fill all text fields into a sequence + std::vector<SwFormatField*> vpFields; + pType->GatherFields(vpFields); + uno::Sequence<uno::Reference <text::XDependentTextField> > aSeq(vpFields.size()); + std::transform(vpFields.begin(), vpFields.end(), aSeq.getArray(), + [this](SwFormatField* pF) { return uno::Reference<text::XDependentTextField>(SwXTextField::CreateXTextField(m_pImpl->m_pDoc, pF)); }); + aRet <<= aSeq; + } + else + { + //TODO: add properties for the other field types + const sal_uInt16 nMId = GetFieldTypeMId( rPropertyName, *pType ); + if (USHRT_MAX == nMId) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + pType->QueryValue( aRet, nMId ); + + if (rPropertyName == UNO_NAME_DATA_BASE_NAME || + rPropertyName == UNO_NAME_DATA_BASE_URL) + { + OUString aDataSource; + aRet >>= aDataSource; + aRet <<= OUString(); + + OUString *pStr = nullptr; // only one of this properties will return + // a non-empty string. + INetURLObject aObj; + aObj.SetURL( aDataSource ); + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if (bIsURL && rPropertyName == UNO_NAME_DATA_BASE_URL) + pStr = &aDataSource; // DataBaseURL + else if (!bIsURL && rPropertyName == UNO_NAME_DATA_BASE_NAME) + pStr = &aDataSource; // DataBaseName + + if (pStr) + aRet <<= *pStr; + } + } + } + else + { + if(rPropertyName == UNO_NAME_DATA_COMMAND_TYPE) + aRet <<= m_pImpl->m_nParam2; + else if(rPropertyName == UNO_NAME_DEPENDENT_TEXT_FIELDS ) + { + uno::Sequence<uno::Reference <text::XDependentTextField> > aRetSeq(0); + aRet <<= aRetSeq; + } + else + { + switch (m_pImpl->m_nResTypeId) + { + case SwFieldIds::User: + if( rPropertyName == UNO_NAME_CONTENT ) + aRet <<= m_pImpl->m_sParam1; + else if(rPropertyName == UNO_NAME_VALUE) + aRet <<= m_pImpl->m_fParam1; + else if(rPropertyName == UNO_NAME_IS_EXPRESSION) + aRet <<= m_pImpl->m_bParam1; + break; + case SwFieldIds::Database: + if(rPropertyName == UNO_NAME_DATA_BASE_NAME || + rPropertyName == UNO_NAME_DATA_BASE_URL) + { + // only one of these properties returns a non-empty string. + INetURLObject aObj; + aObj.SetURL(m_pImpl->m_sParam5); // SetSmartURL + bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; + if (bIsURL && rPropertyName == UNO_NAME_DATA_BASE_URL) + aRet <<= m_pImpl->m_sParam5; // DataBaseURL + else if ( rPropertyName == UNO_NAME_DATA_BASE_NAME) + aRet <<= m_pImpl->m_sParam1; // DataBaseName + } + else if(rPropertyName == UNO_NAME_DATA_TABLE_NAME) + aRet <<= m_pImpl->m_sParam2; + else if(rPropertyName == UNO_NAME_DATA_COLUMN_NAME) + aRet <<= m_pImpl->m_sParam3; + break; + case SwFieldIds::SetExp: + if(rPropertyName == UNO_NAME_NUMBERING_SEPARATOR) + aRet <<= m_pImpl->m_sParam1; + else if(rPropertyName == UNO_NAME_CHAPTER_NUMBERING_LEVEL) + aRet <<= m_pImpl->m_nParam1; + break; + case SwFieldIds::Dde: + { + const sal_Int32 nPart = lcl_PropName2TokenPos(rPropertyName); + if(nPart < 3 ) + aRet <<= m_pImpl->m_sParam1.getToken(nPart, sfx2::cTokenSeparator); + else if(3 == nPart) + aRet <<= m_pImpl->m_bParam1; + } + break; + default: + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + } + } + } + return aRet; +} + +void SwXFieldMaster::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFieldMaster::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFieldMaster::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFieldMaster::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL SwXFieldMaster::dispose() +{ + SolarMutexGuard aGuard; + SwFieldType *const pFieldType = GetFieldType(true); + if (!pFieldType) + throw uno::RuntimeException(); + size_t nTypeIdx = SIZE_MAX; + const SwFieldTypes* pTypes = m_pImpl->m_pDoc->getIDocumentFieldsAccess().GetFieldTypes(); + for( size_t i = 0; i < pTypes->size(); i++ ) + { + if((*pTypes)[i].get()== pFieldType) + nTypeIdx = i; + } + + // first delete all fields + std::vector<SwFormatField*> vpFields; + pFieldType->GatherFields(vpFields); + for(auto pField : vpFields) + SwTextField::DeleteTextField(*pField->GetTextField()); + // then delete FieldType + m_pImpl->m_pDoc->getIDocumentFieldsAccess().RemoveFieldType(nTypeIdx); +} + +void SAL_CALL SwXFieldMaster::addEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXFieldMaster::removeEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +void SwXFieldMaster::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pDoc = nullptr; + m_pType = nullptr; + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); + } +} + +OUString SwXFieldMaster::GetProgrammaticName(const SwFieldType& rType, SwDoc& rDoc) +{ + const OUString sName(rType.GetName()); + if(SwFieldIds::SetExp == rType.Which()) + { + const SwFieldTypes* pTypes = rDoc.getIDocumentFieldsAccess().GetFieldTypes(); + for( size_t i = 0; i <= o3tl::make_unsigned(INIT_FLDTYPES); i++ ) + { + if((*pTypes)[i].get() == &rType) + { + return SwStyleNameMapper::GetProgName( sName, SwGetPoolIdFromName::TxtColl ); + } + } + } + return sName; +} + +OUString SwXFieldMaster::LocalizeFormula( + const SwSetExpField& rField, + const OUString& rFormula, + bool bQuery) +{ + const OUString sTypeName(rField.GetTyp()->GetName()); + const OUString sProgName( + SwStyleNameMapper::GetProgName(sTypeName, SwGetPoolIdFromName::TxtColl )); + if(sProgName != sTypeName) + { + const OUString sSource = bQuery ? sTypeName : sProgName; + const OUString sDest = bQuery ? sProgName : sTypeName; + if(rFormula.startsWith(sSource)) + { + return sDest + rFormula.subView(sSource.getLength()); + } + } + return rFormula; +} + +namespace { + +struct SwFieldProperties_Impl +{ + OUString sPar1; + OUString sPar2; + OUString sPar3; + OUString sPar4; + OUString sPar5; + OUString sPar6; + OUString sPar7; + Date aDate; + double fDouble; + uno::Sequence<beans::PropertyValue> aPropSeq; + uno::Sequence<OUString> aStrings; + std::unique_ptr<util::DateTime> pDateTime; + + sal_Int32 nSubType; + sal_Int32 nFormat; + sal_uInt16 nUSHORT1; + sal_uInt16 nUSHORT2; + sal_uInt16 nUSHORT3; + sal_Int16 nSHORT1; + sal_Int8 nByte1; + bool bFormatIsDefault; + bool bBool1; + bool bBool2; + bool bBool3; + bool bBool4; + + SwFieldProperties_Impl(): + aDate( Date::EMPTY ), + fDouble(0.), + nSubType(0), + nFormat(0), + nUSHORT1(0), + nUSHORT2(0), + nUSHORT3(0), + nSHORT1(0), + nByte1(0), + bFormatIsDefault(true), + bBool1(false), + bBool2(false), + bBool3(false), + bBool4(true) //Automatic language + {} +}; + +} + +class SwXTextField::Impl + : public SvtListener +{ +public: + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + SwFieldType* m_pFieldType; + SwFormatField* m_pFormatField; + + unotools::WeakReference<SwXTextField> m_wThis; + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + + SwDoc* m_pDoc; + rtl::Reference<SwTextAPIObject> m_xTextObject; + bool m_bIsDescriptor; + bool m_bCallUpdate; + SwServiceType m_nServiceId; + OUString m_sTypeName; + std::unique_ptr<SwFieldProperties_Impl> m_pProps; + + Impl(SwDoc *const pDoc, SwFormatField *const pFormat, SwServiceType nServiceId) + : m_pFieldType(nullptr) + , m_pFormatField(pFormat) + , m_pDoc(pDoc) + , m_bIsDescriptor(pFormat == nullptr) + , m_bCallUpdate(false) + , m_nServiceId(pFormat + ? lcl_GetServiceForField(*pFormat->GetField()) + : nServiceId) + , m_pProps(pFormat ? nullptr : new SwFieldProperties_Impl) + { + if(m_pFormatField) + StartListening(m_pFormatField->GetNotifier()); + } + + virtual ~Impl() override + { + if (m_xTextObject.is()) + { + m_xTextObject->DisposeEditSource(); + } + } + + void SetFormatField(SwFormatField* pFormatField, SwDoc* pDoc) + { + m_pFormatField = pFormatField; + m_pDoc = pDoc; + if(m_pFormatField) + { + EndListeningAll(); + StartListening(m_pFormatField->GetNotifier()); + } + } + SwFormatField* GetFormatField() + { + return m_pFormatField; + } + bool IsDescriptor() const + { + // ideally should be: !m_pFormatField && m_pDoc + // but: SwXServiceProvider::MakeInstance() passes nullptr SwDoc, see comment there + return m_bIsDescriptor; + } + void Invalidate(); + + const SwField* GetField() const; + + SwFieldType* GetFieldType() const + { + if(!m_pDoc && !IsDescriptor()) + throw uno::RuntimeException(); + else if (IsDescriptor()) + return m_pFieldType; + + return m_pFormatField->GetField()->GetTyp(); + } + void SetFieldType(SwFieldType& rType) + { + EndListeningAll(); + m_pFieldType = &rType; + StartListening(m_pFieldType->GetNotifier()); + } + void ClearFieldType() + { + SvtListener::EndListeningAll(); + m_pFieldType = nullptr; + } + virtual void Notify(const SfxHint&) override; +}; + +SwXTextField::SwXTextField( + SwServiceType nServiceId, + SwDoc* pDoc) + : m_pImpl(new Impl(pDoc, nullptr, nServiceId)) +{ + //Set visible as default! + if ( SwServiceType::FieldTypeSetExp == nServiceId + || SwServiceType::FieldTypeDatabaseSetNum == nServiceId + || SwServiceType::FieldTypeDatabase == nServiceId + || SwServiceType::FieldTypeDatabaseName == nServiceId ) + { + m_pImpl->m_pProps->bBool2 = true; + } + else if(SwServiceType::FieldTypeTableFormula == nServiceId) + { + m_pImpl->m_pProps->bBool1 = true; + } + if(SwServiceType::FieldTypeSetExp == nServiceId) + { + m_pImpl->m_pProps->nUSHORT2 = USHRT_MAX; + } +} + +SwXTextField::SwXTextField(SwFormatField& rFormat, SwDoc & rDoc) + : m_pImpl(new Impl(&rDoc, &rFormat, SwServiceType::Invalid)) +{ +} + +SwXTextField::~SwXTextField() +{ +} + +rtl::Reference<SwXTextField> +SwXTextField::CreateXTextField(SwDoc *const pDoc, SwFormatField const* pFormat, + SwServiceType nServiceId) +{ + assert(!pFormat || pDoc); + assert(pFormat || nServiceId != SwServiceType::Invalid); + // re-use existing SwXTextField + rtl::Reference<SwXTextField> xField; + if (pFormat) + { + xField = pFormat->GetXTextField(); + } + if (!xField.is()) + { + SwXTextField *const pField( pFormat + ? new SwXTextField(const_cast<SwFormatField&>(*pFormat), *pDoc) + : new SwXTextField(nServiceId, pDoc)); + xField.set(pField); + if (pFormat) + { + const_cast<SwFormatField *>(pFormat)->SetXTextField(xField); + } + // need a permanent Reference to initialize m_wThis + pField->m_pImpl->m_wThis = xField.get(); + } + return xField; +} + +SwServiceType SwXTextField::GetServiceId() const +{ + return m_pImpl->m_nServiceId; +} + +/** Convert between SwSetExpField with InputFlag false and InputFlag true. + Unfortunately the InputFlag is exposed in the API as "Input" property + and is mutable; in the UI and in ODF these are 2 different types of + fields, so the API design is very questionable. + In order to keep the mutable property, the whole thing has to be + reconstructed from scratch, to replace the SwTextField hint with + SwTextInputField or vice versa. + The SwFormatField will be replaced - it must be, because the Which + changes - but the SwXTextField *must not* be disposed in the operation, + it has to be disconnected first and at the end connected to the + new instance! + */ +void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField) +{ + assert(rField.GetFormatField()->Which() == (rField.GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + rtl::Reference<SwXTextField> const pXField( + rField.GetFormatField()->GetXTextField()); + if (pXField) + pXField->m_pImpl->SetFormatField(nullptr, nullptr); + SwTextField *const pOldAttr(rField.GetFormatField()->GetTextField()); + SwSetExpField tempField(rField); + tempField.SetInputFlag(!rField.GetInputFlag()); + SwFormatField tempFormat(tempField); + assert(tempFormat.GetField() != &rField); + assert(tempFormat.GetField() != &tempField); // this copies it again? + assert(tempFormat.Which() == (static_cast<SwSetExpField const*>(tempFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + SwTextNode & rNode(pOldAttr->GetTextNode()); + std::shared_ptr<SwPaM> pPamForTextField; + IDocumentContentOperations & rIDCO(rNode.GetDoc().getIDocumentContentOperations()); + SwTextField::GetPamForTextField(*pOldAttr, pPamForTextField); + assert(pPamForTextField); + sal_Int32 const nStart(pPamForTextField->Start()->GetContentIndex()); + rIDCO.DeleteAndJoin(*pPamForTextField); + // ATTENTION: rField is dead now! hope nobody accesses it... + bool bSuccess = rIDCO.InsertPoolItem(*pPamForTextField, tempFormat); + assert(bSuccess); + (void) bSuccess; + SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, ::sw::GetTextAttrMode::Default)); + assert(pNewAttr); + SwFormatField const& rNewFormat(pNewAttr->GetFormatField()); + assert(rNewFormat.Which() == (static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD)); + assert(static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag() == (dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr)); + if (pXField) + { + pXField->m_pImpl->SetFormatField(const_cast<SwFormatField*>(&rNewFormat), &rNode.GetDoc()); + const_cast<SwFormatField&>(rNewFormat).SetXTextField(pXField); + } +} + +void SAL_CALL SwXTextField::attachTextFieldMaster( + const uno::Reference< beans::XPropertySet > & xFieldMaster) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->IsDescriptor()) + throw uno::RuntimeException(); + SwXFieldMaster* pMaster = dynamic_cast<SwXFieldMaster*>(xFieldMaster.get()); + + SwFieldType* pFieldType = pMaster ? pMaster->GetFieldType() : nullptr; + if (!pFieldType || + pFieldType->Which() != lcl_ServiceIdToResId(m_pImpl->m_nServiceId)) + { + throw lang::IllegalArgumentException(); + } + m_pImpl->m_sTypeName = pFieldType->GetName(); + m_pImpl->SetFieldType(*pFieldType); +} + +uno::Reference< beans::XPropertySet > SAL_CALL +SwXTextField::getTextFieldMaster() +{ + SolarMutexGuard aGuard; + + SwFieldType* pType = m_pImpl->GetFieldType(); + if (!pType && !m_pImpl->m_pDoc) // tdf#152619 + return nullptr; + uno::Reference<beans::XPropertySet> const xRet( + SwXFieldMaster::CreateXFieldMaster(m_pImpl->m_pDoc, pType)); + return xRet; +} + +OUString SAL_CALL SwXTextField::getPresentation(sal_Bool bShowCommand) +{ + SolarMutexGuard aGuard; + + SwField const*const pField = m_pImpl->GetField(); + if (!pField) + { + throw uno::RuntimeException(); + } + return bShowCommand ? pField->GetFieldName() : pField->ExpandField(true, nullptr); +} + +void SAL_CALL SwXTextField::attach( + const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + if (m_pImpl->IsDescriptor()) + { + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr; + // if a FieldMaster was attached, then the document is already fixed! + // NOTE: sw.SwXAutoTextEntry unoapi test depends on m_pDoc = 0 being valid + if (!pDoc || (m_pImpl->m_pDoc && m_pImpl->m_pDoc != pDoc)) + throw lang::IllegalArgumentException(); + + SwUnoInternalPaM aPam(*pDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + std::unique_ptr<SwField> xField; + switch (m_pImpl->m_nServiceId) + { + case SwServiceType::FieldTypeAnnotation: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit); + + DateTime aDateTime( DateTime::EMPTY ); + if (m_pImpl->m_pProps->pDateTime) + { + aDateTime = *(m_pImpl->m_pProps->pDateTime); + } + + sal_uInt32 nImportedId = 0; + if (!m_pImpl->m_pProps->sPar6.isEmpty()) + nImportedId = m_pImpl->m_pProps->sPar6.toInt32(16); + sal_uInt32 nParentId = 0; + if (!m_pImpl->m_pProps->sPar5.isEmpty()) + nParentId = m_pImpl->m_pProps->sPar5.toInt32(16); + + SwPostItField* pPostItField = new SwPostItField( + static_cast<SwPostItFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1, // author + m_pImpl->m_pProps->sPar2, // content + m_pImpl->m_pProps->sPar3, // author's initials + m_pImpl->m_pProps->sPar4, // name + aDateTime, + m_pImpl->m_pProps->bBool1, // resolvedflag + 0, // id + nParentId, // parent id + nImportedId, // imported para id + 0, // PostIt Parent ID. + m_pImpl->m_pProps->sPar7 + ); + if ( m_pImpl->m_xTextObject.is() ) + { + pPostItField->SetTextObject( m_pImpl->m_xTextObject->CreateText() ); + pPostItField->SetPar2(m_pImpl->m_xTextObject->GetText()); + } + xField.reset(pPostItField); + } + break; + case SwServiceType::FieldTypeScript: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Script); + xField.reset(new SwScriptField(static_cast<SwScriptFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1, m_pImpl->m_pProps->sPar2, + m_pImpl->m_pProps->bBool1)); + } + break; + case SwServiceType::FieldTypeDateTime: + { + sal_uInt16 nSub = 0; + if (m_pImpl->m_pProps->bBool1) + nSub |= FIXEDFLD; + if (m_pImpl->m_pProps->bBool2) + nSub |= DATEFLD; + else + nSub |= TIMEFLD; + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DateTime); + SwDateTimeField *const pDTField = new SwDateTimeField( + static_cast<SwDateTimeFieldType*>(pFieldType), + nSub, m_pImpl->m_pProps->nFormat); + xField.reset(pDTField); + if (m_pImpl->m_pProps->fDouble > 0.) + { + pDTField->SetValue(m_pImpl->m_pProps->fDouble); + } + if (m_pImpl->m_pProps->pDateTime) + { + uno::Any aVal; aVal <<= *m_pImpl->m_pProps->pDateTime; + xField->PutValue( aVal, FIELD_PROP_DATE_TIME ); + } + pDTField->SetOffset(m_pImpl->m_pProps->nSubType); + } + break; + case SwServiceType::FieldTypeFileName: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Filename); + sal_Int32 nFormat = m_pImpl->m_pProps->nFormat; + if (m_pImpl->m_pProps->bBool2) + nFormat |= FF_FIXED; + SwFileNameField *const pFNField = new SwFileNameField( + static_cast<SwFileNameFieldType*>(pFieldType), nFormat); + xField.reset(pFNField); + if (!m_pImpl->m_pProps->sPar3.isEmpty()) + pFNField->SetExpansion(m_pImpl->m_pProps->sPar3); + uno::Any aFormat; + aFormat <<= m_pImpl->m_pProps->nFormat; + xField->PutValue( aFormat, FIELD_PROP_FORMAT ); + } + break; + case SwServiceType::FieldTypeTemplateName: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::TemplateName); + xField.reset(new SwTemplNameField(static_cast<SwTemplNameFieldType*>(pFieldType), + m_pImpl->m_pProps->nFormat)); + uno::Any aFormat; + aFormat <<= m_pImpl->m_pProps->nFormat; + xField->PutValue(aFormat, FIELD_PROP_FORMAT); + } + break; + case SwServiceType::FieldTypeChapter: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Chapter); + SwChapterField *const pChapterField = new SwChapterField( + static_cast<SwChapterFieldType*>(pFieldType), + m_pImpl->m_pProps->nUSHORT1); + xField.reset(pChapterField); + pChapterField->SetLevel(m_pImpl->m_pProps->nByte1); + uno::Any aVal; + aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT1); + xField->PutValue(aVal, FIELD_PROP_USHORT1 ); + } + break; + case SwServiceType::FieldTypeAuthor: + { + tools::Long nFormat = m_pImpl->m_pProps->bBool1 ? AF_NAME : AF_SHORTCUT; + if (m_pImpl->m_pProps->bBool2) + nFormat |= AF_FIXED; + + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Author); + SwAuthorField *const pAuthorField = new SwAuthorField( + static_cast<SwAuthorFieldType*>(pFieldType), nFormat); + xField.reset(pAuthorField); + pAuthorField->SetExpansion(m_pImpl->m_pProps->sPar1); + } + break; + case SwServiceType::FieldTypeConditionedText: + case SwServiceType::FieldTypeHiddenText: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenText); + SwHiddenTextField *const pHTField = new SwHiddenTextField( + static_cast<SwHiddenTextFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1, + m_pImpl->m_pProps->sPar2, m_pImpl->m_pProps->sPar3, + SwServiceType::FieldTypeHiddenText == m_pImpl->m_nServiceId ? + SwFieldTypesEnum::HiddenText : SwFieldTypesEnum::ConditionalText); + xField.reset(pHTField); + pHTField->SetValue(m_pImpl->m_pProps->bBool1); + uno::Any aVal; + aVal <<= m_pImpl->m_pProps->sPar4; + xField->PutValue(aVal, FIELD_PROP_PAR4 ); + } + break; + case SwServiceType::FieldTypeHiddenPara: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenPara); + SwHiddenParaField *const pHPField = new SwHiddenParaField( + static_cast<SwHiddenParaFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1); + xField.reset(pHPField); + pHPField->SetHidden(m_pImpl->m_pProps->bBool1); + } + break; + case SwServiceType::FieldTypeGetReference: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef); + xField.reset(new SwGetRefField(static_cast<SwGetRefFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1, + m_pImpl->m_pProps->sPar4, + 0, + 0, + 0, + 0)); + if (!m_pImpl->m_pProps->sPar3.isEmpty()) + static_cast<SwGetRefField*>(xField.get())->SetExpand(m_pImpl->m_pProps->sPar3); + uno::Any aVal; + aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT1); + xField->PutValue(aVal, FIELD_PROP_USHORT1 ); + aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT2); + xField->PutValue(aVal, FIELD_PROP_USHORT2 ); + aVal <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT3); + xField->PutValue(aVal, FIELD_PROP_USHORT3 ); + aVal <<= m_pImpl->m_pProps->nSHORT1; + xField->PutValue(aVal, FIELD_PROP_SHORT1 ); + } + break; + case SwServiceType::FieldTypeJumpEdit: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::JumpEdit); + xField.reset(new SwJumpEditField(static_cast<SwJumpEditFieldType*>(pFieldType), + m_pImpl->m_pProps->nUSHORT1, m_pImpl->m_pProps->sPar2, + m_pImpl->m_pProps->sPar1)); + } + break; + case SwServiceType::FieldTypeDocInfoChangeAuthor: + case SwServiceType::FieldTypeDocInfoChangeDateTime: + case SwServiceType::FieldTypeDocInfoEditTime: + case SwServiceType::FieldTypeDocInfoDescription: + case SwServiceType::FieldTypeDocInfoCreateAuthor: + case SwServiceType::FieldTypeDocInfoCreateDateTime: + case SwServiceType::FieldTypeDocInfoCustom: + case SwServiceType::FieldTypeDocInfoPrintAuthor: + case SwServiceType::FieldTypeDocInfoPrintDateTime: + case SwServiceType::FieldTypeDocInfoKeywords: + case SwServiceType::FieldTypeDocInfoSubject: + case SwServiceType::FieldTypeDocInfoTitle: + case SwServiceType::FieldTypeDocInfoRevision: + case SwServiceType::FieldTypeDocInfo: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocInfo); + sal_uInt16 nSubType = aDocInfoSubTypeFromService[ + static_cast<sal_uInt16>(m_pImpl->m_nServiceId) - sal_uInt16(SwServiceType::FieldTypeDocInfoChangeAuthor)]; + if (SwServiceType::FieldTypeDocInfoChangeDateTime == m_pImpl->m_nServiceId || + SwServiceType::FieldTypeDocInfoCreateDateTime == m_pImpl->m_nServiceId || + SwServiceType::FieldTypeDocInfoPrintDateTime == m_pImpl->m_nServiceId || + SwServiceType::FieldTypeDocInfoEditTime == m_pImpl->m_nServiceId) + { + if (m_pImpl->m_pProps->bBool2) //IsDate + { + nSubType &= 0xf0ff; + nSubType |= DI_SUB_DATE; + } + else + { + nSubType &= 0xf0ff; + nSubType |= DI_SUB_TIME; + } + } + if (m_pImpl->m_pProps->bBool1) + nSubType |= DI_SUB_FIXED; + xField.reset(new SwDocInfoField( + static_cast<SwDocInfoFieldType*>(pFieldType), nSubType, + m_pImpl->m_pProps->sPar4, m_pImpl->m_pProps->nFormat)); + if (!m_pImpl->m_pProps->sPar3.isEmpty()) + static_cast<SwDocInfoField*>(xField.get())->SetExpansion(m_pImpl->m_pProps->sPar3); + } + break; + case SwServiceType::FieldTypeUserExt: + { + sal_Int32 nFormat = 0; + if (m_pImpl->m_pProps->bBool1) + nFormat = AF_FIXED; + + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::ExtUser); + SwExtUserField *const pEUField = new SwExtUserField( + static_cast<SwExtUserFieldType*>(pFieldType), + m_pImpl->m_pProps->nUSHORT1, nFormat); + xField.reset(pEUField); + pEUField->SetExpansion(m_pImpl->m_pProps->sPar1); + } + break; + case SwServiceType::FieldTypeUser: + { + SwFieldType* pFieldType = + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::User, m_pImpl->m_sTypeName, true); + if (!pFieldType) + throw uno::RuntimeException(); + sal_uInt16 nUserSubType = (m_pImpl->m_pProps->bBool1) + ? nsSwExtendedSubType::SUB_INVISIBLE : 0; + if (m_pImpl->m_pProps->bBool2) + nUserSubType |= nsSwExtendedSubType::SUB_CMD; + if (m_pImpl->m_pProps->bFormatIsDefault && + nsSwGetSetExpType::GSE_STRING == static_cast<SwUserFieldType*>(pFieldType)->GetType()) + { + m_pImpl->m_pProps->nFormat = -1; + } + xField.reset(new SwUserField(static_cast<SwUserFieldType*>(pFieldType), + nUserSubType, + m_pImpl->m_pProps->nFormat)); + } + break; + case SwServiceType::FieldTypeRefPageSet: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::RefPageSet); + xField.reset(new SwRefPageSetField( static_cast<SwRefPageSetFieldType*>(pFieldType), + m_pImpl->m_pProps->nUSHORT1, + m_pImpl->m_pProps->bBool1 )); + } + break; + case SwServiceType::FieldTypeRefPageGet: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::RefPageGet); + SwRefPageGetField *const pRGField = new SwRefPageGetField( + static_cast<SwRefPageGetFieldType*>(pFieldType), + m_pImpl->m_pProps->nUSHORT1 ); + xField.reset(pRGField); + pRGField->SetText(m_pImpl->m_pProps->sPar1, nullptr); + } + break; + case SwServiceType::FieldTypePageNum: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::PageNumber); + SwPageNumberField *const pPNField = new SwPageNumberField( + static_cast<SwPageNumberFieldType*>(pFieldType), PG_RANDOM, + m_pImpl->m_pProps->nFormat, + m_pImpl->m_pProps->nUSHORT1); + xField.reset(pPNField); + pPNField->SetUserString(m_pImpl->m_pProps->sPar1); + uno::Any aVal; + aVal <<= m_pImpl->m_pProps->nSubType; + xField->PutValue( aVal, FIELD_PROP_SUBTYPE ); + } + break; + case SwServiceType::FieldTypeDDE: + { + SwFieldType* pFieldType = + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Dde, m_pImpl->m_sTypeName, true); + if (!pFieldType) + throw uno::RuntimeException(); + xField.reset(new SwDDEField( static_cast<SwDDEFieldType*>(pFieldType) )); + } + break; + case SwServiceType::FieldTypeDatabaseName: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DatabaseName); + SwDBData aData; + aData.sDataSource = m_pImpl->m_pProps->sPar1; + aData.sCommand = m_pImpl->m_pProps->sPar2; + aData.nCommandType = m_pImpl->m_pProps->nSHORT1; + xField.reset(new SwDBNameField(static_cast<SwDBNameFieldType*>(pFieldType), aData)); + sal_uInt16 nSubType = xField->GetSubType(); + if (m_pImpl->m_pProps->bBool2) + nSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE; + else + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + xField->SetSubType(nSubType); + } + break; + case SwServiceType::FieldTypeDatabaseNextSet: + { + SwDBData aData; + aData.sDataSource = m_pImpl->m_pProps->sPar1; + aData.sCommand = m_pImpl->m_pProps->sPar2; + aData.nCommandType = m_pImpl->m_pProps->nSHORT1; + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DbNextSet); + xField.reset(new SwDBNextSetField(static_cast<SwDBNextSetFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar3, aData)); + } + break; + case SwServiceType::FieldTypeDatabaseNumSet: + { + SwDBData aData; + aData.sDataSource = m_pImpl->m_pProps->sPar1; + aData.sCommand = m_pImpl->m_pProps->sPar2; + aData.nCommandType = m_pImpl->m_pProps->nSHORT1; + xField.reset(new SwDBNumSetField( static_cast<SwDBNumSetFieldType*>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DbNumSet)), + m_pImpl->m_pProps->sPar3, + OUString::number(m_pImpl->m_pProps->nFormat), + aData )); + } + break; + case SwServiceType::FieldTypeDatabaseSetNum: + { + SwDBData aData; + aData.sDataSource = m_pImpl->m_pProps->sPar1; + aData.sCommand = m_pImpl->m_pProps->sPar2; + aData.nCommandType = m_pImpl->m_pProps->nSHORT1; + SwDBSetNumberField *const pDBSNField = + new SwDBSetNumberField(static_cast<SwDBSetNumberFieldType*>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DbSetNumber)), aData, + m_pImpl->m_pProps->nUSHORT1); + xField.reset(pDBSNField); + pDBSNField->SetSetNumber(m_pImpl->m_pProps->nFormat); + sal_uInt16 nSubType = xField->GetSubType(); + if (m_pImpl->m_pProps->bBool2) + nSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE; + else + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + xField->SetSubType(nSubType); + } + break; + case SwServiceType::FieldTypeDatabase: + { + SwFieldType* pFieldType = + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Database, m_pImpl->m_sTypeName, false); + if (!pFieldType) + throw uno::RuntimeException(); + xField.reset(new SwDBField(static_cast<SwDBFieldType*>(pFieldType), + m_pImpl->m_pProps->nFormat)); + static_cast<SwDBField*>(xField.get())->InitContent(m_pImpl->m_pProps->sPar1); + sal_uInt16 nSubType = xField->GetSubType(); + if (m_pImpl->m_pProps->bBool2) + nSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE; + else + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + xField->SetSubType(nSubType); + } + break; + case SwServiceType::FieldTypeSetExp: + { + SwFieldType* pFieldType = + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, m_pImpl->m_sTypeName, true); + if (!pFieldType) + throw uno::RuntimeException(); + // detect the field type's sub type and set an appropriate number format + if (m_pImpl->m_pProps->bFormatIsDefault && + nsSwGetSetExpType::GSE_STRING == static_cast<SwSetExpFieldType*>(pFieldType)->GetType()) + { + m_pImpl->m_pProps->nFormat = -1; + } + SwSetExpField *const pSEField = new SwSetExpField( + static_cast<SwSetExpFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar2, + m_pImpl->m_pProps->nUSHORT2 != USHRT_MAX ? //#i79471# the field can have a number format or a number_ing_ format + m_pImpl->m_pProps->nUSHORT2 : m_pImpl->m_pProps->nFormat); + xField.reset(pSEField); + + sal_uInt16 nSubType = xField->GetSubType(); + if (m_pImpl->m_pProps->bBool2) + nSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE; + else + nSubType |= nsSwExtendedSubType::SUB_INVISIBLE; + if (m_pImpl->m_pProps->bBool3) + nSubType |= nsSwExtendedSubType::SUB_CMD; + else + nSubType &= ~nsSwExtendedSubType::SUB_CMD; + xField->SetSubType(nSubType); + pSEField->SetSeqNumber(m_pImpl->m_pProps->nUSHORT1); + pSEField->SetInputFlag(m_pImpl->m_pProps->bBool1); + pSEField->SetPromptText(m_pImpl->m_pProps->sPar3); + if (!m_pImpl->m_pProps->sPar4.isEmpty()) + pSEField->ChgExpStr(m_pImpl->m_pProps->sPar4, nullptr); + + } + break; + case SwServiceType::FieldTypeGetExp: + { + sal_uInt16 nSubType; + switch (m_pImpl->m_pProps->nSubType) + { + case text::SetVariableType::STRING: nSubType = nsSwGetSetExpType::GSE_STRING; break; + case text::SetVariableType::VAR: nSubType = nsSwGetSetExpType::GSE_EXPR; break; + //case text::SetVariableType::SEQUENCE: nSubType = nsSwGetSetExpType::GSE_SEQ; break; + case text::SetVariableType::FORMULA: nSubType = nsSwGetSetExpType::GSE_FORMULA; break; + default: + OSL_FAIL("wrong value"); + nSubType = nsSwGetSetExpType::GSE_EXPR; + } + //make sure the SubType matches the field type + SwFieldType* pSetExpField = pDoc->getIDocumentFieldsAccess().GetFieldType( + SwFieldIds::SetExp, m_pImpl->m_pProps->sPar1, false); + bool bSetGetExpFieldUninitialized = false; + if (pSetExpField) + { + if (nSubType != nsSwGetSetExpType::GSE_STRING && + static_cast< SwSetExpFieldType* >(pSetExpField)->GetType() == nsSwGetSetExpType::GSE_STRING) + nSubType = nsSwGetSetExpType::GSE_STRING; + } + else + bSetGetExpFieldUninitialized = true; // #i82544# + + if (m_pImpl->m_pProps->bBool2) + nSubType |= nsSwExtendedSubType::SUB_CMD; + else + nSubType &= ~nsSwExtendedSubType::SUB_CMD; + SwGetExpField *const pGEField = new SwGetExpField( + static_cast<SwGetExpFieldType*>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetExp)), + m_pImpl->m_pProps->sPar1, nSubType, + m_pImpl->m_pProps->nFormat); + xField.reset(pGEField); + //TODO: evaluate SubType! + if (!m_pImpl->m_pProps->sPar4.isEmpty()) + pGEField->ChgExpStr(m_pImpl->m_pProps->sPar4, nullptr); + // #i82544# + if (bSetGetExpFieldUninitialized) + pGEField->SetLateInitialization(); + } + break; + case SwServiceType::FieldTypeInputUser: + case SwServiceType::FieldTypeInput: + { + SwFieldType* pFieldType = + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Input, m_pImpl->m_sTypeName, true); + if (!pFieldType) + throw uno::RuntimeException(); + sal_uInt16 nInpSubType = + sal::static_int_cast<sal_uInt16>( + SwServiceType::FieldTypeInputUser == m_pImpl->m_nServiceId + ? INP_USR : INP_TXT); + SwInputField * pTextField = + new SwInputField(static_cast<SwInputFieldType*>(pFieldType), + m_pImpl->m_pProps->sPar1, + m_pImpl->m_pProps->sPar2, + nInpSubType); + pTextField->SetHelp(m_pImpl->m_pProps->sPar3); + pTextField->SetToolTip(m_pImpl->m_pProps->sPar4); + + xField.reset(pTextField); + } + break; + case SwServiceType::FieldTypeMacro: + { + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Macro); + OUString aName; + + // support for Scripting Framework macros + if (!m_pImpl->m_pProps->sPar4.isEmpty()) + { + aName = m_pImpl->m_pProps->sPar4; + } + else + { + SwMacroField::CreateMacroString(aName, + m_pImpl->m_pProps->sPar1, m_pImpl->m_pProps->sPar3); + } + xField.reset(new SwMacroField(static_cast<SwMacroFieldType*>(pFieldType), aName, + m_pImpl->m_pProps->sPar2)); + } + break; + case SwServiceType::FieldTypePageCount: + case SwServiceType::FieldTypeParagraphCount: + case SwServiceType::FieldTypeWordCount: + case SwServiceType::FieldTypeCharacterCount: + case SwServiceType::FieldTypeTableCount: + case SwServiceType::FieldTypeGraphicObjectCount: + case SwServiceType::FieldTypeEmbeddedObjectCount: + { + sal_uInt16 nSubType = DS_PAGE; + switch (m_pImpl->m_nServiceId) + { + case SwServiceType::FieldTypeParagraphCount : nSubType = DS_PARA; break; + case SwServiceType::FieldTypeWordCount : nSubType = DS_WORD; break; + case SwServiceType::FieldTypeCharacterCount : nSubType = DS_CHAR; break; + case SwServiceType::FieldTypeTableCount : nSubType = DS_TBL; break; + case SwServiceType::FieldTypeGraphicObjectCount : nSubType = DS_GRF; break; + case SwServiceType::FieldTypeEmbeddedObjectCount : nSubType = DS_OLE; break; + default: break; + } + SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocStat); + xField.reset(new SwDocStatField( + static_cast<SwDocStatFieldType*>(pFieldType), + nSubType, m_pImpl->m_pProps->nUSHORT2)); + } + break; + case SwServiceType::FieldTypeBibliography: + { + SwAuthorityFieldType const type(pDoc); + xField.reset(new SwAuthorityField(static_cast<SwAuthorityFieldType*>( + pDoc->getIDocumentFieldsAccess().InsertFieldType(type)), + u"")); + if (m_pImpl->m_pProps->aPropSeq.hasElements()) + { + uno::Any aVal; + aVal <<= m_pImpl->m_pProps->aPropSeq; + xField->PutValue( aVal, FIELD_PROP_PROP_SEQ ); + } + } + break; + case SwServiceType::FieldTypeCombinedCharacters: + // create field + xField.reset(new SwCombinedCharField( static_cast<SwCombinedCharFieldType*>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::CombinedChars)), + m_pImpl->m_pProps->sPar1)); + break; + case SwServiceType::FieldTypeDropdown: + { + SwDropDownField *const pDDField = new SwDropDownField( + static_cast<SwDropDownFieldType *>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Dropdown))); + xField.reset(pDDField); + + pDDField->SetItems(m_pImpl->m_pProps->aStrings); + pDDField->SetSelectedItem(m_pImpl->m_pProps->sPar1); + pDDField->SetName(m_pImpl->m_pProps->sPar2); + pDDField->SetHelp(m_pImpl->m_pProps->sPar3); + pDDField->SetToolTip(m_pImpl->m_pProps->sPar4); + } + break; + + case SwServiceType::FieldTypeTableFormula: + { + // create field + sal_uInt16 nType = nsSwGetSetExpType::GSE_FORMULA; + if (m_pImpl->m_pProps->bBool1) + { + nType |= nsSwExtendedSubType::SUB_CMD; + if (m_pImpl->m_pProps->bFormatIsDefault) + m_pImpl->m_pProps->nFormat = -1; + } + xField.reset(new SwTableField( static_cast<SwTableFieldType*>( + pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Table)), + m_pImpl->m_pProps->sPar2, + nType, + m_pImpl->m_pProps->nFormat)); + static_cast<SwTableField*>(xField.get())->ChgExpStr(m_pImpl->m_pProps->sPar1); + } + break; + default: OSL_FAIL("What kind of type is that?"); + } + + if (!xField) + throw uno::RuntimeException("no SwField created?"); + + xField->SetAutomaticLanguage(!m_pImpl->m_pProps->bBool4); + SwFormatField aFormat(*xField); + + UnoActionContext aCont(pDoc); + if (aPam.HasMark() && + m_pImpl->m_nServiceId != SwServiceType::FieldTypeAnnotation) + { + pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); + } + + SwXTextCursor const*const pTextCursor(dynamic_cast<SwXTextCursor*>(pCursor)); + const bool bForceExpandHints( + pTextCursor + && pTextCursor->IsAtEndOfMeta() ); + const SetAttrMode nInsertFlags = + bForceExpandHints + ? SetAttrMode::FORCEHINTEXPAND + : SetAttrMode::DEFAULT; + + if (*aPam.GetPoint() != *aPam.GetMark() && + m_pImpl->m_nServiceId == SwServiceType::FieldTypeAnnotation) + { + // Make sure we always insert the field at the end + SwPaM aEnd(*aPam.End(), *aPam.End()); + pDoc->getIDocumentContentOperations().InsertPoolItem(aEnd, aFormat, nInsertFlags); + } + else + pDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aFormat, nInsertFlags); + + SwTextAttr* pTextAttr = aPam.GetPointNode().GetTextNode()->GetFieldTextAttrAt(aPam.GetPoint()->GetContentIndex()-1, ::sw::GetTextAttrMode::Default); + + // What about updating the fields? (see fldmgr.cxx) + if (!pTextAttr) + throw uno::RuntimeException("no SwTextAttr inserted?"); // could theoretically happen, if paragraph is full + + m_pImpl->ClearFieldType(); + const SwFormatField& rField = pTextAttr->GetFormatField(); + m_pImpl->SetFormatField(const_cast<SwFormatField*>(&rField), pDoc); + + if ( pTextAttr->Which() == RES_TXTATR_ANNOTATION + && *aPam.GetPoint() != *aPam.GetMark() ) + { + // create annotation mark + const SwPostItField* pPostItField = dynamic_cast< const SwPostItField* >(pTextAttr->GetFormatField().GetField()); + OSL_ENSURE( pPostItField != nullptr, "<SwXTextField::attachToRange(..)> - annotation field missing!" ); + if ( pPostItField != nullptr ) + { + IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess(); + pMarksAccess->makeAnnotationMark( aPam, pPostItField->GetName() ); + } + } + + xField.reset(); + + assert(m_pImpl->GetFormatField()); + m_pImpl->m_pDoc = pDoc; + m_pImpl->GetFormatField()->SetXTextField(this); + m_pImpl->m_wThis = this; + m_pImpl->m_bIsDescriptor = false; + m_pImpl->m_pProps.reset(); + if (m_pImpl->m_bCallUpdate) + update(); + } + else if ( !m_pImpl->IsDescriptor() + && m_pImpl->m_pDoc != nullptr + && m_pImpl->m_nServiceId == SwServiceType::FieldTypeAnnotation ) + { + SwDoc* pDoc = m_pImpl->m_pDoc; + SwUnoInternalPaM aIntPam( *pDoc ); + if ( !::sw::XTextRangeToSwPaM( aIntPam, xTextRange ) ) + throw lang::IllegalArgumentException(); + + // Nothing to do, if the text range has a separate start and end, but they have the same + // value. + if (!aIntPam.HasMark() || *aIntPam.Start() != *aIntPam.End()) + { + UnoActionContext aCont( pDoc ); + // insert copy of annotation at new text range + std::unique_ptr<SwPostItField> pPostItField(static_cast< SwPostItField* >(m_pImpl->GetFormatField()->GetField()->CopyField().release())); + SwFormatField aFormatField( *pPostItField ); + pPostItField.reset(); + SwPaM aEnd( *aIntPam.End(), *aIntPam.End() ); + pDoc->getIDocumentContentOperations().InsertPoolItem( aEnd, aFormatField ); + // delete former annotation + { + const SwTextField* pTextField = m_pImpl->GetFormatField()->GetTextField(); + SwTextNode& rTextNode = *pTextField->GetpTextNode(); + SwPaM aPam( rTextNode, pTextField->GetStart() ); + aPam.SetMark(); + aPam.Move(); + pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); + } + // keep inserted annotation + { + SwTextField *const pTextAttr = aEnd.GetPointNode().GetTextNode()->GetFieldTextAttrAt(aEnd.End()->GetContentIndex()-1, ::sw::GetTextAttrMode::Default); + if ( pTextAttr != nullptr ) + { + m_pImpl->SetFormatField(const_cast<SwFormatField*>(&pTextAttr->GetFormatField()), pDoc); + + if ( *aIntPam.GetPoint() != *aIntPam.GetMark() ) + { + // create annotation mark + const SwPostItField* pField = dynamic_cast< const SwPostItField* >(pTextAttr->GetFormatField().GetField()); + OSL_ENSURE( pField != nullptr, "<SwXTextField::attach(..)> - annotation field missing!" ); + if ( pField != nullptr ) + { + IDocumentMarkAccess* pMarksAccess = aIntPam.GetDoc().getIDocumentMarkAccess(); + pMarksAccess->makeAnnotationMark( aIntPam, pField->GetName() ); + } + } + } + } + } + + } + else + throw lang::IllegalArgumentException(); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextField::getAnchor() +{ + SolarMutexGuard aGuard; + + SwField const*const pField = m_pImpl->GetField(); + if (!pField) + return nullptr; + + const SwTextField* pTextField = m_pImpl->GetFormatField()->GetTextField(); + if (!pTextField) + throw uno::RuntimeException(); + + std::shared_ptr< SwPaM > pPamForTextField; + SwTextField::GetPamForTextField(*pTextField, pPamForTextField); + if (pPamForTextField == nullptr) + return nullptr; + + // If this is a postit field, then return the range of its annotation mark if it has one. + if (pField->Which() == SwFieldIds::Postit) + { + const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pField); + IDocumentMarkAccess* pMarkAccess = m_pImpl->m_pDoc->getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAnnotationMarksBegin(); ppMark != pMarkAccess->getAnnotationMarksEnd(); ++ppMark) + { + if ((*ppMark)->GetName() == pPostItField->GetName()) + { + pPamForTextField = std::make_shared<SwPaM>((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd()); + break; + } + } + } + + rtl::Reference<SwXTextRange> xRange = SwXTextRange::CreateXTextRange( + *m_pImpl->m_pDoc, *(pPamForTextField->GetPoint()), pPamForTextField->GetMark()); + return xRange; +} + +void SAL_CALL SwXTextField::dispose() +{ + SolarMutexGuard aGuard; + SwField const*const pField = m_pImpl->GetField(); + if(pField && m_pImpl->m_pDoc) + { + UnoActionContext aContext(m_pImpl->m_pDoc); + assert(m_pImpl->GetFormatField()->GetTextField() && "<SwXTextField::dispose()> - missing <SwTextField> --> crash"); + SwTextField::DeleteTextField(*(m_pImpl->GetFormatField()->GetTextField())); + } + + if (m_pImpl->m_xTextObject.is()) + { + m_pImpl->m_xTextObject->DisposeEditSource(); + m_pImpl->m_xTextObject.clear(); + } + m_pImpl->Invalidate(); +} + +void SAL_CALL SwXTextField::addEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXTextField::removeEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXTextField::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + // no static + uno::Reference< beans::XPropertySetInfo > aRef; + if (m_pImpl->m_nServiceId == SwServiceType::Invalid) + { + throw uno::RuntimeException(); + } + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet( + lcl_GetPropertyMapOfService(m_pImpl->m_nServiceId)); + const uno::Reference<beans::XPropertySetInfo>& xInfo = pPropSet->getPropertySetInfo(); + // extend PropertySetInfo! + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + aRef = new SfxExtItemPropertySetInfo( + aSwMapProvider.GetPropertyMapEntries(PROPERTY_MAP_PARAGRAPH_EXTENSIONS), + aPropSeq ); + return aRef; +} + +void SAL_CALL +SwXTextField::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + SwField const*const pField = m_pImpl->GetField(); + const SfxItemPropertySet* _pPropSet = aSwMapProvider.GetPropertySet( + lcl_GetPropertyMapOfService(m_pImpl->m_nServiceId)); + const SfxItemPropertyMapEntry* pEntry = _pPropSet->getPropertyMap().getByName(rPropertyName); + + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException( "Property is read-only: " + rPropertyName, getXWeak() ); + + if(pField) + { + // special treatment for mail merge fields + const SwFieldIds nWhich = pField->Which(); + if( SwFieldIds::Database == nWhich && + (rPropertyName == UNO_NAME_DATA_BASE_NAME || + rPropertyName == UNO_NAME_DATA_BASE_URL|| + rPropertyName == UNO_NAME_DATA_TABLE_NAME|| + rPropertyName == UNO_NAME_DATA_COLUMN_NAME)) + { + // here a new field type must be created and the field must + // be registered at the new type + OSL_FAIL("not implemented"); + } + else + { + SwDoc * pDoc = m_pImpl->m_pDoc; + assert(pDoc); + const SwTextField* pTextField = m_pImpl->GetFormatField()->GetTextField(); + if(!pTextField) + throw uno::RuntimeException(); + SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() ); + pDoc->getIDocumentFieldsAccess().PutValueToField( aPosition, rValue, pEntry->nWID); + } + + //#i100374# notify SwPostIt about new field content + assert(m_pImpl->GetFormatField()); + if (SwFieldIds::Postit == nWhich) + { + m_pImpl->GetFormatField()->Broadcast( + SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::CHANGED )); + } + + // fdo#42073 notify SwTextField about changes of the expanded string + if (m_pImpl->GetFormatField()->GetTextField()) + { + m_pImpl->GetFormatField()->GetTextField()->ExpandTextField(); + } + + //#i100374# changing a document field should set the modify flag + SwDoc* pDoc = m_pImpl->m_pDoc; + if (pDoc) + pDoc->getIDocumentState().SetModified(); + + } + else if (m_pImpl->m_pProps) + { + bool* pBool = nullptr; + switch(pEntry->nWID) + { + case FIELD_PROP_PAR1: + rValue >>= m_pImpl->m_pProps->sPar1; + break; + case FIELD_PROP_PAR2: + rValue >>= m_pImpl->m_pProps->sPar2; + break; + case FIELD_PROP_PAR3: + rValue >>= m_pImpl->m_pProps->sPar3; + break; + case FIELD_PROP_PAR4: + rValue >>= m_pImpl->m_pProps->sPar4; + break; + case FIELD_PROP_PAR7: + rValue >>= m_pImpl->m_pProps->sPar7; + break; + case FIELD_PROP_PAR5: + rValue >>= m_pImpl->m_pProps->sPar5; + break; + case FIELD_PROP_PAR6: + rValue >>= m_pImpl->m_pProps->sPar6; + break; + case FIELD_PROP_FORMAT: + rValue >>= m_pImpl->m_pProps->nFormat; + m_pImpl->m_pProps->bFormatIsDefault = false; + break; + case FIELD_PROP_SUBTYPE: + m_pImpl->m_pProps->nSubType = SWUnoHelper::GetEnumAsInt32(rValue); + break; + case FIELD_PROP_BYTE1 : + rValue >>= m_pImpl->m_pProps->nByte1; + break; + case FIELD_PROP_BOOL1 : + pBool = &m_pImpl->m_pProps->bBool1; + break; + case FIELD_PROP_BOOL2 : + pBool = &m_pImpl->m_pProps->bBool2; + break; + case FIELD_PROP_BOOL3 : + pBool = &m_pImpl->m_pProps->bBool3; + break; + case FIELD_PROP_BOOL4: + pBool = &m_pImpl->m_pProps->bBool4; + break; + case FIELD_PROP_DATE : + { + auto aTemp = o3tl::tryAccess<util::Date>(rValue); + if(!aTemp) + throw lang::IllegalArgumentException(); + + m_pImpl->m_pProps->aDate = Date(aTemp->Day, aTemp->Month, aTemp->Year); + } + break; + case FIELD_PROP_USHORT1: + case FIELD_PROP_USHORT2: + case FIELD_PROP_USHORT3: + { + sal_Int16 nVal = 0; + rValue >>= nVal; + if( FIELD_PROP_USHORT1 == pEntry->nWID) + m_pImpl->m_pProps->nUSHORT1 = nVal; + else if( FIELD_PROP_USHORT2 == pEntry->nWID) + m_pImpl->m_pProps->nUSHORT2 = nVal; + else + m_pImpl->m_pProps->nUSHORT3 = nVal; + } + break; + case FIELD_PROP_SHORT1: + rValue >>= m_pImpl->m_pProps->nSHORT1; + break; + case FIELD_PROP_DOUBLE: + if(rValue.getValueType() != ::cppu::UnoType<double>::get()) + throw lang::IllegalArgumentException(); + rValue >>= m_pImpl->m_pProps->fDouble; + break; + + case FIELD_PROP_DATE_TIME : + if (!m_pImpl->m_pProps->pDateTime) + m_pImpl->m_pProps->pDateTime.reset( new util::DateTime ); + rValue >>= *m_pImpl->m_pProps->pDateTime; + break; + case FIELD_PROP_PROP_SEQ: + rValue >>= m_pImpl->m_pProps->aPropSeq; + break; + case FIELD_PROP_STRINGS: + rValue >>= m_pImpl->m_pProps->aStrings; + break; + } + if (pBool) + { + std::optional<const bool> b = o3tl::tryAccess<bool>(rValue); + if( !b.has_value() ) + throw lang::IllegalArgumentException(); + *pBool = *b; + + } + } + else + throw uno::RuntimeException(); +} + +uno::Any SAL_CALL SwXTextField::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwField const*const pField = m_pImpl->GetField(); + const SfxItemPropertySet* _pPropSet = aSwMapProvider.GetPropertySet( + lcl_GetPropertyMapOfService(m_pImpl->m_nServiceId)); + const SfxItemPropertyMapEntry* pEntry = _pPropSet->getPropertyMap().getByName(rPropertyName); + if(!pEntry ) + { + const SfxItemPropertySet* _pParaPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH_EXTENSIONS); + pEntry = _pParaPropSet->getPropertyMap().getByName(rPropertyName); + } + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + + switch( pEntry->nWID ) + { + case FN_UNO_TEXT_WRAP: + aRet <<= text::WrapTextMode_NONE; + break; + case FN_UNO_ANCHOR_TYPE: + aRet <<= text::TextContentAnchorType_AS_CHARACTER; + break; + case FN_UNO_ANCHOR_TYPES: + { + uno::Sequence<text::TextContentAnchorType> aTypes { text::TextContentAnchorType_AS_CHARACTER }; + aRet <<= aTypes; + } + break; + + default: + if( pField ) + { + if (FIELD_PROP_IS_FIELD_USED == pEntry->nWID || + FIELD_PROP_IS_FIELD_DISPLAYED == pEntry->nWID) + { + bool bIsFieldUsed = false; + bool bIsFieldDisplayed = false; + + // in order to have the information about fields + // correctly evaluated the document needs a layout + // (has to be already formatted) + SwDoc *pDoc = m_pImpl->m_pDoc; + SwViewShell *pViewShell = nullptr; + SwEditShell *pEditShell = nullptr; + if( pDoc ) + { + pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + pEditShell = pDoc->GetEditShell(); + } + + if (pEditShell) + pEditShell->CalcLayout(); + else if (pViewShell) // a page preview has no SwEditShell it should only have a view shell + pViewShell->CalcLayout(); + else + throw uno::RuntimeException(); + + // get text node for the text field + const SwFormatField *pFieldFormat = + (m_pImpl->GetField()) ? m_pImpl->GetFormatField() : nullptr; + const SwTextField* pTextField = pFieldFormat + ? m_pImpl->GetFormatField()->GetTextField() : nullptr; + if(!pTextField) + throw uno::RuntimeException(); + const SwTextNode& rTextNode = pTextField->GetTextNode(); + + // skip fields that are currently not in the document + // e.g. fields in undo or redo array + if (rTextNode.GetNodes().IsDocNodes()) + { + bool bFrame = 0 != rTextNode.FindLayoutRect().Width(); // or so + bool bHidden = rTextNode.IsHidden(); + if ( !bHidden ) + { + sal_Int32 nHiddenStart; + sal_Int32 nHiddenEnd; + bHidden = SwScriptInfo::GetBoundsOfHiddenRange( pTextField->GetTextNode(), + pTextField->GetStart(), + nHiddenStart, nHiddenEnd ); + } + + // !bFrame && !bHidden: most probably a field in an unused page style + + // FME: Problem: hidden field in unused page template => + // bIsFieldUsed = true + // bIsFieldDisplayed = false + bIsFieldUsed = bFrame || bHidden; + bIsFieldDisplayed = bIsFieldUsed && !bHidden; + } + aRet <<= (FIELD_PROP_IS_FIELD_USED == pEntry->nWID) ? bIsFieldUsed : bIsFieldDisplayed; + } + else + pField->QueryValue( aRet, pEntry->nWID ); + } + else if (m_pImpl->m_pProps) // currently just a descriptor... + { + switch(pEntry->nWID) + { + case FIELD_PROP_TEXT: + { + if (!m_pImpl->m_xTextObject.is()) + { + m_pImpl->m_xTextObject + = new SwTextAPIObject( std::make_unique<SwTextAPIEditSource>(m_pImpl->m_pDoc) ); + } + + uno::Reference<text::XText> xText(m_pImpl->m_xTextObject); + aRet <<= xText; + break; + } + case FIELD_PROP_PAR1: + aRet <<= m_pImpl->m_pProps->sPar1; + break; + case FIELD_PROP_PAR2: + aRet <<= m_pImpl->m_pProps->sPar2; + break; + case FIELD_PROP_PAR3: + aRet <<= m_pImpl->m_pProps->sPar3; + break; + case FIELD_PROP_PAR4: + aRet <<= m_pImpl->m_pProps->sPar4; + break; + case FIELD_PROP_PAR7: + aRet <<= m_pImpl->m_pProps->sPar7; + break; + case FIELD_PROP_PAR5: + aRet <<= m_pImpl->m_pProps->sPar5; + break; + case FIELD_PROP_PAR6: + aRet <<= m_pImpl->m_pProps->sPar6; + break; + case FIELD_PROP_FORMAT: + aRet <<= m_pImpl->m_pProps->nFormat; + break; + case FIELD_PROP_SUBTYPE: + aRet <<= m_pImpl->m_pProps->nSubType; + break; + case FIELD_PROP_BYTE1 : + aRet <<= m_pImpl->m_pProps->nByte1; + break; + case FIELD_PROP_BOOL1 : + aRet <<= m_pImpl->m_pProps->bBool1; + break; + case FIELD_PROP_BOOL2 : + aRet <<= m_pImpl->m_pProps->bBool2; + break; + case FIELD_PROP_BOOL3 : + aRet <<= m_pImpl->m_pProps->bBool3; + break; + case FIELD_PROP_BOOL4 : + aRet <<= m_pImpl->m_pProps->bBool4; + break; + case FIELD_PROP_DATE : + aRet <<= m_pImpl->m_pProps->aDate.GetUNODate(); + break; + case FIELD_PROP_USHORT1: + aRet <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT1); + break; + case FIELD_PROP_USHORT2: + aRet <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT2); + break; + case FIELD_PROP_USHORT3: + aRet <<= static_cast<sal_Int16>(m_pImpl->m_pProps->nUSHORT3); + break; + case FIELD_PROP_SHORT1: + aRet <<= m_pImpl->m_pProps->nSHORT1; + break; + case FIELD_PROP_DOUBLE: + aRet <<= m_pImpl->m_pProps->fDouble; + break; + case FIELD_PROP_DATE_TIME : + if (m_pImpl->m_pProps->pDateTime) + aRet <<= *m_pImpl->m_pProps->pDateTime; + break; + case FIELD_PROP_PROP_SEQ: + aRet <<= m_pImpl->m_pProps->aPropSeq; + break; + case FIELD_PROP_STRINGS: + aRet <<= m_pImpl->m_pProps->aStrings; + break; + case FIELD_PROP_IS_FIELD_USED: + case FIELD_PROP_IS_FIELD_DISPLAYED: + aRet <<= false; + break; + } + } + else + throw uno::RuntimeException(); + } + return aRet; +} + +void SwXTextField::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextField::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextField::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextField::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL SwXTextField::update() +{ + SolarMutexGuard aGuard; + SwField * pField = const_cast<SwField*>(m_pImpl->GetField()); + if (pField) + { + switch(pField->Which()) + { + case SwFieldIds::DateTime: + static_cast<SwDateTimeField*>(pField)->SetDateTime( ::DateTime( ::DateTime::SYSTEM ) ); + break; + + case SwFieldIds::ExtUser: + { + SwExtUserField* pExtUserField = static_cast<SwExtUserField*>(pField); + pExtUserField->SetExpansion( SwExtUserFieldType::Expand( + pExtUserField->GetSubType() ) ); + } + break; + + case SwFieldIds::Author: + { + SwAuthorField* pAuthorField = static_cast<SwAuthorField*>(pField); + pAuthorField->SetExpansion( SwAuthorFieldType::Expand( + pAuthorField->GetFormat() ) ); + } + break; + + case SwFieldIds::Filename: + { + SwFileNameField* pFileNameField = static_cast<SwFileNameField*>(pField); + pFileNameField->SetExpansion( static_cast<SwFileNameFieldType*>(pField->GetTyp())->Expand( + pFileNameField->GetFormat() ) ); + } + break; + + case SwFieldIds::DocInfo: + { + SwDocInfoField* pDocInfField = static_cast<SwDocInfoField*>(pField); + pDocInfField->SetExpansion( static_cast<SwDocInfoFieldType*>(pField->GetTyp())->Expand( + pDocInfField->GetSubType(), + pDocInfField->GetFormat(), + pDocInfField->GetLanguage(), + pDocInfField->GetName() ) ); + } + break; + default: break; + } + // Text formatting has to be triggered. + m_pImpl->GetFormatField()->ForceUpdateTextNode(); + } + else + m_pImpl->m_bCallUpdate = true; +} + +OUString SAL_CALL SwXTextField::getImplementationName() +{ + return "SwXTextField"; +} + +static OUString OldNameToNewName_Impl( const OUString &rOld ) +{ + static const char aOldNamePart1[] = ".TextField.DocInfo."; + static const char aOldNamePart2[] = ".TextField."; + OUString sServiceNameCC( rOld ); + sal_Int32 nIdx = sServiceNameCC.indexOf( aOldNamePart1 ); + if (nIdx >= 0) + sServiceNameCC = sServiceNameCC.replaceAt( nIdx, strlen(aOldNamePart1), u".textfield.docinfo." ); + nIdx = sServiceNameCC.indexOf( aOldNamePart2 ); + if (nIdx >= 0) + sServiceNameCC = sServiceNameCC.replaceAt( nIdx, strlen(aOldNamePart2), u".textfield." ); + return sServiceNameCC; +} + +sal_Bool SAL_CALL SwXTextField::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SwXTextField::getSupportedServiceNames() +{ + const OUString sServiceName = + SwXServiceProvider::GetProviderName(m_pImpl->m_nServiceId); + + // case-corrected version of service-name (see #i67811) + // (need to supply both because of compatibility to older versions) + const OUString sServiceNameCC( OldNameToNewName_Impl( sServiceName ) ); + sal_Int32 nLen = sServiceName == sServiceNameCC ? 2 : 3; + + uno::Sequence< OUString > aRet( nLen ); + OUString* pArray = aRet.getArray(); + *pArray++ = sServiceName; + if (nLen == 3) + *pArray++ = sServiceNameCC; + *pArray++ = "com.sun.star.text.TextContent"; + return aRet; +} + +void SwXTextField::Impl::Invalidate() +{ + EndListeningAll(); + m_pFormatField = nullptr; + m_pDoc = nullptr; + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +void SwXTextField::Impl::Notify(const SfxHint& rHint) +{ + + if(rHint.GetId() == SfxHintId::Dying) + Invalidate(); + else if (rHint.GetId() == SfxHintId::SwLegacyModify) + { + auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint); + switch(pLegacyHint->m_pOld ? pLegacyHint->m_pOld->Which() : 0) + { + case RES_REMOVE_UNO_OBJECT: + case RES_OBJECTDYING: + Invalidate(); + break; + } + } +} + +const SwField* SwXTextField::Impl::GetField() const +{ + return m_pFormatField ? m_pFormatField->GetField() : nullptr; +} + +OUString SwXTextFieldMasters::getImplementationName() +{ + return "SwXTextFieldMasters"; +} + +sal_Bool SwXTextFieldMasters::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextFieldMasters::getSupportedServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextFieldMasters" }; + return aRet; +} + +SwXTextFieldMasters::SwXTextFieldMasters(SwDoc* _pDoc) : + SwUnoCollection(_pDoc) +{ +} + +SwXTextFieldMasters::~SwXTextFieldMasters() +{ + +} + +/* + Iteration over non-standard field types + USER/SETEXP/DDE/DATABASE + Thus the names are: + "com.sun.star.text.fieldmaster.User" + <field type name> + "com.sun.star.text.fieldmaster.DDE" + <field type name> + "com.sun.star.text.fieldmaster.SetExpression" + <field type name> + "com.sun.star.text.fieldmaster.DataBase" + <field type name> + + If too much, maybe one could leave out the "com.sun.star.text". + */ +static SwFieldIds lcl_GetIdByName( OUString& rName, OUString& rTypeName ) +{ + if (rName.startsWithIgnoreAsciiCase(COM_TEXT_FLDMASTER_CC)) + rName = rName.copy(COM_TEXT_FLDMASTER_CC.getLength()); + + SwFieldIds nResId = SwFieldIds::Unknown; + sal_Int32 nIdx = 0; + rTypeName = rName.getToken( 0, '.', nIdx ); + if (rTypeName == "User") + nResId = SwFieldIds::User; + else if (rTypeName == "DDE") + nResId = SwFieldIds::Dde; + else if (rTypeName == "SetExpression") + { + nResId = SwFieldIds::SetExp; + + const OUString sFieldTypName( rName.getToken( 0, '.', nIdx )); + const OUString sUIName( SwStyleNameMapper::GetSpecialExtraUIName( sFieldTypName ) ); + + if( sUIName != sFieldTypName ) + rName = comphelper::string::setToken(rName, 1, '.', sUIName); + } + else if (rTypeName.equalsIgnoreAsciiCase("DataBase")) + { + rName = rName.copy(RTL_CONSTASCII_LENGTH("DataBase.")); + if (!rName.isEmpty()) + { + // #i51815# + rName = "DataBase." + rName; + nResId = SwFieldIds::Database; + } + } + else if (rTypeName == "Bibliography") + nResId = SwFieldIds::TableOfAuthorities; + return nResId; +} + +uno::Any SwXTextFieldMasters::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + OUString sName(rName), sTypeName; + const SwFieldIds nResId = lcl_GetIdByName( sName, sTypeName ); + if( SwFieldIds::Unknown == nResId ) + throw container::NoSuchElementException( + "SwXTextFieldMasters::getByName(" + rName + ")", + css::uno::Reference<css::uno::XInterface>()); + + sName = sName.copy(std::min(sTypeName.getLength()+1, sName.getLength())); + auto& rDoc = GetDoc(); + SwFieldType* pType = rDoc.getIDocumentFieldsAccess().GetFieldType(nResId, sName, true); + if(!pType) + throw container::NoSuchElementException( + "SwXTextFieldMasters::getByName(" + rName + ")", + css::uno::Reference<css::uno::XInterface>()); + + uno::Reference<beans::XPropertySet> const xRet( + SwXFieldMaster::CreateXFieldMaster(&rDoc, pType)); + return uno::Any(xRet); +} + +bool SwXTextFieldMasters::getInstanceName( + const SwFieldType& rFieldType, OUString& rName) +{ + OUString sField; + + switch( rFieldType.Which() ) + { + case SwFieldIds::User: + sField = "User." + rFieldType.GetName(); + break; + case SwFieldIds::Dde: + sField = "DDE." + rFieldType.GetName(); + break; + + case SwFieldIds::SetExp: + sField = "SetExpression." + SwStyleNameMapper::GetSpecialExtraProgName( rFieldType.GetName() ); + break; + + case SwFieldIds::Database: + sField = "DataBase." + rFieldType.GetName().replaceAll(OUStringChar(DB_DELIM), "."); + break; + + case SwFieldIds::TableOfAuthorities: + sField = "Bibliography"; + break; + + default: + return false; + } + + rName += COM_TEXT_FLDMASTER_CC + sField; + return true; +} + +uno::Sequence< OUString > SwXTextFieldMasters::getElementNames() +{ + SolarMutexGuard aGuard; + + const SwFieldTypes* pFieldTypes = GetDoc().getIDocumentFieldsAccess().GetFieldTypes(); + const size_t nCount = pFieldTypes->size(); + + std::vector<OUString> aFieldNames; + for( size_t i = 0; i < nCount; ++i ) + { + SwFieldType& rFieldType = *((*pFieldTypes)[i]); + + OUString sFieldName; + if (SwXTextFieldMasters::getInstanceName(rFieldType, sFieldName)) + { + aFieldNames.push_back(sFieldName); + } + } + + return comphelper::containerToSequence(aFieldNames); +} + +sal_Bool SwXTextFieldMasters::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + OUString sName(rName), sTypeName; + const SwFieldIds nResId = lcl_GetIdByName( sName, sTypeName ); + bool bRet = false; + if( SwFieldIds::Unknown != nResId ) + { + sName = sName.copy(std::min(sTypeName.getLength()+1, sName.getLength())); + bRet = nullptr != GetDoc().getIDocumentFieldsAccess().GetFieldType(nResId, sName, true); + } + return bRet; +} + +uno::Type SwXTextFieldMasters::getElementType() +{ + return cppu::UnoType<beans::XPropertySet>::get(); + +} + +sal_Bool SwXTextFieldMasters::hasElements() +{ + SolarMutexGuard aGuard; + if(!IsValid()) + throw uno::RuntimeException(); + return true; +} + +class SwXTextFieldTypes::Impl +{ +public: + std::mutex m_Mutex; // just for OInterfaceContainerHelper3 + ::comphelper::OInterfaceContainerHelper4<util::XRefreshListener> m_RefreshListeners; +}; + +OUString SwXTextFieldTypes::getImplementationName() +{ + return "SwXTextFieldTypes"; +} + +sal_Bool SwXTextFieldTypes::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextFieldTypes::getSupportedServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextFields" }; + return aRet; +} + +SwXTextFieldTypes::SwXTextFieldTypes(SwDoc* _pDoc) + : SwUnoCollection (_pDoc) + , m_pImpl(new Impl) +{ +} + +SwXTextFieldTypes::~SwXTextFieldTypes() +{ +} + +void SwXTextFieldTypes::Invalidate() +{ + SwUnoCollection::Invalidate(); + lang::EventObject const ev(getXWeak()); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.disposeAndClear(aGuard, ev); +} + +uno::Reference< container::XEnumeration > SwXTextFieldTypes::createEnumeration() +{ + SolarMutexGuard aGuard; + return new SwXFieldEnumeration(GetDoc()); +} + +uno::Type SwXTextFieldTypes::getElementType() +{ + return cppu::UnoType<text::XDependentTextField>::get(); +} + +sal_Bool SwXTextFieldTypes::hasElements() +{ + SolarMutexGuard aGuard; + if(!IsValid()) + throw uno::RuntimeException(); + return true; // they always exist +} + +void SAL_CALL SwXTextFieldTypes::refresh() +{ + { + SolarMutexGuard aGuard; + auto& rDoc = GetDoc(); + UnoActionContext aContext(&rDoc); + rDoc.getIDocumentStatistics().UpdateDocStat(false, true); + rDoc.getIDocumentFieldsAccess().UpdateFields(false); + } + // call refresh listeners (without SolarMutex locked) + lang::EventObject const event(getXWeak()); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.notifyEach(aGuard, + & util::XRefreshListener::refreshed, event); +} + +void SAL_CALL SwXTextFieldTypes::addRefreshListener( + const uno::Reference<util::XRefreshListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXTextFieldTypes::removeRefreshListener( + const uno::Reference<util::XRefreshListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.removeInterface(aGuard, xListener); +} + +class SwXFieldEnumeration::Impl + : public SvtListener +{ +public: + SwDoc* m_pDoc; + std::vector<uno::Reference<text::XTextField>> m_Items; + sal_Int32 m_nNextIndex; ///< index of next element to be returned + + explicit Impl(SwDoc& rDoc) + : m_pDoc(&rDoc) + , m_nNextIndex(0) + { + StartListening(rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); + } + + virtual void Notify(const SfxHint& rHint) override + { + if(rHint.GetId() == SfxHintId::Dying) + m_pDoc = nullptr; + } +}; + +OUString SAL_CALL +SwXFieldEnumeration::getImplementationName() +{ + return "SwXFieldEnumeration"; +} + +sal_Bool SAL_CALL SwXFieldEnumeration::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL +SwXFieldEnumeration::getSupportedServiceNames() +{ + return { "com.sun.star.text.FieldEnumeration" }; +} + +SwXFieldEnumeration::SwXFieldEnumeration(SwDoc & rDoc) + : m_pImpl(new Impl(rDoc)) +{ + // build sequence + m_pImpl->m_Items.clear(); + + const SwFieldTypes* pFieldTypes = m_pImpl->m_pDoc->getIDocumentFieldsAccess().GetFieldTypes(); + const size_t nCount = pFieldTypes->size(); + for(size_t nType = 0; nType < nCount; ++nType) + { + const SwFieldType* pCurType = (*pFieldTypes)[nType].get(); + std::vector<SwFormatField*> vFormatFields; + pCurType->GatherFields(vFormatFields); + std::for_each(vFormatFields.begin(), vFormatFields.end(), + [this](SwFormatField* pF) { m_pImpl->m_Items.push_back(SwXTextField::CreateXTextField(m_pImpl->m_pDoc, pF)); }); + } + // now handle meta-fields, which are not SwFields + const std::vector< uno::Reference<text::XTextField> > MetaFields( + m_pImpl->m_pDoc->GetMetaFieldManager().getMetaFields() ); + for (const auto & rMetaField : MetaFields) + { + m_pImpl->m_Items.push_back( rMetaField ); + } + // also add fieldmarks + IDocumentMarkAccess& rMarksAccess(*rDoc.getIDocumentMarkAccess()); + for (auto iter = rMarksAccess.getFieldmarksBegin(); iter != rMarksAccess.getFieldmarksEnd(); ++iter) + { + m_pImpl->m_Items.emplace_back(cppu::getXWeak(SwXFieldmark::CreateXFieldmark(rDoc, *iter).get()), uno::UNO_QUERY); + } +} + +SwXFieldEnumeration::~SwXFieldEnumeration() +{ +} + +sal_Bool SAL_CALL SwXFieldEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + + return m_pImpl->m_nNextIndex < static_cast<sal_Int32>(m_pImpl->m_Items.size()); +} + +uno::Any SAL_CALL SwXFieldEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + + if (m_pImpl->m_nNextIndex >= static_cast<sal_Int32>(m_pImpl->m_Items.size())) + throw container::NoSuchElementException( + "SwXFieldEnumeration::nextElement", + css::uno::Reference<css::uno::XInterface>()); + + uno::Reference< text::XTextField > &rxField = + m_pImpl->m_Items[ m_pImpl->m_nNextIndex++ ]; + uno::Any aRet; + aRet <<= rxField; + rxField = nullptr; // free memory for item that is no longer used + return aRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoflatpara.cxx b/sw/source/core/unocore/unoflatpara.cxx new file mode 100644 index 0000000000..0f158e49fc --- /dev/null +++ b/sw/source/core/unocore/unoflatpara.cxx @@ -0,0 +1,581 @@ +/* -*- 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 <unobaseclass.hxx> +#include <unocrsrhelper.hxx> +#include <unoflatpara.hxx> + +#include <o3tl/safeint.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <com/sun/star/text/TextMarkupType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <unotextmarkup.hxx> +#include <ndtxt.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> +#include <breakit.hxx> +#include <pam.hxx> +#include <unotextrange.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <txtfrm.hxx> +#include <rootfrm.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <GrammarContact.hxx> +#include <viewopt.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +using namespace ::com::sun::star; + +namespace SwUnoCursorHelper { + +uno::Reference<text::XFlatParagraphIterator> +CreateFlatParagraphIterator(SwDoc & rDoc, sal_Int32 const nTextMarkupType, + bool const bAutomatic) +{ + return new SwXFlatParagraphIterator(rDoc, nTextMarkupType, bAutomatic); +} + +} + +SwXFlatParagraph::SwXFlatParagraph( SwTextNode& rTextNode, OUString aExpandText, const ModelToViewHelper& rMap ) + : SwXFlatParagraph_Base(& rTextNode, rMap) + , maExpandText(std::move(aExpandText)) + , maOrigText(rTextNode.GetText()) +{ +} + +SwXFlatParagraph::~SwXFlatParagraph() +{ +} + + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXFlatParagraph::getPropertySetInfo() +{ + static const comphelper::PropertyMapEntry s_Entries[] = { + { OUString("FieldPositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("FootnotePositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("SortedTextId"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("DocumentElementsCount"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 }, + }; + return new comphelper::PropertySetInfo(s_Entries); +} + +void SAL_CALL +SwXFlatParagraph::setPropertyValue(const OUString&, const uno::Any&) +{ + throw lang::IllegalArgumentException("no values can be set", + getXWeak(), 0); +} + +uno::Any SAL_CALL +SwXFlatParagraph::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + if (rPropertyName == "FieldPositions") + { + return uno::Any( comphelper::containerToSequence( GetConversionMap().getFieldPositions() ) ); + } + else if (rPropertyName == "FootnotePositions") + { + return uno::Any( comphelper::containerToSequence( GetConversionMap().getFootnotePositions() ) ); + } + else if (rPropertyName == "SortedTextId") + { + SwTextNode const*const pCurrentNode = GetTextNode(); + sal_Int32 nIndex = -1; + if ( pCurrentNode ) + nIndex = pCurrentNode->GetIndex().get(); + return uno::Any( nIndex ); + } + else if (rPropertyName == "DocumentElementsCount") + { + SwTextNode const*const pCurrentNode = GetTextNode(); + sal_Int32 nCount = -1; + if ( pCurrentNode ) + nCount = pCurrentNode->GetDoc().GetNodes().Count().get(); + return uno::Any( nCount ); + } + return uno::Any(); +} + +void SAL_CALL +SwXFlatParagraph::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::removeVetoableChangeListener(): not implemented"); +} + + +css::uno::Reference< css::container::XStringKeyMap > SAL_CALL SwXFlatParagraph::getMarkupInfoContainer() +{ + return SwXTextMarkup::getMarkupInfoContainer(); +} + +void SAL_CALL SwXFlatParagraph::commitTextRangeMarkup(::sal_Int32 nType, const OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange, + const css::uno::Reference< css::container::XStringKeyMap > & xMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + SwXTextMarkup::commitTextRangeMarkup( nType, aIdentifier, xRange, xMarkupInfoContainer ); +} + +void SAL_CALL SwXFlatParagraph::commitStringMarkup(::sal_Int32 nType, const OUString & rIdentifier, ::sal_Int32 nStart, ::sal_Int32 nLength, const css::uno::Reference< css::container::XStringKeyMap > & rxMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + SwXTextMarkup::commitStringMarkup( nType, rIdentifier, nStart, nLength, rxMarkupInfoContainer ); +} + +// text::XFlatParagraph: +OUString SAL_CALL SwXFlatParagraph::getText() +{ + return maExpandText; +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal ) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + if ( text::TextMarkupType::SPELLCHECK == nType ) + { + GetTextNode()->SetWrongDirty( + bVal ? sw::WrongState::DONE : sw::WrongState::TODO); + } + else if ( text::TextMarkupType::SMARTTAG == nType ) + GetTextNode()->SetSmartTagDirty( !bVal ); + else if( text::TextMarkupType::PROOFREADING == nType ) + { + GetTextNode()->SetGrammarCheckDirty( !bVal ); + if( bVal ) + sw::finishGrammarCheckFor(*GetTextNode()); + } +} + +// text::XFlatParagraph: +sal_Bool SAL_CALL SwXFlatParagraph::isChecked( ::sal_Int32 nType ) +{ + SolarMutexGuard aGuard; + if (GetTextNode()) + { + if ( text::TextMarkupType::SPELLCHECK == nType ) + return !GetTextNode()->IsWrongDirty(); + else if ( text::TextMarkupType::PROOFREADING == nType ) + return !GetTextNode()->IsGrammarCheckDirty(); + else if ( text::TextMarkupType::SMARTTAG == nType ) + return !GetTextNode()->IsSmartTagDirty(); + } + + return true; +} + +// text::XFlatParagraph: +sal_Bool SAL_CALL SwXFlatParagraph::isModified() +{ + SolarMutexGuard aGuard; + return !GetTextNode() || GetTextNode()->GetText() != maOrigText; +} + +// text::XFlatParagraph: +lang::Locale SAL_CALL SwXFlatParagraph::getLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen) +{ + SolarMutexGuard aGuard; + if (!GetTextNode()) + return LanguageTag::convertToLocale( LANGUAGE_NONE ); + + const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) ); + return aLocale; +} + +// text::XFlatParagraph: +lang::Locale SAL_CALL SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return LanguageTag::convertToLocale( LANGUAGE_NONE ); + + const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) ); + return aLocale; +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::changeText(::sal_Int32 nPos, ::sal_Int32 nLen, const OUString & aNewText, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + SwTextNode *const pOldTextNode = GetTextNode(); + + if (nPos < 0 || pOldTextNode->Len() < nPos || nLen < 0 || o3tl::make_unsigned(pOldTextNode->Len()) < static_cast<sal_uInt32>(nPos) + nLen) + { + throw lang::IllegalArgumentException(); + } + + SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen ); + + UnoActionContext aAction( &GetTextNode()->GetDoc() ); + + const rtl::Reference<SwXTextRange> xRange = + SwXTextRange::CreateXTextRange( + GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() ); + if ( xRange.is() ) + { + for ( const auto& rAttribute : aAttributes ) + xRange->setPropertyValue( rAttribute.Name, rAttribute.Value ); + } + + IDocumentContentOperations& rIDCO = pOldTextNode->getIDocumentContentOperations(); + rIDCO.ReplaceRange( aPaM, aNewText, false ); + + ClearTextNode(); // TODO: is this really needed? +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::changeAttributes(::sal_Int32 nPos, ::sal_Int32 nLen, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + if (nPos < 0 || GetTextNode()->Len() < nPos || nLen < 0 || o3tl::make_unsigned(GetTextNode()->Len()) < static_cast<sal_uInt32>(nPos) + nLen) + { + throw lang::IllegalArgumentException(); + } + + SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen ); + + UnoActionContext aAction( &GetTextNode()->GetDoc() ); + + const rtl::Reference<SwXTextRange> xRange = + SwXTextRange::CreateXTextRange( + GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() ); + if ( xRange.is() ) + { + for ( const auto& rAttribute : aAttributes ) + xRange->setPropertyValue( rAttribute.Name, rAttribute.Value ); + } + + ClearTextNode(); // TODO: is this really needed? +} + +// text::XFlatParagraph: +css::uno::Sequence< ::sal_Int32 > SAL_CALL SwXFlatParagraph::getLanguagePortions() +{ + return css::uno::Sequence< ::sal_Int32>(); +} + +SwXFlatParagraphIterator::SwXFlatParagraphIterator( SwDoc& rDoc, sal_Int32 nType, bool bAutomatic ) + : mpDoc( &rDoc ), + mnType( nType ), + mbAutomatic( bAutomatic ), + mnCurrentNode( 0 ), + mnEndNode( rDoc.GetNodes().Count() ) +{ + //mnStartNode = mnCurrentNode = get node from current cursor TODO! + + // register as listener and get notified when document is closed + StartListening(mpDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD )->GetNotifier()); +} + +SwXFlatParagraphIterator::~SwXFlatParagraphIterator() +{ + SolarMutexGuard aGuard; + EndListeningAll(); +} + +void SwXFlatParagraphIterator::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + SolarMutexGuard aGuard; + mpDoc = nullptr; + } +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getFirstPara() +{ + return getNextPara(); // TODO +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getNextPara() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwTextNode* pRet = nullptr; + if ( mbAutomatic ) + { + SwViewShell* pViewShell = mpDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + + SwPageFrame* pCurrentPage = pViewShell ? pViewShell->Imp()->GetFirstVisPage(pViewShell->GetOut()) : nullptr; + SwPageFrame* pStartPage = pCurrentPage; + SwPageFrame* pStopPage = nullptr; + + while ( pCurrentPage && pCurrentPage != pStopPage ) + { + if (mnType != text::TextMarkupType::SPELLCHECK || pCurrentPage->IsInvalidSpelling() ) + { + // this method is supposed to return an empty paragraph in case Online Checking is disabled + if ( ( mnType == text::TextMarkupType::PROOFREADING || mnType == text::TextMarkupType::SPELLCHECK ) + && !pViewShell->GetViewOptions()->IsOnlineSpell() ) + return xRet; + + // search for invalid content: + SwContentFrame* pCnt = pCurrentPage->ContainsContent(); + + while( pCnt && pCurrentPage->IsAnLower( pCnt ) ) + { + if (pCnt->IsTextFrame()) + { + SwTextFrame const*const pText(static_cast<SwTextFrame const*>(pCnt)); + if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara() + ) + { + SwTextNode * pTextNode(nullptr); + for (auto const& e : pMergedPara->extents) + { + if (e.pNode != pTextNode) + { + pTextNode = e.pNode; + if ((mnType == text::TextMarkupType::SPELLCHECK + && pTextNode->IsWrongDirty()) || + (mnType == text::TextMarkupType::PROOFREADING + && pTextNode->IsGrammarCheckDirty())) + { + pRet = pTextNode; + break; + } + } + } + } + else + { + SwTextNode const*const pTextNode(pText->GetTextNodeFirst()); + if ((mnType == text::TextMarkupType::SPELLCHECK + && pTextNode->IsWrongDirty()) || + (mnType == text::TextMarkupType::PROOFREADING + && pTextNode->IsGrammarCheckDirty())) + + { + pRet = const_cast<SwTextNode*>(pTextNode); + } + } + + if (pRet) + { + break; + } + } + + pCnt = pCnt->GetNextContentFrame(); + } + } + + if ( pRet ) + break; + + // if there is no invalid text node on the current page, + // we validate the page + pCurrentPage->ValidateSpelling(); + + // proceed with next page, wrap at end of document if required: + pCurrentPage = static_cast<SwPageFrame*>(pCurrentPage->GetNext()); + + if ( !pCurrentPage && !pStopPage ) + { + pStopPage = pStartPage; + pCurrentPage = static_cast<SwPageFrame*>(pViewShell->GetLayout()->Lower()); + } + } + } + else // non-automatic checking + { + const SwNodes& rNodes = mpDoc->GetNodes(); + const SwNodeOffset nMaxNodes = rNodes.Count(); + + while ( mnCurrentNode < mnEndNode && mnCurrentNode < nMaxNodes ) + { + SwNode* pNd = rNodes[ mnCurrentNode ]; + + ++mnCurrentNode; + + pRet = pNd->GetTextNode(); + if ( pRet ) + break; + + if ( mnCurrentNode == mnEndNode ) + { + mnCurrentNode = SwNodeOffset(0); + mnEndNode = SwNodeOffset(0); + } + } + } + + if ( pRet ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pRet, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pRet, aExpandText, aConversionMap ); + } + + return xRet; +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getLastPara() +{ + return getNextPara(); +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaAfter(const uno::Reference< text::XFlatParagraph > & xPara) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get())); + SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument"); + if ( !pFlatParagraph ) + return xRet; + + SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode(); + + if ( !pCurrentNode ) + return xRet; + + SwTextNode* pNextTextNode = nullptr; + const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes(); + + for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() + 1; nCurrentNode < rNodes.Count(); ++nCurrentNode ) + { + SwNode* pNd = rNodes[ nCurrentNode ]; + pNextTextNode = pNd->GetTextNode(); + if ( pNextTextNode ) + break; + } + + if ( pNextTextNode ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pNextTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pNextTextNode, aExpandText, aConversionMap ); + } + + return xRet; +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaBefore(const uno::Reference< text::XFlatParagraph > & xPara ) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get())); + SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument"); + if ( !pFlatParagraph ) + return xRet; + + SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode(); + + if ( !pCurrentNode ) + return xRet; + + SwTextNode* pPrevTextNode = nullptr; + const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes(); + + for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() - 1; nCurrentNode > SwNodeOffset(0); --nCurrentNode ) + { + SwNode* pNd = rNodes[ nCurrentNode ]; + pPrevTextNode = pNd->GetTextNode(); + if ( pPrevTextNode ) + break; + } + + if ( pPrevTextNode ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pPrevTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pPrevTextNode, aExpandText, aConversionMap ); + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx new file mode 100644 index 0000000000..7880a749b9 --- /dev/null +++ b/sw/source/core/unocore/unoframe.cxx @@ -0,0 +1,3691 @@ +/* -*- 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 <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <o3tl/any.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflgrit.hxx> +#include <svx/sdtaitm.hxx> +#include <svx/xflclit.hxx> +#include <tools/globname.hxx> +#include <tools/UnitConversion.hxx> +#include <editeng/memberids.h> +#include <swtypes.hxx> +#include <cmdid.h> +#include <unomid.h> +#include <memory> +#include <utility> +#include <cntfrm.hxx> +#include <doc.hxx> +#include <drawdoc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <UndoAttribute.hxx> +#include <docsh.hxx> +#include <editsh.hxx> +#include <ndindex.hxx> +#include <pam.hxx> +#include <ndnotxt.hxx> +#include <svx/unomid.hxx> +#include <unocrsr.hxx> +#include <unocrsrhelper.hxx> +#include <docstyle.hxx> +#include <dcontact.hxx> +#include <fmtcnct.hxx> +#include <ndole.hxx> +#include <frmfmt.hxx> +#include <frame.hxx> +#include <textboxhelper.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unoparagraph.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unoevent.hxx> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <tools/poly.hxx> +#include <swundo.hxx> +#include <svx/svdpage.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/protitem.hxx> +#include <fmtornt.hxx> +#include <fmteiro.hxx> +#include <fmturl.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/shaditem.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include <grfatr.hxx> +#include <unoframe.hxx> +#include <fmtanchr.hxx> +#include <fmtclds.hxx> +#include <fmtcntnt.hxx> +#include <frmatr.hxx> +#include <ndtxt.hxx> +#include <ndgrf.hxx> +#include <mutex> +#include <vcl/svapp.hxx> +#include <vcl/GraphicLoader.hxx> +#include <SwStyleNameMapper.hxx> +#include <editeng/xmlcnitm.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <editeng/frmdiritem.hxx> +#include <fmtfollowtextflow.hxx> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> +#include <vcl/errinf.hxx> + +#include <svx/unobrushitemhelper.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xgrscit.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbmpit.hxx> +#include <svx/xflbmsxy.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xsflclit.hxx> +#include <svx/xflbmsli.hxx> +#include <svx/xflbtoxy.hxx> +#include <svx/xflbstit.hxx> +#include <svx/xflboxy.hxx> +#include <svx/xflbckit.hxx> +#include <svx/unoshape.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xfltrit.hxx> +#include <swunohelper.hxx> +#include <fefly.hxx> +#include <formatflysplit.hxx> +#include <formatwraptextatflystart.hxx> + +using namespace ::com::sun::star; + +using ::com::sun::star::frame::XModel; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::style::XStyleFamiliesSupplier; + +class BaseFrameProperties_Impl +{ + SwUnoCursorHelper::SwAnyMapHelper m_aAnyMap; + +public: + virtual ~BaseFrameProperties_Impl(); + + void SetProperty(sal_uInt16 nWID, sal_uInt8 nMemberId, const uno::Any& rVal); + bool GetProperty(sal_uInt16 nWID, sal_uInt8 nMemberId, const uno::Any*& pAny ); + bool FillBaseProperties(SfxItemSet& rToSet, const SfxItemSet &rFromSet, bool& rSizeFound); + + virtual bool AnyToItemSet( SwDoc* pDoc, SfxItemSet& rFrameSet, SfxItemSet& rSet, bool& rSizeFound) = 0; +}; + +BaseFrameProperties_Impl::~BaseFrameProperties_Impl() +{ +} + +void BaseFrameProperties_Impl::SetProperty(sal_uInt16 nWID, sal_uInt8 nMemberId, const uno::Any& rVal) +{ + m_aAnyMap.SetValue( nWID, nMemberId, rVal ); +} + +bool BaseFrameProperties_Impl::GetProperty(sal_uInt16 nWID, sal_uInt8 nMemberId, const uno::Any*& rpAny) +{ + return m_aAnyMap.FillValue( nWID, nMemberId, rpAny ); +} + +bool BaseFrameProperties_Impl::FillBaseProperties(SfxItemSet& rToSet, const SfxItemSet& rFromSet, bool& rSizeFound) +{ + // assert when the target SfxItemSet has no parent. It *should* have the pDfltFrameFormat + // from SwDoc set as parent (or similar) to have the necessary XFILL_NONE in the ItemSet + if(!rToSet.GetParent()) + { + OSL_ENSURE(false, "OOps, target SfxItemSet *should* have a parent which contains XFILL_NONE as XFillStyleItem (!)"); + } + + bool bRet = true; + // always add an anchor to the set + SwFormatAnchor aAnchor ( rFromSet.Get ( RES_ANCHOR ) ); + { + const ::uno::Any* pAnchorType; + if(GetProperty(RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, pAnchorType)) + bRet &= static_cast<SfxPoolItem&>(aAnchor).PutValue(*pAnchorType, MID_ANCHOR_ANCHORTYPE); + const ::uno::Any* pAnchorPgNo; + if(GetProperty(RES_ANCHOR, MID_ANCHOR_PAGENUM, pAnchorPgNo)) + bRet &= static_cast<SfxPoolItem&>(aAnchor).PutValue(*pAnchorPgNo, MID_ANCHOR_PAGENUM); + } + + rToSet.Put(aAnchor); + + // check for SvxBrushItem (RES_BACKGROUND) properties + const ::uno::Any* pCol = nullptr; GetProperty(RES_BACKGROUND, MID_BACK_COLOR, pCol ); + const ::uno::Any* pRGBCol = nullptr; GetProperty(RES_BACKGROUND, MID_BACK_COLOR_R_G_B, pRGBCol ); + const ::uno::Any* pColTrans = nullptr; GetProperty(RES_BACKGROUND, MID_BACK_COLOR_TRANSPARENCY, pColTrans); + const ::uno::Any* pTrans = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC_TRANSPARENT, pTrans ); + const ::uno::Any* pGrLoc = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC_POSITION, pGrLoc ); + const ::uno::Any* pGraphic = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC, pGraphic ); + const ::uno::Any* pGrFilter = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC_FILTER, pGrFilter ); + const ::uno::Any* pGraphicURL = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC_URL, pGraphicURL ); + const ::uno::Any* pGrTransparency = nullptr; GetProperty(RES_BACKGROUND, MID_GRAPHIC_TRANSPARENCY, pGrTransparency ); + const bool bSvxBrushItemPropertiesUsed( + pCol || + pTrans || + pGraphic || + pGraphicURL || + pGrFilter || + pGrLoc || + pGrTransparency || + pColTrans || + pRGBCol); + + // check for FillStyle properties in the range XATTR_FILL_FIRST, XATTR_FILL_LAST + const uno::Any* pXFillStyleItem = nullptr; GetProperty(XATTR_FILLSTYLE, 0, pXFillStyleItem); + const uno::Any* pXFillColorItem = nullptr; GetProperty(XATTR_FILLCOLOR, 0, pXFillColorItem); + + // XFillGradientItem: two possible slots supported in UNO API + const uno::Any* pXFillGradientItem = nullptr; GetProperty(XATTR_FILLGRADIENT, MID_FILLGRADIENT, pXFillGradientItem); + const uno::Any* pXFillGradientNameItem = nullptr; GetProperty(XATTR_FILLGRADIENT, MID_NAME, pXFillGradientNameItem); + + // XFillHatchItem: two possible slots supported in UNO API + const uno::Any* pXFillHatchItem = nullptr; GetProperty(XATTR_FILLHATCH, MID_FILLHATCH, pXFillHatchItem); + const uno::Any* pXFillHatchNameItem = nullptr; GetProperty(XATTR_FILLHATCH, MID_NAME, pXFillHatchNameItem); + + // XFillBitmapItem: three possible slots supported in UNO API + const uno::Any* pXFillBitmapItem = nullptr; GetProperty(XATTR_FILLBITMAP, MID_BITMAP, pXFillBitmapItem); + const uno::Any* pXFillBitmapNameItem = nullptr; GetProperty(XATTR_FILLBITMAP, MID_NAME, pXFillBitmapNameItem); + + const uno::Any* pXFillTransparenceItem = nullptr; GetProperty(XATTR_FILLTRANSPARENCE, 0, pXFillTransparenceItem); + const uno::Any* pXGradientStepCountItem = nullptr; GetProperty(XATTR_GRADIENTSTEPCOUNT, 0, pXGradientStepCountItem); + const uno::Any* pXFillBmpPosItem = nullptr; GetProperty(XATTR_FILLBMP_POS, 0, pXFillBmpPosItem); + const uno::Any* pXFillBmpSizeXItem = nullptr; GetProperty(XATTR_FILLBMP_SIZEX, 0, pXFillBmpSizeXItem); + const uno::Any* pXFillBmpSizeYItem = nullptr; GetProperty(XATTR_FILLBMP_SIZEY, 0, pXFillBmpSizeYItem); + + // XFillFloatTransparenceItem: two possible slots supported in UNO API + const uno::Any* pXFillFloatTransparenceItem = nullptr; GetProperty(XATTR_FILLFLOATTRANSPARENCE, MID_FILLGRADIENT, pXFillFloatTransparenceItem); + const uno::Any* pXFillFloatTransparenceNameItem = nullptr; GetProperty(XATTR_FILLFLOATTRANSPARENCE, MID_NAME, pXFillFloatTransparenceNameItem); + + const uno::Any* pXSecondaryFillColorItem = nullptr; GetProperty(XATTR_SECONDARYFILLCOLOR, 0, pXSecondaryFillColorItem); + const uno::Any* pXFillBmpSizeLogItem = nullptr; GetProperty(XATTR_FILLBMP_SIZELOG, 0, pXFillBmpSizeLogItem); + const uno::Any* pXFillBmpTileOffsetXItem = nullptr; GetProperty(XATTR_FILLBMP_TILEOFFSETX, 0, pXFillBmpTileOffsetXItem); + const uno::Any* pXFillBmpTileOffsetYItem = nullptr; GetProperty(XATTR_FILLBMP_TILEOFFSETY, 0, pXFillBmpTileOffsetYItem); + const uno::Any* pXFillBmpPosOffsetXItem = nullptr; GetProperty(XATTR_FILLBMP_POSOFFSETX, 0, pXFillBmpPosOffsetXItem); + const uno::Any* pXFillBmpPosOffsetYItem = nullptr; GetProperty(XATTR_FILLBMP_POSOFFSETY, 0, pXFillBmpPosOffsetYItem); + const uno::Any* pXFillBackgroundItem = nullptr; GetProperty(XATTR_FILLBACKGROUND, 0, pXFillBackgroundItem); + const uno::Any* pOwnAttrFillBmpItem = nullptr; GetProperty(OWN_ATTR_FILLBMP_MODE, 0, pOwnAttrFillBmpItem); + + // tdf#91140: ignore SOLID fill style for determining if fill style is used + // but there is a Graphic + const bool bFillStyleUsed(pXFillStyleItem && pXFillStyleItem->hasValue() && + (pXFillStyleItem->get<drawing::FillStyle>() != drawing::FillStyle_SOLID || (!pGraphic || !pGraphicURL) )); + SAL_INFO_IF(pXFillStyleItem && pXFillStyleItem->hasValue() && !bFillStyleUsed, + "sw.uno", "FillBaseProperties: ignoring invalid FillStyle"); + const bool bXFillStyleItemUsed( + bFillStyleUsed || + pXFillColorItem || + pXFillGradientItem || pXFillGradientNameItem || + pXFillHatchItem || pXFillHatchNameItem || + pXFillBitmapItem || pXFillBitmapNameItem || + pXFillTransparenceItem || + pXGradientStepCountItem || + pXFillBmpPosItem || + pXFillBmpSizeXItem || + pXFillBmpSizeYItem || + pXFillFloatTransparenceItem || pXFillFloatTransparenceNameItem || + pXSecondaryFillColorItem || + pXFillBmpSizeLogItem || + pXFillBmpTileOffsetXItem || + pXFillBmpTileOffsetYItem || + pXFillBmpPosOffsetXItem || + pXFillBmpPosOffsetYItem || + pXFillBackgroundItem || + pOwnAttrFillBmpItem); + + // use brush items, but *only* if no FillStyle properties are used; if both are used and when applying both + // in the obvious order some attributes may be wrong since they are set by the 1st set, but not + // redefined as needed by the 2nd set when they are default (and thus no tset) in the 2nd set. If + // it is necessary for any reason to set both (it should not) an in-between step will be needed + // that resets the items for FillAttributes in rToSet to default. + // Note: There are other mechanisms in XMLOFF to pre-sort this relationship already, but this version + // was used initially, is tested and works. Keep it to be able to react when another feed adds attributes + // from both sets. + if(bSvxBrushItemPropertiesUsed && !bXFillStyleItemUsed) + { + // create a temporary SvxBrushItem, fill the attributes to it and use it to set + // the corresponding FillAttributes + SvxBrushItem aBrush(RES_BACKGROUND); + + if(pCol) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pCol,MID_BACK_COLOR ); + } + + if(pColTrans) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pColTrans, MID_BACK_COLOR_TRANSPARENCY); + } + + if(pRGBCol) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pRGBCol, MID_BACK_COLOR_R_G_B); + } + + if(pTrans) + { + // don't overwrite transparency with a non-transparence flag + if(!pColTrans || Any2Bool( *pTrans )) + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pTrans, MID_GRAPHIC_TRANSPARENT); + } + + if (pGraphic) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pGraphic, MID_GRAPHIC); + } + + if (pGraphicURL) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pGraphicURL, MID_GRAPHIC_URL); + } + + if(pGrFilter) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pGrFilter, MID_GRAPHIC_FILTER); + } + + if(pGrLoc) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pGrLoc, MID_GRAPHIC_POSITION); + } + + if(pGrTransparency) + { + bRet &= static_cast<SfxPoolItem&>(aBrush).PutValue(*pGrTransparency, MID_GRAPHIC_TRANSPARENCY); + } + + setSvxBrushItemAsFillAttributesToTargetSet(aBrush, rToSet); + } + + if(bXFillStyleItemUsed) + { + XFillStyleItem aXFillStyleItem; + std::unique_ptr<SvxBrushItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + + if(pXFillStyleItem) + { + aXFillStyleItem.PutValue(*pXFillStyleItem, 0); + rToSet.Put(aXFillStyleItem); + } + + if(pXFillColorItem) + { + const Color aNullCol(COL_DEFAULT_SHAPE_FILLING); + XFillColorItem aXFillColorItem(OUString(), aNullCol); + + aXFillColorItem.PutValue(*pXFillColorItem, 0); + rToSet.Put(aXFillColorItem); + //set old-school brush color if we later encounter the + //MID_BACK_COLOR_TRANSPARENCY case below + aBrush = getSvxBrushItemFromSourceSet(rToSet, RES_BACKGROUND, false); + } + else if (aXFillStyleItem.GetValue() == drawing::FillStyle_SOLID && (pCol || pRGBCol)) + { + // Fill style is set to solid, but no fill color is given. + // On the other hand, we have a BackColor, so use that. + if (pCol) + aBrush->PutValue(*pCol, MID_BACK_COLOR); + else + aBrush->PutValue(*pRGBCol, MID_BACK_COLOR_R_G_B); + setSvxBrushItemAsFillAttributesToTargetSet(*aBrush, rToSet); + } + + if(pXFillGradientItem || pXFillGradientNameItem) + { + if(pXFillGradientItem) + { + // basegfx::BGradient() default already creates [COL_BLACK, COL_WHITE] as defaults + const basegfx::BGradient aNullGrad; + XFillGradientItem aXFillGradientItem(aNullGrad); + + aXFillGradientItem.PutValue(*pXFillGradientItem, MID_FILLGRADIENT); + rToSet.Put(aXFillGradientItem); + } + + if(pXFillGradientNameItem) + { + OUString aTempName; + + if(!(*pXFillGradientNameItem >>= aTempName )) + { + throw lang::IllegalArgumentException(); + } + + bool const bSuccess = SvxShape::SetFillAttribute( + XATTR_FILLGRADIENT, aTempName, rToSet); + if (aXFillStyleItem.GetValue() == drawing::FillStyle_GRADIENT) + { // tdf#90946 ignore invalid gradient-name if SOLID + bRet &= bSuccess; + } + else + { + SAL_INFO_IF(!bSuccess, "sw.uno", + "FillBaseProperties: ignoring invalid FillGradientName"); + } + } + } + + if(pXFillHatchItem || pXFillHatchNameItem) + { + if(pXFillHatchItem) + { + const Color aNullCol(COL_DEFAULT_SHAPE_STROKE); + const XHatch aNullHatch(aNullCol); + XFillHatchItem aXFillHatchItem(aNullHatch); + + aXFillHatchItem.PutValue(*pXFillHatchItem, MID_FILLHATCH); + rToSet.Put(aXFillHatchItem); + } + + if(pXFillHatchNameItem) + { + OUString aTempName; + + if(!(*pXFillHatchNameItem >>= aTempName )) + { + throw lang::IllegalArgumentException(); + } + + bRet &= SvxShape::SetFillAttribute(XATTR_FILLHATCH, aTempName, rToSet); + } + } + + if (pXFillBitmapItem || pXFillBitmapNameItem) + { + if(pXFillBitmapItem) + { + Graphic aNullGraphic; + XFillBitmapItem aXFillBitmapItem(std::move(aNullGraphic)); + + aXFillBitmapItem.PutValue(*pXFillBitmapItem, MID_BITMAP); + rToSet.Put(aXFillBitmapItem); + } + + if(pXFillBitmapNameItem) + { + OUString aTempName; + + if(!(*pXFillBitmapNameItem >>= aTempName )) + { + throw lang::IllegalArgumentException(); + } + + bRet &= SvxShape::SetFillAttribute(XATTR_FILLBITMAP, aTempName, rToSet); + } + } + + if (pXFillTransparenceItem) + { + XFillTransparenceItem aXFillTransparenceItem; + aXFillTransparenceItem.PutValue(*pXFillTransparenceItem, 0); + rToSet.Put(aXFillTransparenceItem); + } + else if (pColTrans && + !pXFillFloatTransparenceItem && !pXFillFloatTransparenceNameItem) + { + // No fill transparency is given. On the other hand, we have a + // BackColorTransparency, so use that. + // tdf#90640 tdf#90130: this is necessary for LO 4.4.0 - 4.4.2 + // that forgot to write draw:opacity into documents + // but: the value was *always* wrong for bitmaps! => ignore it + sal_Int8 nGraphicTransparency(0); + *pColTrans >>= nGraphicTransparency; + if (aXFillStyleItem.GetValue() != drawing::FillStyle_BITMAP) + { + rToSet.Put(XFillTransparenceItem(nGraphicTransparency)); + } + if (aXFillStyleItem.GetValue() == drawing::FillStyle_SOLID) + { + aBrush->PutValue(*pColTrans, MID_BACK_COLOR_TRANSPARENCY); + setSvxBrushItemAsFillAttributesToTargetSet(*aBrush, rToSet); + } + } + + if(pXGradientStepCountItem) + { + XGradientStepCountItem aXGradientStepCountItem; + + aXGradientStepCountItem.PutValue(*pXGradientStepCountItem, 0); + rToSet.Put(aXGradientStepCountItem); + } + + if(pXFillBmpPosItem) + { + XFillBmpPosItem aXFillBmpPosItem; + + aXFillBmpPosItem.PutValue(*pXFillBmpPosItem, 0); + rToSet.Put(aXFillBmpPosItem); + } + + if(pXFillBmpSizeXItem) + { + XFillBmpSizeXItem aXFillBmpSizeXItem; + + aXFillBmpSizeXItem.PutValue(*pXFillBmpSizeXItem, 0); + rToSet.Put(aXFillBmpSizeXItem); + } + + if(pXFillBmpSizeYItem) + { + XFillBmpSizeYItem aXFillBmpSizeYItem; + + aXFillBmpSizeYItem.PutValue(*pXFillBmpSizeYItem, 0); + rToSet.Put(aXFillBmpSizeYItem); + } + + if(pXFillFloatTransparenceItem || pXFillFloatTransparenceNameItem) + { + if(pXFillFloatTransparenceItem) + { + // basegfx::BGradient() default already creates [COL_BLACK, COL_WHITE] as defaults + const basegfx::BGradient aNullGrad; + XFillFloatTransparenceItem aXFillFloatTransparenceItem(aNullGrad, false); + + aXFillFloatTransparenceItem.PutValue(*pXFillFloatTransparenceItem, MID_FILLGRADIENT); + rToSet.Put(aXFillFloatTransparenceItem); + } + + if(pXFillFloatTransparenceNameItem) + { + OUString aTempName; + + if(!(*pXFillFloatTransparenceNameItem >>= aTempName )) + { + throw lang::IllegalArgumentException(); + } + + bRet &= SvxShape::SetFillAttribute(XATTR_FILLFLOATTRANSPARENCE, aTempName, rToSet); + } + } + + if(pXSecondaryFillColorItem) + { + const Color aNullCol(COL_DEFAULT_SHAPE_FILLING); + XSecondaryFillColorItem aXSecondaryFillColorItem(OUString(), aNullCol); + + aXSecondaryFillColorItem.PutValue(*pXSecondaryFillColorItem, 0); + rToSet.Put(aXSecondaryFillColorItem); + } + + if(pXFillBmpSizeLogItem) + { + XFillBmpSizeLogItem aXFillBmpSizeLogItem; + + aXFillBmpSizeLogItem.PutValue(*pXFillBmpSizeLogItem, 0); + rToSet.Put(aXFillBmpSizeLogItem); + } + + if(pXFillBmpTileOffsetXItem) + { + XFillBmpTileOffsetXItem aXFillBmpTileOffsetXItem; + + aXFillBmpTileOffsetXItem.PutValue(*pXFillBmpTileOffsetXItem, 0); + rToSet.Put(aXFillBmpTileOffsetXItem); + } + + if(pXFillBmpTileOffsetYItem) + { + XFillBmpTileOffsetYItem aXFillBmpTileOffsetYItem; + + aXFillBmpTileOffsetYItem.PutValue(*pXFillBmpTileOffsetYItem, 0); + rToSet.Put(aXFillBmpTileOffsetYItem); + } + + if(pXFillBmpPosOffsetXItem) + { + XFillBmpPosOffsetXItem aXFillBmpPosOffsetXItem; + + aXFillBmpPosOffsetXItem.PutValue(*pXFillBmpPosOffsetXItem, 0); + rToSet.Put(aXFillBmpPosOffsetXItem); + } + + if(pXFillBmpPosOffsetYItem) + { + XFillBmpPosOffsetYItem aXFillBmpPosOffsetYItem; + + aXFillBmpPosOffsetYItem.PutValue(*pXFillBmpPosOffsetYItem, 0); + rToSet.Put(aXFillBmpPosOffsetYItem); + } + + if(pXFillBackgroundItem) + { + XFillBackgroundItem aXFillBackgroundItem; + + aXFillBackgroundItem.PutValue(*pXFillBackgroundItem, 0); + rToSet.Put(aXFillBackgroundItem); + } + + if(pOwnAttrFillBmpItem) + { + drawing::BitmapMode eMode; + + if(!(*pOwnAttrFillBmpItem >>= eMode)) + { + sal_Int32 nMode = 0; + + if(!(*pOwnAttrFillBmpItem >>= nMode)) + { + throw lang::IllegalArgumentException(); + } + + eMode = static_cast<drawing::BitmapMode>(nMode); + } + + rToSet.Put(XFillBmpStretchItem(drawing::BitmapMode_STRETCH == eMode)); + rToSet.Put(XFillBmpTileItem(drawing::BitmapMode_REPEAT == eMode)); + } + } + { + const ::uno::Any* pCont = nullptr; + GetProperty(RES_PROTECT, MID_PROTECT_CONTENT, pCont ); + const ::uno::Any* pPos = nullptr; + GetProperty(RES_PROTECT,MID_PROTECT_POSITION, pPos ); + const ::uno::Any* pName = nullptr; + GetProperty(RES_PROTECT, MID_PROTECT_SIZE, pName ); + if(pCont||pPos||pName) + { + SvxProtectItem aProt ( rFromSet.Get ( RES_PROTECT ) ); + if(pCont) + bRet &= static_cast<SfxPoolItem&>(aProt).PutValue(*pCont, MID_PROTECT_CONTENT); + if(pPos ) + bRet &= static_cast<SfxPoolItem&>(aProt).PutValue(*pPos, MID_PROTECT_POSITION); + if(pName) + bRet &= static_cast<SfxPoolItem&>(aProt).PutValue(*pName, MID_PROTECT_SIZE); + rToSet.Put(aProt); + } + } + { + const ::uno::Any* pHori = nullptr; + GetProperty(RES_HORI_ORIENT, MID_HORIORIENT_ORIENT, pHori ); + const ::uno::Any* pHoriP = nullptr; + GetProperty(RES_HORI_ORIENT, MID_HORIORIENT_POSITION|CONVERT_TWIPS, pHoriP ); + const ::uno::Any* pHoriR = nullptr; + GetProperty(RES_HORI_ORIENT, MID_HORIORIENT_RELATION, pHoriR ); + const ::uno::Any* pPageT = nullptr; + GetProperty(RES_HORI_ORIENT, MID_HORIORIENT_PAGETOGGLE, pPageT); + if(pHori||pHoriP||pHoriR||pPageT) + { + SwFormatHoriOrient aOrient ( rFromSet.Get ( RES_HORI_ORIENT ) ); + if(pHori ) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pHori, MID_HORIORIENT_ORIENT); + if(pHoriP) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pHoriP, MID_HORIORIENT_POSITION|CONVERT_TWIPS); + if(pHoriR) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pHoriR, MID_HORIORIENT_RELATION); + if(pPageT) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pPageT, MID_HORIORIENT_PAGETOGGLE); + rToSet.Put(aOrient); + } + } + + { + const ::uno::Any* pVert = nullptr; + GetProperty(RES_VERT_ORIENT, MID_VERTORIENT_ORIENT, pVert); + const ::uno::Any* pVertP = nullptr; + GetProperty(RES_VERT_ORIENT, MID_VERTORIENT_POSITION|CONVERT_TWIPS, pVertP ); + const ::uno::Any* pVertR = nullptr; + GetProperty(RES_VERT_ORIENT, MID_VERTORIENT_RELATION, pVertR ); + if(pVert||pVertP||pVertR) + { + SwFormatVertOrient aOrient ( rFromSet.Get ( RES_VERT_ORIENT ) ); + if(pVert ) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pVert, MID_VERTORIENT_ORIENT); + if(pVertP) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pVertP, MID_VERTORIENT_POSITION|CONVERT_TWIPS); + if(pVertR) + bRet &= static_cast<SfxPoolItem&>(aOrient).PutValue(*pVertR, MID_VERTORIENT_RELATION); + rToSet.Put(aOrient); + } + } + { + const ::uno::Any* pURL = nullptr; + GetProperty(RES_URL, MID_URL_URL, pURL ); + const ::uno::Any* pTarget = nullptr; + GetProperty(RES_URL, MID_URL_TARGET, pTarget ); + const ::uno::Any* pHyLNm = nullptr; + GetProperty(RES_URL, MID_URL_HYPERLINKNAME, pHyLNm ); + const ::uno::Any* pHySMp = nullptr; + GetProperty(RES_URL, MID_URL_SERVERMAP, pHySMp ); + if(pURL||pTarget||pHyLNm||pHySMp) + { + SwFormatURL aURL ( rFromSet.Get ( RES_URL ) ); + if(pURL) + bRet &= static_cast<SfxPoolItem&>(aURL).PutValue(*pURL, MID_URL_URL); + if(pTarget) + bRet &= static_cast<SfxPoolItem&>(aURL).PutValue(*pTarget, MID_URL_TARGET); + if(pHyLNm) + bRet &= static_cast<SfxPoolItem&>(aURL).PutValue(*pHyLNm, MID_URL_HYPERLINKNAME ); + if(pHySMp) + bRet &= static_cast<SfxPoolItem&>(aURL).PutValue(*pHySMp, MID_URL_SERVERMAP); + rToSet.Put(aURL); + } + } + const ::uno::Any* pL = nullptr; + GetProperty(RES_LR_SPACE, MID_L_MARGIN|CONVERT_TWIPS, pL ); + const ::uno::Any* pR = nullptr; + GetProperty(RES_LR_SPACE, MID_R_MARGIN|CONVERT_TWIPS, pR ); + if(pL||pR) + { + SvxLRSpaceItem aLR ( rFromSet.Get ( RES_LR_SPACE ) ); + if(pL) + bRet &= static_cast<SfxPoolItem&>(aLR).PutValue(*pL, MID_L_MARGIN|CONVERT_TWIPS); + if(pR) + bRet &= static_cast<SfxPoolItem&>(aLR).PutValue(*pR, MID_R_MARGIN|CONVERT_TWIPS); + rToSet.Put(aLR); + } + const ::uno::Any* pT = nullptr; + GetProperty(RES_UL_SPACE, MID_UP_MARGIN|CONVERT_TWIPS, pT ); + const ::uno::Any* pB = nullptr; + GetProperty(RES_UL_SPACE, MID_LO_MARGIN|CONVERT_TWIPS, pB ); + if(pT||pB) + { + SvxULSpaceItem aTB ( rFromSet.Get ( RES_UL_SPACE ) ); + if(pT) + bRet &= static_cast<SfxPoolItem&>(aTB).PutValue(*pT, MID_UP_MARGIN|CONVERT_TWIPS); + if(pB) + bRet &= static_cast<SfxPoolItem&>(aTB).PutValue(*pB, MID_LO_MARGIN|CONVERT_TWIPS); + rToSet.Put(aTB); + } + const ::uno::Any* pOp; + if(GetProperty(RES_OPAQUE, 0, pOp)) + { + SvxOpaqueItem aOp ( rFromSet.Get ( RES_OPAQUE ) ); + bRet &= static_cast<SfxPoolItem&>(aOp).PutValue(*pOp, 0); + rToSet.Put(aOp); + } + const ::uno::Any* pPrt; + if(GetProperty(RES_PRINT, 0, pPrt)) + { + SvxPrintItem aPrt ( rFromSet.Get ( RES_PRINT ) ); + bRet &= static_cast<SfxPoolItem&>(aPrt).PutValue(*pPrt, 0); + rToSet.Put(aPrt); + } + const ::uno::Any* pSh; + if(GetProperty(RES_SHADOW, CONVERT_TWIPS, pSh)) + { + SvxShadowItem aSh ( rFromSet.Get ( RES_SHADOW ) ); + bRet &= static_cast<SfxPoolItem&>(aSh).PutValue(*pSh, CONVERT_TWIPS); + rToSet.Put(aSh); + } + const ::uno::Any* pShTr; + if(GetProperty(RES_SHADOW, MID_SHADOW_TRANSPARENCE, pShTr) && rToSet.HasItem(RES_SHADOW)) + { + SvxShadowItem aSh(rToSet.Get(RES_SHADOW)); + bRet &= aSh.PutValue(*pShTr, MID_SHADOW_TRANSPARENCE); + rToSet.Put(aSh); + } + const ::uno::Any* pSur = nullptr; + GetProperty(RES_SURROUND, MID_SURROUND_SURROUNDTYPE, pSur); + const ::uno::Any* pSurCont = nullptr; + GetProperty(RES_SURROUND, MID_SURROUND_CONTOUR, pSurCont); + const ::uno::Any* pSurAnch = nullptr; + GetProperty(RES_SURROUND, MID_SURROUND_ANCHORONLY, pSurAnch); + if(pSur || pSurAnch) + { + SwFormatSurround aSrnd ( rFromSet.Get ( RES_SURROUND ) ); + if(pSur) + bRet &= static_cast<SfxPoolItem&>(aSrnd).PutValue(*pSur, MID_SURROUND_SURROUNDTYPE); + if(pSurCont) + bRet &= static_cast<SfxPoolItem&>(aSrnd).PutValue(*pSurCont, MID_SURROUND_CONTOUR); + if(pSurAnch) + bRet &= static_cast<SfxPoolItem&>(aSrnd).PutValue(*pSurAnch, MID_SURROUND_ANCHORONLY); + rToSet.Put(aSrnd); + } + const ::uno::Any* pLeft = nullptr; + GetProperty(RES_BOX, LEFT_BORDER |CONVERT_TWIPS, pLeft ); + const ::uno::Any* pRight = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|RIGHT_BORDER , pRight ); + const ::uno::Any* pTop = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|TOP_BORDER , pTop ); + const ::uno::Any* pBottom = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|BOTTOM_BORDER, pBottom); + const ::uno::Any* pDistance = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|BORDER_DISTANCE, pDistance); + const ::uno::Any* pLeftDistance = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|LEFT_BORDER_DISTANCE, pLeftDistance); + const ::uno::Any* pRightDistance = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|RIGHT_BORDER_DISTANCE, pRightDistance); + const ::uno::Any* pTopDistance = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|TOP_BORDER_DISTANCE, pTopDistance); + const ::uno::Any* pBottomDistance = nullptr; + GetProperty(RES_BOX, CONVERT_TWIPS|BOTTOM_BORDER_DISTANCE, pBottomDistance); + const ::uno::Any* pLineStyle = nullptr; + GetProperty(RES_BOX, LINE_STYLE, pLineStyle); + const ::uno::Any* pLineWidth = nullptr; + GetProperty(RES_BOX, LINE_WIDTH, pLineWidth); + if( pLeft || pRight || pTop || pBottom || pDistance || + pLeftDistance || pRightDistance || pTopDistance || pBottomDistance || + pLineStyle || pLineWidth ) + { + SvxBoxItem aBox ( rFromSet.Get ( RES_BOX ) ); + if( pLeft ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pLeft, CONVERT_TWIPS|LEFT_BORDER ); + if( pRight ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pRight, CONVERT_TWIPS|RIGHT_BORDER ); + if( pTop ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pTop, CONVERT_TWIPS|TOP_BORDER); + if( pBottom ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pBottom, CONVERT_TWIPS|BOTTOM_BORDER); + if( pDistance ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pDistance, CONVERT_TWIPS|BORDER_DISTANCE); + if( pLeftDistance ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pLeftDistance, CONVERT_TWIPS|LEFT_BORDER_DISTANCE); + if( pRightDistance ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pRightDistance, CONVERT_TWIPS|RIGHT_BORDER_DISTANCE); + if( pTopDistance ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pTopDistance, CONVERT_TWIPS|TOP_BORDER_DISTANCE); + if( pBottomDistance ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pBottomDistance, CONVERT_TWIPS|BOTTOM_BORDER_DISTANCE); + if( pLineStyle ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pLineStyle, LINE_STYLE); + if( pLineWidth ) + bRet &= static_cast<SfxPoolItem&>(aBox).PutValue(*pLineWidth, LINE_WIDTH|CONVERT_TWIPS); + rToSet.Put(aBox); + } + { + const ::uno::Any* pRelH = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_REL_HEIGHT, pRelH); + const ::uno::Any* pRelHRelation = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_REL_HEIGHT_RELATION, pRelHRelation); + const ::uno::Any* pRelW = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_REL_WIDTH, pRelW); + const ::uno::Any* pRelWRelation = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_REL_WIDTH_RELATION, pRelWRelation); + const ::uno::Any* pSyncWidth = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT, pSyncWidth); + const ::uno::Any* pSyncHeight = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH, pSyncHeight); + const ::uno::Any* pWidth = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_WIDTH|CONVERT_TWIPS, pWidth); + const ::uno::Any* pHeight = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_HEIGHT|CONVERT_TWIPS, pHeight); + const ::uno::Any* pSize = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_SIZE|CONVERT_TWIPS, pSize); + const ::uno::Any* pSizeType = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_SIZE_TYPE, pSizeType); + const ::uno::Any* pWidthType = nullptr; + GetProperty(RES_FRM_SIZE, MID_FRMSIZE_WIDTH_TYPE, pWidthType); + if( pWidth || pHeight ||pRelH || pRelHRelation || pRelW || pRelWRelation || pSize ||pSizeType || + pWidthType ||pSyncWidth || pSyncHeight ) + { + rSizeFound = true; + SwFormatFrameSize aFrameSz ( rFromSet.Get ( RES_FRM_SIZE ) ); + if(pWidth) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pWidth, MID_FRMSIZE_WIDTH|CONVERT_TWIPS); + if(pHeight) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pHeight, MID_FRMSIZE_HEIGHT|CONVERT_TWIPS); + if(pRelH ) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pRelH, MID_FRMSIZE_REL_HEIGHT); + if (pRelHRelation) + bRet &= aFrameSz.PutValue(*pRelHRelation, MID_FRMSIZE_REL_HEIGHT_RELATION); + if(pRelW ) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pRelW, MID_FRMSIZE_REL_WIDTH); + if (pRelWRelation) + bRet &= aFrameSz.PutValue(*pRelWRelation, MID_FRMSIZE_REL_WIDTH_RELATION); + if(pSyncWidth) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pSyncWidth, MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT); + if(pSyncHeight) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pSyncHeight, MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH); + if(pSize) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pSize, MID_FRMSIZE_SIZE|CONVERT_TWIPS); + if(pSizeType) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pSizeType, MID_FRMSIZE_SIZE_TYPE); + if(pWidthType) + bRet &= static_cast<SfxPoolItem&>(aFrameSz).PutValue(*pWidthType, MID_FRMSIZE_WIDTH_TYPE); + if(!aFrameSz.GetWidth()) + aFrameSz.SetWidth(MINFLY); + if(!aFrameSz.GetHeight()) + aFrameSz.SetHeight(MINFLY); + rToSet.Put(aFrameSz); + } + else + { + rSizeFound = false; + SwFormatFrameSize aFrameSz; + constexpr sal_Int32 constTwips_1cm = o3tl::toTwips(1, o3tl::Length::cm); + awt::Size aSize; + aSize.Width = constTwips_1cm; + aSize.Height = constTwips_1cm; + ::uno::Any aSizeVal; + aSizeVal <<= aSize; + static_cast<SfxPoolItem&>(aFrameSz).PutValue(aSizeVal, MID_FRMSIZE_SIZE|CONVERT_TWIPS); + rToSet.Put(aFrameSz); + } + } + const ::uno::Any* pFrameDirection = nullptr; + GetProperty(RES_FRAMEDIR, 0, pFrameDirection); + if(pFrameDirection) + { + SvxFrameDirectionItem aAttr(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR); + aAttr.PutValue(*pFrameDirection, 0); + rToSet.Put(aAttr); + } + const ::uno::Any* pUnknown = nullptr; + GetProperty(RES_UNKNOWNATR_CONTAINER, 0, pUnknown); + if(pUnknown) + { + SvXMLAttrContainerItem aAttr(RES_UNKNOWNATR_CONTAINER); + aAttr.PutValue(*pUnknown, 0); + rToSet.Put(aAttr); + } + + // #i18732# + const ::uno::Any* pFollowTextFlow = nullptr; + GetProperty(RES_FOLLOW_TEXT_FLOW, MID_FOLLOW_TEXT_FLOW, pFollowTextFlow); + + if (pFollowTextFlow) + { + SwFormatFollowTextFlow aFormatFollowTextFlow; + if( pFollowTextFlow ) + { + aFormatFollowTextFlow.PutValue(*pFollowTextFlow, MID_FOLLOW_TEXT_FLOW); + } + + rToSet.Put(aFormatFollowTextFlow); + } + + // #i28701# - RES_WRAP_INFLUENCE_ON_OBJPOS + const ::uno::Any* pWrapInfluenceOnObjPos = nullptr; + GetProperty(RES_WRAP_INFLUENCE_ON_OBJPOS, MID_WRAP_INFLUENCE, pWrapInfluenceOnObjPos); + const ::uno::Any* pAllowOverlap = nullptr; + GetProperty(RES_WRAP_INFLUENCE_ON_OBJPOS, MID_ALLOW_OVERLAP, pAllowOverlap); + if ( pWrapInfluenceOnObjPos || pAllowOverlap ) + { + SwFormatWrapInfluenceOnObjPos aFormatWrapInfluenceOnObjPos; + if (pWrapInfluenceOnObjPos) + aFormatWrapInfluenceOnObjPos.PutValue( *pWrapInfluenceOnObjPos, MID_WRAP_INFLUENCE ); + if (pAllowOverlap) + aFormatWrapInfluenceOnObjPos.PutValue( *pAllowOverlap, MID_ALLOW_OVERLAP ); + rToSet.Put(aFormatWrapInfluenceOnObjPos); + } + + { + const ::uno::Any* pTextVertAdjust = nullptr; + GetProperty(RES_TEXT_VERT_ADJUST, 0, pTextVertAdjust); + if ( pTextVertAdjust ) + { + SdrTextVertAdjustItem aTextVertAdjust( rFromSet.Get ( RES_TEXT_VERT_ADJUST ) ); + bRet &= static_cast<SfxPoolItem&>(aTextVertAdjust).PutValue(*pTextVertAdjust, 0); + rToSet.Put(aTextVertAdjust); + } + } + + const ::uno::Any* pDecorative = nullptr; + GetProperty(RES_DECORATIVE, 0, pDecorative); + if (pDecorative) + { + SfxBoolItem item(RES_DECORATIVE); + bRet &= item.PutValue(*pDecorative, 0); + rToSet.Put(item); + } + + const ::uno::Any* pFlySplit = nullptr; + GetProperty(RES_FLY_SPLIT, 0, pFlySplit); + if (pFlySplit) + { + SwFormatFlySplit aSplit(true); + bRet &= aSplit.PutValue(*pFlySplit, 0); + rToSet.Put(aSplit); + } + + const ::uno::Any* pWrapTextAtFlyStart = nullptr; + GetProperty(RES_WRAP_TEXT_AT_FLY_START, 0, pWrapTextAtFlyStart); + if (pWrapTextAtFlyStart) + { + SwFormatWrapTextAtFlyStart aWrapTextAtFlyStart(true); + bRet &= aWrapTextAtFlyStart.PutValue(*pWrapTextAtFlyStart, 0); + rToSet.Put(aWrapTextAtFlyStart); + } + + return bRet; +} + +namespace { + +class SwFrameProperties_Impl : public BaseFrameProperties_Impl +{ +public: + SwFrameProperties_Impl(); + + bool AnyToItemSet( SwDoc* pDoc, SfxItemSet& rFrameSet, SfxItemSet& rSet, bool& rSizeFound) override; +}; + +} + +SwFrameProperties_Impl::SwFrameProperties_Impl(): + BaseFrameProperties_Impl(/*aSwMapProvider.GetPropertyMap(PROPERTY_MAP_TEXT_FRAME)*/ ) +{ +} + +static void lcl_FillCol ( SfxItemSet &rToSet, const ::SfxItemSet &rFromSet, const ::uno::Any *pAny) +{ + if ( pAny ) + { + SwFormatCol aCol ( rFromSet.Get ( RES_COL ) ); + static_cast<SfxPoolItem&>(aCol).PutValue( *pAny, MID_COLUMNS); + rToSet.Put(aCol); + } +} + +bool SwFrameProperties_Impl::AnyToItemSet(SwDoc *pDoc, SfxItemSet& rSet, SfxItemSet&, bool& rSizeFound) +{ + // Properties for all frames + const ::uno::Any *pStyleName; + SwDocStyleSheet* pStyle = nullptr; + bool bRet; + + if ( GetProperty ( FN_UNO_FRAME_STYLE_NAME, 0, pStyleName ) ) + { + OUString sStyle; + *pStyleName >>= sStyle; + SwStyleNameMapper::FillUIName(sStyle, sStyle, SwGetPoolIdFromName::FrmFmt); + pStyle = static_cast<SwDocStyleSheet*>(pDoc->GetDocShell()->GetStyleSheetPool()->Find(sStyle, + SfxStyleFamily::Frame)); + } + + const ::uno::Any* pColumns = nullptr; + GetProperty (RES_COL, MID_COLUMNS, pColumns); + if ( pStyle ) + { + rtl::Reference< SwDocStyleSheet > xStyle( new SwDocStyleSheet( *pStyle ) ); + const ::SfxItemSet *pItemSet = &xStyle->GetItemSet(); + bRet = FillBaseProperties( rSet, *pItemSet, rSizeFound ); + lcl_FillCol ( rSet, *pItemSet, pColumns ); + } + else + { + const ::SfxItemSet *pItemSet = &pDoc->getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME )->GetAttrSet(); + bRet = FillBaseProperties( rSet, *pItemSet, rSizeFound ); + lcl_FillCol ( rSet, *pItemSet, pColumns ); + } + const ::uno::Any* pEdit; + if(GetProperty(RES_EDIT_IN_READONLY, 0, pEdit)) + { + SwFormatEditInReadonly item(RES_EDIT_IN_READONLY); + item.PutValue(*pEdit, 0); + rSet.Put(item); + } + return bRet; +} + +namespace { + +class SwGraphicProperties_Impl : public BaseFrameProperties_Impl +{ +public: + SwGraphicProperties_Impl(); + + virtual bool AnyToItemSet( SwDoc* pDoc, SfxItemSet& rFrameSet, SfxItemSet& rSet, bool& rSizeFound) override; +}; + +} + +SwGraphicProperties_Impl::SwGraphicProperties_Impl( ) : + BaseFrameProperties_Impl(/*aSwMapProvider.GetPropertyMap(PROPERTY_MAP_TEXT_GRAPHIC)*/ ) +{ +} + +static void lcl_FillMirror ( SfxItemSet &rToSet, const ::SfxItemSet &rFromSet, const ::uno::Any *pHEvenMirror, const ::uno::Any *pHOddMirror, const ::uno::Any *pVMirror, bool &rRet ) +{ + if(pHEvenMirror || pHOddMirror || pVMirror ) + { + SwMirrorGrf aMirror ( rFromSet.Get ( RES_GRFATR_MIRRORGRF ) ); + if(pHEvenMirror) + rRet &= static_cast<SfxPoolItem&>(aMirror).PutValue(*pHEvenMirror, MID_MIRROR_HORZ_EVEN_PAGES); + if(pHOddMirror) + rRet &= static_cast<SfxPoolItem&>(aMirror).PutValue(*pHOddMirror, MID_MIRROR_HORZ_ODD_PAGES); + if(pVMirror) + rRet &= static_cast<SfxPoolItem&>(aMirror).PutValue(*pVMirror, MID_MIRROR_VERT); + rToSet.Put(aMirror); + } +} + +bool SwGraphicProperties_Impl::AnyToItemSet( + SwDoc* pDoc, + SfxItemSet& rFrameSet, + SfxItemSet& rGrSet, + bool& rSizeFound) +{ + // Properties for all frames + bool bRet; + const ::uno::Any *pStyleName; + SwDocStyleSheet* pStyle = nullptr; + + if ( GetProperty ( FN_UNO_FRAME_STYLE_NAME, 0, pStyleName ) ) + { + OUString sStyle; + *pStyleName >>= sStyle; + SwStyleNameMapper::FillUIName(sStyle, sStyle, SwGetPoolIdFromName::FrmFmt); + pStyle = static_cast<SwDocStyleSheet*>(pDoc->GetDocShell()->GetStyleSheetPool()->Find(sStyle, + SfxStyleFamily::Frame)); + } + + const ::uno::Any* pHEvenMirror = nullptr; + const ::uno::Any* pHOddMirror = nullptr; + const ::uno::Any* pVMirror = nullptr; + GetProperty(RES_GRFATR_MIRRORGRF, MID_MIRROR_HORZ_EVEN_PAGES, pHEvenMirror); + GetProperty(RES_GRFATR_MIRRORGRF, MID_MIRROR_HORZ_ODD_PAGES, pHOddMirror); + GetProperty(RES_GRFATR_MIRRORGRF, MID_MIRROR_VERT, pVMirror); + + if ( pStyle ) + { + rtl::Reference< SwDocStyleSheet > xStyle( new SwDocStyleSheet(*pStyle) ); + const ::SfxItemSet *pItemSet = &xStyle->GetItemSet(); + bRet = FillBaseProperties(rFrameSet, *pItemSet, rSizeFound); + lcl_FillMirror ( rGrSet, *pItemSet, pHEvenMirror, pHOddMirror, pVMirror, bRet ); + } + else + { + const ::SfxItemSet *pItemSet = &pDoc->getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC )->GetAttrSet(); + bRet = FillBaseProperties(rFrameSet, *pItemSet, rSizeFound); + lcl_FillMirror ( rGrSet, *pItemSet, pHEvenMirror, pHOddMirror, pVMirror, bRet ); + } + + static const ::sal_uInt16 nIDs[] = + { + RES_GRFATR_CROPGRF, + RES_GRFATR_ROTATION, + RES_GRFATR_LUMINANCE, + RES_GRFATR_CONTRAST, + RES_GRFATR_CHANNELR, + RES_GRFATR_CHANNELG, + RES_GRFATR_CHANNELB, + RES_GRFATR_GAMMA, + RES_GRFATR_INVERT, + RES_GRFATR_TRANSPARENCY, + RES_GRFATR_DRAWMODE, + 0 + }; + const ::uno::Any* pAny; + for(sal_Int16 nIndex = 0; nIDs[nIndex]; nIndex++) + { + sal_uInt8 nMId = RES_GRFATR_CROPGRF == nIDs[nIndex] ? CONVERT_TWIPS : 0; + if(GetProperty(nIDs[nIndex], nMId, pAny )) + { + std::unique_ptr<SfxPoolItem> pItem(::GetDfltAttr( nIDs[nIndex] )->Clone()); + bRet &= pItem->PutValue(*pAny, nMId ); + rGrSet.Put(std::move(pItem)); + } + } + + return bRet; +} + +namespace { + +class SwOLEProperties_Impl : public SwFrameProperties_Impl +{ +public: + SwOLEProperties_Impl() {} + + virtual bool AnyToItemSet( SwDoc* pDoc, SfxItemSet& rFrameSet, SfxItemSet& rSet, bool& rSizeFound) override; +}; + +} + +bool SwOLEProperties_Impl::AnyToItemSet( + SwDoc* pDoc, SfxItemSet& rFrameSet, SfxItemSet& rSet, bool& rSizeFound) +{ + const ::uno::Any* pTemp; + if(!GetProperty(FN_UNO_CLSID, 0, pTemp) && !GetProperty(FN_UNO_STREAM_NAME, 0, pTemp) + && !GetProperty(FN_EMBEDDED_OBJECT, 0, pTemp) + && !GetProperty(FN_UNO_VISIBLE_AREA_WIDTH, 0, pTemp) + && !GetProperty(FN_UNO_VISIBLE_AREA_HEIGHT, 0, pTemp) ) + return false; + SwFrameProperties_Impl::AnyToItemSet( pDoc, rFrameSet, rSet, rSizeFound); + + return true; +} + +class SwXFrame::Impl +{ +public: + uno::WeakReference<uno::XInterface> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; +}; + +OUString SwXFrame::getImplementationName() +{ + return "SwXFrame"; +} + +sal_Bool SwXFrame::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXFrame::getSupportedServiceNames() +{ + return { "com.sun.star.text.BaseFrame", "com.sun.star.text.TextContent", "com.sun.star.document.LinkTarget" }; +} + +SwXFrame::SwXFrame(FlyCntType eSet, const ::SfxItemPropertySet* pSet, SwDoc *pDoc) + : m_pImpl(new Impl) + , m_pFrameFormat(nullptr) + , m_pPropSet(pSet) + , m_pDoc(pDoc) + , m_eType(eSet) + , m_bIsDescriptor(true) + , m_nDrawAspect(embed::Aspects::MSOLE_CONTENT) + , m_nVisibleAreaWidth(0) + , m_nVisibleAreaHeight(0) +{ + // Register ourselves as a listener to the document (via the page descriptor) + StartListening(pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); + // get the property set for the default style data + // First get the model + uno::Reference < XModel > xModel = pDoc->GetDocShell()->GetBaseModel(); + // Ask the model for its family supplier interface + uno::Reference < XStyleFamiliesSupplier > xFamilySupplier ( xModel, uno::UNO_QUERY ); + // Get the style families + uno::Reference < XNameAccess > xFamilies = xFamilySupplier->getStyleFamilies(); + // Get the Frame family (and keep it for later) + const ::uno::Any aAny = xFamilies->getByName ("FrameStyles"); + aAny >>= mxStyleFamily; + // In the derived class, we'll ask mxStyleFamily for the relevant default style + // mxStyleFamily is initialised in the SwXFrame constructor + switch(m_eType) + { + case FLYCNTTYPE_FRM: + { + uno::Any aAny2 = mxStyleFamily->getByName ("Frame"); + aAny2 >>= mxStyleData; + m_pProps.reset(new SwFrameProperties_Impl); + } + break; + case FLYCNTTYPE_GRF: + { + uno::Any aAny2 = mxStyleFamily->getByName ("Graphics"); + aAny2 >>= mxStyleData; + m_pProps.reset(new SwGraphicProperties_Impl); + } + break; + case FLYCNTTYPE_OLE: + { + uno::Any aAny2 = mxStyleFamily->getByName ("OLE"); + aAny2 >>= mxStyleData; + m_pProps.reset(new SwOLEProperties_Impl); + } + break; + + default: + m_pProps.reset(); + break; + } +} + +SwXFrame::SwXFrame(SwFrameFormat& rFrameFormat, FlyCntType eSet, const ::SfxItemPropertySet* pSet) + : m_pImpl(new Impl) + , m_pFrameFormat(&rFrameFormat) + , m_pPropSet(pSet) + , m_pDoc(nullptr) + , m_eType(eSet) + , m_bIsDescriptor(false) + , m_nDrawAspect(embed::Aspects::MSOLE_CONTENT) + , m_nVisibleAreaWidth(0) + , m_nVisibleAreaHeight(0) +{ + StartListening(rFrameFormat.GetNotifier()); +} + +SwXFrame::~SwXFrame() +{ + SolarMutexGuard aGuard; + m_pProps.reset(); + EndListeningAll(); +} + +template<class NameLookupIsHard> +rtl::Reference<NameLookupIsHard> +SwXFrame::CreateXFrame(SwDoc & rDoc, SwFrameFormat *const pFrameFormat) +{ + assert(!pFrameFormat || &rDoc == pFrameFormat->GetDoc()); + rtl::Reference<NameLookupIsHard> xFrame; + if (pFrameFormat) + { + xFrame = dynamic_cast<NameLookupIsHard*>(pFrameFormat->GetXObject().get().get()); // cached? + } + if (!xFrame.is()) + { + xFrame = pFrameFormat + ? new NameLookupIsHard(*pFrameFormat) + : new NameLookupIsHard(&rDoc); + if (pFrameFormat) + { + pFrameFormat->SetXObject(cppu::getXWeak(xFrame.get())); + } + // need a permanent Reference to initialize m_wThis + xFrame->SwXFrame::m_pImpl->m_wThis = uno::Reference<XWeak>(xFrame.get()); + } + return xFrame; +} + +OUString SwXFrame::getName() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + return pFormat->GetName(); + if(!m_bIsDescriptor) + throw uno::RuntimeException(); + return m_sName; +} + +void SwXFrame::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + pFormat->GetDoc()->SetFlyName(static_cast<SwFlyFrameFormat&>(*pFormat), rName); + if(pFormat->GetName() != rName) + { + throw uno::RuntimeException("SwXFrame::setName(): Illegal object name. Duplicate name?"); + } + } + else if(m_bIsDescriptor) + m_sName = rName; + else + throw uno::RuntimeException(); +} + +uno::Reference< beans::XPropertySetInfo > SwXFrame::getPropertySetInfo() +{ + uno::Reference< beans::XPropertySetInfo > xRef; + static uno::Reference< beans::XPropertySetInfo > xFrameRef; + static uno::Reference< beans::XPropertySetInfo > xGrfRef; + static uno::Reference< beans::XPropertySetInfo > xOLERef; + switch(m_eType) + { + case FLYCNTTYPE_FRM: + if( !xFrameRef.is() ) + xFrameRef = m_pPropSet->getPropertySetInfo(); + xRef = xFrameRef; + break; + case FLYCNTTYPE_GRF: + if( !xGrfRef.is() ) + xGrfRef = m_pPropSet->getPropertySetInfo(); + xRef = xGrfRef; + break; + case FLYCNTTYPE_OLE: + if( !xOLERef.is() ) + xOLERef = m_pPropSet->getPropertySetInfo(); + xRef = xOLERef; + break; + default: + ; + } + return xRef; +} + +SdrObject *SwXFrame::GetOrCreateSdrObject(SwFlyFrameFormat &rFormat) +{ + SdrObject* pObject = rFormat.FindSdrObject(); + if( !pObject ) + { + SwDoc *pDoc = rFormat.GetDoc(); + // #i52858# - method name changed + SwFlyDrawContact* pContactObject(rFormat.GetOrCreateContact()); + pObject = pContactObject->GetMaster(); + + const ::SwFormatSurround& rSurround = rFormat.GetSurround(); + pObject->SetLayer( + ( css::text::WrapTextMode_THROUGH == rSurround.GetSurround() && + !rFormat.GetOpaque().GetValue() ) ? pDoc->getIDocumentDrawModelAccess().GetHellId() + : pDoc->getIDocumentDrawModelAccess().GetHeavenId() ); + SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); + pDrawModel->GetPage(0)->InsertObject( pObject ); + } + + return pObject; +} + +static SwFrameFormat *lcl_GetFrameFormat( const ::uno::Any& rValue, SwDoc *pDoc ) +{ + SwFrameFormat *pRet = nullptr; + SwDocShell* pDocSh = pDoc->GetDocShell(); + if(pDocSh) + { + OUString uTemp; + rValue >>= uTemp; + OUString sStyle; + SwStyleNameMapper::FillUIName(uTemp, sStyle, + SwGetPoolIdFromName::FrmFmt); + SwDocStyleSheet* pStyle = + static_cast<SwDocStyleSheet*>(pDocSh->GetStyleSheetPool()->Find(sStyle, + SfxStyleFamily::Frame)); + if(pStyle) + pRet = pStyle->GetFrameFormat(); + } + + return pRet; +} + +void SwXFrame::setPropertyValue(const OUString& rPropertyName, const ::uno::Any& _rValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if (!pFormat && !IsDescriptor()) + throw uno::RuntimeException(); + + // Hack to support hidden property to transfer textDirection + if(rPropertyName == "FRMDirection") + { + if (pFormat) + { + SwDocModifyAndUndoGuard guard(*pFormat); + SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR); + aItem.PutValue(_rValue, 0); + pFormat->SetFormatAttr(aItem); + } + else // if(IsDescriptor()) + { + m_pProps->SetProperty(o3tl::narrowing<sal_uInt16>(RES_FRAMEDIR), 0, _rValue); + } + return; + } + + const ::SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + + if (!pEntry) + { + // Hack to skip the dummy CursorNotIgnoreTables property + if (rPropertyName != "CursorNotIgnoreTables") + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak()); + return; + } + + const sal_uInt8 nMemberId(pEntry->nMemberId); + uno::Any aValue(_rValue); + + // check for needed metric translation + if(pEntry->nMoreFlags & PropertyMoreFlags::METRIC_ITEM) + { + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == pEntry->nWID || XATTR_FILLBMP_SIZEY == pEntry->nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(aValue >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const SwDoc* pDoc = (IsDescriptor() ? m_pDoc : pFormat->GetDoc()); + const SfxItemPool& rPool = pDoc->GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(pEntry->nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertFromMM(eMapUnit, aValue); + } + } + } + + if(pFormat) + { + bool bNextFrame = false; + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + + SwDoc* pDoc = pFormat->GetDoc(); + if ( ((m_eType == FLYCNTTYPE_GRF) && isGRFATR(pEntry->nWID)) || + (FN_PARAM_CONTOUR_PP == pEntry->nWID) || + (FN_UNO_IS_AUTOMATIC_CONTOUR == pEntry->nWID) || + (FN_UNO_IS_PIXEL_CONTOUR == pEntry->nWID) ) + { + const ::SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwNoTextNode* pNoText = aIdx.GetNode().GetNoTextNode(); + if(pEntry->nWID == FN_PARAM_CONTOUR_PP) + { + drawing::PointSequenceSequence aParam; + if(!aValue.hasValue()) + pNoText->SetContour(nullptr); + else if(aValue >>= aParam) + { + tools::PolyPolygon aPoly(o3tl::narrowing<sal_uInt16>(aParam.getLength())); + for(const ::drawing::PointSequence& rPointSeq : std::as_const(aParam)) + { + sal_Int32 nPoints = rPointSeq.getLength(); + const ::awt::Point* pPoints = rPointSeq.getConstArray(); + tools::Polygon aSet( o3tl::narrowing<sal_uInt16>(nPoints) ); + for(sal_Int32 j = 0; j < nPoints; j++) + { + Point aPoint(pPoints[j].X, pPoints[j].Y); + aSet.SetPoint(aPoint, o3tl::narrowing<sal_uInt16>(j)); + } + // Close polygon if it isn't closed already. + aSet.Optimize( PolyOptimizeFlags::CLOSE ); + aPoly.Insert( aSet ); + } + pNoText->SetContourAPI( &aPoly ); + } + else + throw lang::IllegalArgumentException(); + } + else if(pEntry->nWID == FN_UNO_IS_AUTOMATIC_CONTOUR ) + { + pNoText->SetAutomaticContour( *o3tl::doAccess<bool>(aValue) ); + } + else if(pEntry->nWID == FN_UNO_IS_PIXEL_CONTOUR ) + { + // The IsPixelContour property can only be set if there + // is no contour, or if the contour has been set by the + // API itself (or in other words, if the contour isn't + // used already). + if( pNoText->HasContour_() && pNoText->IsContourMapModeValid() ) + throw lang::IllegalArgumentException(); + + pNoText->SetPixelContour( *o3tl::doAccess<bool>(aValue) ); + + } + else + { + SfxItemSet aSet(pNoText->GetSwAttrSet()); + m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + pNoText->SetAttr(aSet); + } + } + } + // New attribute Title + else if( FN_UNO_TITLE == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + OUString sTitle; + aValue >>= sTitle; + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + rFlyFormat.GetDoc()->SetFlyFrameTitle(rFlyFormat, sTitle); + } + else if (pEntry->nWID == FN_UNO_TOOLTIP) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + OUString sTooltip; + aValue >>= sTooltip; + rFlyFormat.SetObjTooltip(sTooltip); + } + // New attribute Description + else if( FN_UNO_DESCRIPTION == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + OUString sDescription; + aValue >>= sDescription; + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + rFlyFormat.GetDoc()->SetFlyFrameDescription(rFlyFormat, sDescription); + } + else if(FN_UNO_FRAME_STYLE_NAME == pEntry->nWID) + { + SwFrameFormat *pFrameFormat = lcl_GetFrameFormat( aValue, pFormat->GetDoc() ); + if( !pFrameFormat ) + throw lang::IllegalArgumentException(); + + UnoActionContext aAction(pFormat->GetDoc()); + + std::optional<SfxItemSet> pSet; + // #i31771#, #i25798# - No adjustment of + // anchor ( no call of method <sw_ChkAndSetNewAnchor(..)> ), + // if document is currently in reading mode. + if ( !pFormat->GetDoc()->IsInReading() ) + { + // see SwFEShell::SetFrameFormat( SwFrameFormat *pNewFormat, bool bKeepOrient, Point* pDocPos ) + SwFlyFrame *pFly = nullptr; + if (auto pFlyFrameFormat = dynamic_cast<const SwFlyFrameFormat*>(pFormat) ) + pFly = pFlyFrameFormat->GetFrame(); + if ( pFly ) + { + if( const SwFormatAnchor* pItem = pFrameFormat->GetItemIfSet( RES_ANCHOR, false )) + { + pSet.emplace( pDoc->GetAttrPool(), aFrameFormatSetRange ); + pSet->Put( *pItem ); + if ( pFormat->GetDoc()->GetEditShell() != nullptr + && !sw_ChkAndSetNewAnchor( *pFly, *pSet ) ) + { + pSet.reset(); + } + } + } + } + + pFormat->GetDoc()->SetFrameFormatToFly( *pFormat, *pFrameFormat, pSet ? &*pSet : nullptr ); + } + else if (FN_UNO_GRAPHIC_FILTER == pEntry->nWID) + { + OUString sGrfName; + OUString sFltName; + SwDoc::GetGrfNms( *static_cast<SwFlyFrameFormat*>(pFormat), &sGrfName, &sFltName ); + aValue >>= sFltName; + UnoActionContext aAction(pFormat->GetDoc()); + const ::SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if (pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwGrfNode* pGrfNode = aIdx.GetNode().GetGrfNode(); + if(!pGrfNode) + { + throw uno::RuntimeException(); + } + SwPaM aGrfPaM(*pGrfNode); + pFormat->GetDoc()->getIDocumentContentOperations().ReRead(aGrfPaM, sGrfName, sFltName, nullptr); + } + } + else if (FN_UNO_GRAPHIC == pEntry->nWID || FN_UNO_GRAPHIC_URL == pEntry->nWID) + { + Graphic aGraphic; + if (aValue.has<OUString>()) + { + OUString aURL = aValue.get<OUString>(); + if (!aURL.isEmpty()) + { + aGraphic = vcl::graphic::loadFromURL(aURL); + } + } + else if (aValue.has<uno::Reference<graphic::XGraphic>>()) + { + uno::Reference<graphic::XGraphic> xGraphic = aValue.get<uno::Reference<graphic::XGraphic>>(); + if (xGraphic.is()) + { + aGraphic = Graphic(xGraphic); + } + } + + if (!aGraphic.IsNone()) + { + const ::SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if (pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwGrfNode* pGrfNode = aIdx.GetNode().GetGrfNode(); + if (!pGrfNode) + { + throw uno::RuntimeException(); + } + SwPaM aGrfPaM(*pGrfNode); + pFormat->GetDoc()->getIDocumentContentOperations().ReRead(aGrfPaM, OUString(), OUString(), &aGraphic); + } + } + } + else if (FN_UNO_REPLACEMENT_GRAPHIC == pEntry->nWID || FN_UNO_REPLACEMENT_GRAPHIC_URL == pEntry->nWID) + { + Graphic aGraphic; + if (aValue.has<OUString>()) + { + OUString aURL = aValue.get<OUString>(); + if (!aURL.isEmpty()) + { + aGraphic = vcl::graphic::loadFromURL(aURL); + } + } + else if (aValue.has<uno::Reference<graphic::XGraphic>>()) + { + uno::Reference<graphic::XGraphic> xGraphic = aValue.get<uno::Reference<graphic::XGraphic>>(); + if (xGraphic.is()) + { + aGraphic = Graphic(xGraphic); + } + } + + if (!aGraphic.IsNone()) + { + const ::SwFormatContent* pCnt = &pFormat->GetContent(); + if ( pCnt->GetContentIdx() && pDoc->GetNodes()[ pCnt->GetContentIdx()->GetIndex() + 1 ] ) + { + SwOLENode* pOleNode = pDoc->GetNodes()[ pCnt->GetContentIdx()->GetIndex() + 1 ]->GetOLENode(); + + if ( pOleNode ) + { + svt::EmbeddedObjectRef &rEmbeddedObject = pOleNode->GetOLEObj().GetObject(); + rEmbeddedObject.SetGraphic(aGraphic, OUString() ); + } + } + } + } + else if((bNextFrame = (rPropertyName == UNO_NAME_CHAIN_NEXT_NAME)) + || rPropertyName == UNO_NAME_CHAIN_PREV_NAME) + { + OUString sChainName; + aValue >>= sChainName; + if (sChainName.isEmpty()) + { + if(bNextFrame) + pDoc->Unchain(*pFormat); + else + { + const SwFormatChain& aChain( pFormat->GetChain() ); + SwFrameFormat *pPrev = aChain.GetPrev(); + if(pPrev) + pDoc->Unchain(*pPrev); + } + } + else + { + const size_t nCount = pDoc->GetFlyCount(FLYCNTTYPE_FRM); + + SwFrameFormat* pChain = nullptr; + for( size_t i = 0; i < nCount; ++i ) + { + SwFrameFormat* pFormat2 = pDoc->GetFlyNum(i, FLYCNTTYPE_FRM); + if(sChainName == pFormat2->GetName() ) + { + pChain = pFormat2; + break; + } + } + if(pChain) + { + SwFrameFormat* pSource = bNextFrame ? pFormat : pChain; + SwFrameFormat* pDest = bNextFrame ? pChain: pFormat; + pDoc->Chain(*pSource, *pDest); + } + } + } + else if(FN_UNO_Z_ORDER == pEntry->nWID) + { + sal_Int32 nZOrder = - 1; + aValue >>= nZOrder; + + // Don't set an explicit ZOrder on TextBoxes. + if( nZOrder >= 0 && !SwTextBoxHelper::isTextBox(pFormat, RES_FLYFRMFMT) ) + { + SdrObject* pObject = + GetOrCreateSdrObject( static_cast<SwFlyFrameFormat&>(*pFormat) ); + SwDrawModel *pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); + pDrawModel->GetPage(0)-> + SetObjectOrdNum(pObject->GetOrdNum(), nZOrder); + } + } + else if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORFRAME == nMemberId) + { + bool bDone = false; + uno::Reference<text::XTextFrame> xFrame; + if(aValue >>= xFrame) + { + SwXFrame* pFrame = dynamic_cast<SwXFrame*>(xFrame.get()); + if(pFrame && this != pFrame && pFrame->GetFrameFormat() && pFrame->GetFrameFormat()->GetDoc() == pDoc) + { + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aSet( pDoc->GetAttrPool() ); + aSet.SetParent(&pFormat->GetAttrSet()); + SwFormatAnchor aAnchor = static_cast<const SwFormatAnchor&>(aSet.Get(pEntry->nWID)); + + SwPosition aPos(*pFrame->GetFrameFormat()->GetContent().GetContentIdx()); + aAnchor.SetAnchor(&aPos); + aAnchor.SetType(RndStdIds::FLY_AT_FLY); + aSet.Put(aAnchor); + pDoc->SetFlyFrameAttr( *pFormat, aSet ); + bDone = true; + } + } + if(!bDone) + throw lang::IllegalArgumentException(); + } + else + { + // standard UNO API write attributes + // adapt former attr from SvxBrushItem::PutValue to new items XATTR_FILL_FIRST, XATTR_FILL_LAST + SfxItemSetFixed + <RES_FRMATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER, + + // FillAttribute support + XATTR_FILL_FIRST, XATTR_FILL_LAST> + aSet( pDoc->GetAttrPool()); + bool bDone(false); + + aSet.SetParent(&pFormat->GetAttrSet()); + + if(RES_BACKGROUND == pEntry->nWID) + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND, true, pDoc->IsInXMLImport())); + std::unique_ptr<SvxBrushItem> aChangedBrushItem(aOriginalBrushItem->Clone()); + + aChangedBrushItem->PutValue(aValue, nMemberId); + + if(*aChangedBrushItem != *aOriginalBrushItem) + { + setSvxBrushItemAsFillAttributesToTargetSet(*aChangedBrushItem, aSet); + pFormat->GetDoc()->SetFlyFrameAttr( *pFormat, aSet ); + } + + bDone = true; + } + else if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + drawing::BitmapMode eMode; + + if(!(aValue >>= eMode)) + { + sal_Int32 nMode = 0; + + if(!(aValue >>= nMode)) + { + throw lang::IllegalArgumentException(); + } + + eMode = static_cast<drawing::BitmapMode>(nMode); + } + + aSet.Put(XFillBmpStretchItem(drawing::BitmapMode_STRETCH == eMode)); + aSet.Put(XFillBmpTileItem(drawing::BitmapMode_REPEAT == eMode)); + pFormat->GetDoc()->SetFlyFrameAttr( *pFormat, aSet ); + bDone = true; + } + + switch(nMemberId) + { + case MID_NAME: + { + // when named items get set, replace these with the NameOrIndex items + // which exist already in the pool + switch(pEntry->nWID) + { + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_FILLBITMAP: + case XATTR_FILLFLOATTRANSPARENCE: + { + OUString aTempName; + + if(!(aValue >>= aTempName )) + { + throw lang::IllegalArgumentException(); + } + + bDone = SvxShape::SetFillAttribute(pEntry->nWID, aTempName, aSet); + break; + } + default: + { + break; + } + } + break; + } + case MID_BITMAP: + { + switch(pEntry->nWID) + { + case XATTR_FILLBITMAP: + { + Graphic aNullGraphic; + XFillBitmapItem aXFillBitmapItem(std::move(aNullGraphic)); + + aXFillBitmapItem.PutValue(aValue, nMemberId); + aSet.Put(aXFillBitmapItem); + bDone = true; + break; + } + default: + { + break; + } + } + break; + } + default: + { + break; + } + } + + if(!bDone) + { + m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + } + + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORTYPE == nMemberId) + { + SwFormatAnchor aAnchor = static_cast<const SwFormatAnchor&>(aSet.Get(pEntry->nWID)); + if(aAnchor.GetAnchorId() == RndStdIds::FLY_AT_FLY) + { + const ::SwNode* pAnchorNode = aAnchor.GetAnchorNode(); + SwFrameFormat* pFlyFormat = pAnchorNode ? pAnchorNode->GetFlyFormat() : nullptr; + if(!pFlyFormat || pFlyFormat->Which() == RES_DRAWFRMFMT) + { + throw lang::IllegalArgumentException("Anchor to frame: no frame found", nullptr, 0); + } + else + { + SwPosition aPos = *aAnchor.GetContentAnchor(); + aPos.Assign( *pFlyFormat->GetContent().GetContentIdx() ); + aAnchor.SetAnchor(&aPos); + aSet.Put(aAnchor); + } + } + else if ((aAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && + !aAnchor.GetAnchorNode()) + { + SwNode& rNode = pDoc->GetNodes().GetEndOfContent(); + SwPaM aPam(rNode); + aPam.Move( fnMoveBackward, GoInDoc ); + aAnchor.SetAnchor( aPam.Start() ); + aSet.Put(aAnchor); + } + + // #i31771#, #i25798# - No adjustment of + // anchor ( no call of method <sw_ChkAndSetNewAnchor(..)> ), + // if document is currently in reading mode. + if ( !pFormat->GetDoc()->IsInReading() ) + { + // see SwFEShell::SetFlyFrameAttr( SfxItemSet& rSet ) + SwFlyFrame *pFly = nullptr; + if (auto pFrameFormat = dynamic_cast<SwFlyFrameFormat*>( pFormat) ) + pFly = pFrameFormat->GetFrame(); + if (pFly) + { + if( const SwFormatAnchor* pItem = aSet.GetItemIfSet( RES_ANCHOR, false )) + { + aSet.Put( *pItem ); + if ( pFormat->GetDoc()->GetEditShell() != nullptr ) + { + sw_ChkAndSetNewAnchor( *pFly, aSet ); + } + } + } + } + + pFormat->GetDoc()->SetFlyFrameAttr( *pFormat, aSet ); + } + else if(FN_UNO_CLSID == pEntry->nWID || FN_UNO_STREAM_NAME == pEntry->nWID || FN_EMBEDDED_OBJECT == pEntry->nWID) + { + throw lang::IllegalArgumentException(); + } + else + { + SwDocModifyAndUndoGuard guard(*pFormat); + pFormat->SetFormatAttr(aSet); + } + } + } + else // if(IsDescriptor()) + { + m_pProps->SetProperty(pEntry->nWID, nMemberId, aValue); + if( FN_UNO_FRAME_STYLE_NAME == pEntry->nWID ) + { + OUString sStyleName; + aValue >>= sStyleName; + try + { + uno::Any aAny = mxStyleFamily->getByName ( sStyleName ); + aAny >>= mxStyleData; + } + catch ( container::NoSuchElementException const & ) + { + } + catch ( lang::WrappedTargetException const & ) + { + } + catch ( uno::RuntimeException const & ) + { + } + } + else if (FN_UNO_DRAW_ASPECT == pEntry->nWID) + { + OUString sAspect = ""; + aValue >>= sAspect; + + if (sAspect == "Icon") + m_nDrawAspect = embed::Aspects::MSOLE_ICON; + else if (sAspect == "Content") + m_nDrawAspect = embed::Aspects::MSOLE_CONTENT; + } + else if (FN_UNO_VISIBLE_AREA_WIDTH == pEntry->nWID) + { + OUString sAspect = ""; + aValue >>= sAspect; + m_nVisibleAreaWidth = sAspect.toInt64(); + } + else if (FN_UNO_VISIBLE_AREA_HEIGHT == pEntry->nWID) + { + OUString sAspect = ""; + aValue >>= sAspect; + m_nVisibleAreaHeight = sAspect.toInt64(); + } + } +} + +namespace +{ +/// Redirect error popups to developer warnings for the duration of the UNO API call. +class DisplayLockGuard +{ + bool m_bLock; + +public: + DisplayLockGuard() + { + m_bLock = ErrorRegistry::GetLock(); + ErrorRegistry::SetLock(true); + } + + ~DisplayLockGuard() { ErrorRegistry::SetLock(m_bLock); } +}; +} + +uno::Any SwXFrame::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + DisplayLockGuard aDisplayGuard; + uno::Any aAny; + SwFrameFormat* pFormat = GetFrameFormat(); + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + + const sal_uInt8 nMemberId(pEntry->nMemberId); + + if(FN_UNO_ANCHOR_TYPES == pEntry->nWID) + { + uno::Sequence<text::TextContentAnchorType> aTypes + { + text::TextContentAnchorType_AT_PARAGRAPH, + text::TextContentAnchorType_AS_CHARACTER, + text::TextContentAnchorType_AT_PAGE, + text::TextContentAnchorType_AT_FRAME, + text::TextContentAnchorType_AT_CHARACTER + }; + aAny <<= aTypes; + } + else if(pFormat) + { + if( ((m_eType == FLYCNTTYPE_GRF) || (m_eType == FLYCNTTYPE_OLE)) && + (isGRFATR(pEntry->nWID) || + pEntry->nWID == FN_PARAM_CONTOUR_PP || + pEntry->nWID == FN_UNO_IS_AUTOMATIC_CONTOUR || + pEntry->nWID == FN_UNO_IS_PIXEL_CONTOUR )) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwNoTextNode* pNoText = aIdx.GetNode().GetNoTextNode(); + if(pEntry->nWID == FN_PARAM_CONTOUR_PP) + { + tools::PolyPolygon aContour; + if( pNoText->GetContourAPI( aContour ) ) + { + drawing::PointSequenceSequence aPtSeq(aContour.Count()); + drawing::PointSequence* pPSeq = aPtSeq.getArray(); + for(sal_uInt16 i = 0; i < aContour.Count(); i++) + { + const tools::Polygon& rPoly = aContour.GetObject(i); + pPSeq[i].realloc(rPoly.GetSize()); + awt::Point* pPoints = pPSeq[i].getArray(); + for(sal_uInt16 j = 0; j < rPoly.GetSize(); j++) + { + const Point& rPoint = rPoly.GetPoint(j); + pPoints[j].X = rPoint.X(); + pPoints[j].Y = rPoint.Y(); + } + } + aAny <<= aPtSeq; + } + } + else if(pEntry->nWID == FN_UNO_IS_AUTOMATIC_CONTOUR ) + { + aAny <<= pNoText->HasAutomaticContour(); + } + else if(pEntry->nWID == FN_UNO_IS_PIXEL_CONTOUR ) + { + aAny <<= pNoText->IsPixelContour(); + } + else + { + const SfxItemSet& aSet(pNoText->GetSwAttrSet()); + m_pPropSet->getPropertyValue(*pEntry, aSet, aAny); + } + } + } + else if (FN_UNO_REPLACEMENT_GRAPHIC == pEntry->nWID) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + uno::Reference<graphic::XGraphic> xGraphic; + + if (pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwGrfNode* pGrfNode = aIdx.GetNode().GetGrfNode(); + if (!pGrfNode) + throw uno::RuntimeException(); + + const GraphicObject* pGraphicObject = pGrfNode->GetReplacementGrfObj(); + + if (pGraphicObject) + { + xGraphic = pGraphicObject->GetGraphic().GetXGraphic(); + } + } + aAny <<= xGraphic; + } + else if( FN_UNO_GRAPHIC_FILTER == pEntry->nWID ) + { + OUString sFltName; + SwDoc::GetGrfNms( *static_cast<SwFlyFrameFormat*>(pFormat), nullptr, &sFltName ); + aAny <<= sFltName; + } + else if( FN_UNO_GRAPHIC_URL == pEntry->nWID ) + { + throw uno::RuntimeException("Getting from this property is not supported"); + } + else if( FN_UNO_GRAPHIC == pEntry->nWID ) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwGrfNode* pGrfNode = aIdx.GetNode().GetGrfNode(); + if(!pGrfNode) + throw uno::RuntimeException(); + aAny <<= pGrfNode->GetGrf().GetXGraphic(); + } + } + else if( FN_UNO_TRANSFORMED_GRAPHIC == pEntry->nWID + || FN_UNO_GRAPHIC_PREVIEW == pEntry->nWID ) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwGrfNode* pGrfNode = aIdx.GetNode().GetGrfNode(); + if(!pGrfNode) + throw uno::RuntimeException(); + + SwDoc* pDoc = pFormat->GetDoc(); + if (pDoc) + { + if (const SwEditShell* pEditShell = pDoc->GetEditShell()) + { + SwFrame* pCurrFrame = pEditShell->GetCurrFrame(false); + GraphicAttr aGraphicAttr; + pGrfNode->GetGraphicAttr( aGraphicAttr, pCurrFrame ); + const GraphicObject aGraphicObj = pGrfNode->GetGrfObj(); + + awt::Size aFrameSize = getSize(); + Size aSize100thmm(aFrameSize.Width, aFrameSize.Height); + Size aSize = OutputDevice::LogicToLogic(aSize100thmm, MapMode(MapUnit::Map100thMM), aGraphicObj.GetPrefMapMode()); + + if (FN_UNO_GRAPHIC_PREVIEW == pEntry->nWID) + { + double fX = static_cast<double>(aSize.getWidth()) / 1280; + double fY = static_cast<double>(aSize.getHeight()) / 720; + double fFactor = fX > fY ? fX : fY; + if (fFactor > 1.0) + { + aSize.setWidth(aSize.getWidth() / fFactor); + aSize.setHeight(aSize.getHeight() / fFactor); + } + } + + Graphic aGraphic = aGraphicObj.GetTransformedGraphic(aSize, aGraphicObj.GetPrefMapMode(), aGraphicAttr); + aAny <<= aGraphic.GetXGraphic(); + } + } + } + } + else if(FN_UNO_FRAME_STYLE_NAME == pEntry->nWID) + { + aAny <<= SwStyleNameMapper::GetProgName(pFormat->DerivedFrom()->GetName(), SwGetPoolIdFromName::FrmFmt ); + } + // #i73249# + else if( FN_UNO_TITLE == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + aAny <<= rFlyFormat.GetObjTitle(); + } + else if (pEntry->nWID == FN_UNO_TOOLTIP) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + aAny <<= rFlyFormat.GetObjTooltip(); + } + // New attribute Description + else if( FN_UNO_DESCRIPTION == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + aAny <<= rFlyFormat.GetObjDescription(); + } + else if(m_eType == FLYCNTTYPE_GRF && + (rPropertyName == UNO_NAME_ACTUAL_SIZE)) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + Size aActSize = aIdx.GetNode().GetNoTextNode()->GetTwipSize(); + awt::Size aTmp; + aTmp.Width = convertTwipToMm100(aActSize.Width()); + aTmp.Height = convertTwipToMm100(aActSize.Height()); + aAny <<= aTmp; + } + } + else if(FN_PARAM_LINK_DISPLAY_NAME == pEntry->nWID) + { + aAny <<= pFormat->GetName(); + } + else if(FN_UNO_Z_ORDER == pEntry->nWID) + { + const SdrObject* pObj = pFormat->FindRealSdrObject(); + if( pObj == nullptr ) + pObj = pFormat->FindSdrObject(); + if( pObj ) + { + aAny <<= static_cast<sal_Int32>(pObj->GetOrdNum()); + } + } + else if(FN_UNO_CLSID == pEntry->nWID || FN_UNO_MODEL == pEntry->nWID|| + FN_UNO_COMPONENT == pEntry->nWID ||FN_UNO_STREAM_NAME == pEntry->nWID|| + FN_EMBEDDED_OBJECT == pEntry->nWID) + { + SwDoc* pDoc = pFormat->GetDoc(); + const SwFormatContent* pCnt = &pFormat->GetContent(); + OSL_ENSURE( pCnt->GetContentIdx() && + pDoc->GetNodes()[ pCnt->GetContentIdx()-> + GetIndex() + 1 ]->GetOLENode(), "no OLE-Node?"); + + SwOLENode* pOleNode = pDoc->GetNodes()[ pCnt->GetContentIdx() + ->GetIndex() + 1 ]->GetOLENode(); + uno::Reference < embed::XEmbeddedObject > xIP = pOleNode->GetOLEObj().GetOleRef(); + OUString aHexCLSID; + { + SvGlobalName aClassName( xIP->getClassID() ); + aHexCLSID = aClassName.GetHexName(); + if(FN_UNO_CLSID != pEntry->nWID) + { + if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) + { + uno::Reference < lang::XComponent > xComp( xIP->getComponent(), uno::UNO_QUERY ); + uno::Reference < frame::XModel > xModel( xComp, uno::UNO_QUERY ); + if ( FN_EMBEDDED_OBJECT == pEntry->nWID ) + { + // when exposing the EmbeddedObject, ensure it has a client site + OSL_ENSURE( pDoc->GetDocShell(), "no doc shell => no client site" ); + if ( pDoc->GetDocShell() ) + pDoc->GetDocShell()->GetIPClient( svt::EmbeddedObjectRef( xIP, embed::Aspects::MSOLE_CONTENT ) ); + aAny <<= xIP; + } + else if ( xModel.is() ) + aAny <<= xModel; + else if ( FN_UNO_COMPONENT == pEntry->nWID ) + aAny <<= xComp; + } + } + } + + if(FN_UNO_CLSID == pEntry->nWID) + aAny <<= aHexCLSID; + else if(FN_UNO_STREAM_NAME == pEntry->nWID) + { + aAny <<= pOleNode->GetOLEObj().GetCurrentPersistName(); + } + else if(FN_EMBEDDED_OBJECT == pEntry->nWID) + { + aAny <<= pOleNode->GetOLEObj().GetOleRef(); + } + } + else if(WID_LAYOUT_SIZE == pEntry->nWID) + { + // format document completely in order to get correct value (no EditShell for ole embedded case) + if (SwEditShell* pEditShell = pFormat->GetDoc()->GetEditShell()) + pEditShell->CalcLayout(); + + SwFrame* pTmpFrame = SwIterator<SwFrame,SwFormat>( *pFormat ).First(); + if ( pTmpFrame ) + { + OSL_ENSURE( pTmpFrame->isFrameAreaDefinitionValid(), "frame not valid" ); + const SwRect &rRect = pTmpFrame->getFrameArea(); + Size aMM100Size = o3tl::convert( + Size( rRect.Width(), rRect.Height() ), + o3tl::Length::twip, o3tl::Length::mm100 ); + aAny <<= awt::Size( aMM100Size.Width(), aMM100Size.Height() ); + } + } + else if(pEntry->nWID == FN_UNO_PARENT_TEXT) + { + if (!m_xParentText.is()) + { + const SwFormatAnchor& rFormatAnchor = pFormat->GetAnchor(); + if (rFormatAnchor.GetAnchorNode()) + { + m_xParentText = sw::CreateParentXText(*pFormat->GetDoc(), *rFormatAnchor.GetContentAnchor()); + } + } + aAny <<= m_xParentText; + } + else + { + // standard UNO API read attributes + // adapt former attr from SvxBrushItem::PutValue to new items XATTR_FILL_FIRST, XATTR_FILL_LAST + const SwAttrSet& rSet = pFormat->GetAttrSet(); + bool bDone(false); + + if(RES_BACKGROUND == pEntry->nWID) + { + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND)); + + if(!aOriginalBrushItem->QueryValue(aAny, nMemberId)) + { + OSL_ENSURE(false, "Error getting attribute from RES_BACKGROUND (!)"); + } + + bDone = true; + } + else if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + if (rSet.Get(XATTR_FILLBMP_TILE).GetValue()) + { + aAny <<= drawing::BitmapMode_REPEAT; + } + else if (rSet.Get(XATTR_FILLBMP_STRETCH).GetValue()) + { + aAny <<= drawing::BitmapMode_STRETCH; + } + else + { + aAny <<= drawing::BitmapMode_NO_REPEAT; + } + + bDone = true; + } + + if(!bDone) + { + m_pPropSet->getPropertyValue(*pEntry, rSet, aAny); + } + } + } + else if(IsDescriptor()) + { + if ( ! m_pDoc ) + throw uno::RuntimeException(); + if(WID_LAYOUT_SIZE != pEntry->nWID) // there is no LayoutSize in a descriptor + { + const uno::Any* pAny = nullptr; + if (!m_pProps->GetProperty(pEntry->nWID, nMemberId, pAny)) + aAny = mxStyleData->getPropertyValue( rPropertyName ); + else if ( pAny ) + aAny = *pAny; + } + } + else + throw uno::RuntimeException(); + + if (pEntry->aType == ::cppu::UnoType<sal_Int16>::get() && pEntry->aType != aAny.getValueType()) + { + // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here + sal_Int32 nValue = 0; + aAny >>= nValue; + aAny <<= static_cast<sal_Int16>(nValue); + } + + // check for needed metric translation + if(pEntry->nMoreFlags & PropertyMoreFlags::METRIC_ITEM) + { + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == pEntry->nWID || XATTR_FILLBMP_SIZEY == pEntry->nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(aAny >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const SwDoc* pDoc = (IsDescriptor() ? m_pDoc : GetFrameFormat()->GetDoc()); + const SfxItemPool& rPool = pDoc->GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(pEntry->nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertToMM(eMapUnit, aAny); + } + } + } + + return aAny; +} + +void SwXFrame::addPropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFrame::removePropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFrame::addVetoableChangeListener(const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFrame::removeVetoableChangeListener( + const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +beans::PropertyState SwXFrame::getPropertyState( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Sequence< OUString > aPropertyNames { rPropertyName }; + uno::Sequence< beans::PropertyState > aStates = getPropertyStates(aPropertyNames); + return aStates.getConstArray()[0]; +} + +uno::Sequence< beans::PropertyState > SwXFrame::getPropertyStates( + const uno::Sequence< OUString >& aPropertyNames ) +{ + SolarMutexGuard aGuard; + uno::Sequence< beans::PropertyState > aStates(aPropertyNames.getLength()); + auto [pStates, end] = asNonConstRange(aStates); + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const OUString* pNames = aPropertyNames.getConstArray(); + const SwAttrSet& rFormatSet = pFormat->GetAttrSet(); + for(int i = 0; i < aPropertyNames.getLength(); i++) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(pNames[i]); + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + pNames[i], getXWeak() ); + + if(pEntry->nWID == FN_UNO_ANCHOR_TYPES|| + pEntry->nWID == FN_PARAM_LINK_DISPLAY_NAME|| + FN_UNO_FRAME_STYLE_NAME == pEntry->nWID|| + FN_UNO_GRAPHIC == pEntry->nWID|| + FN_UNO_GRAPHIC_URL == pEntry->nWID|| + FN_UNO_GRAPHIC_FILTER == pEntry->nWID|| + FN_UNO_ACTUAL_SIZE == pEntry->nWID|| + FN_UNO_ALTERNATIVE_TEXT == pEntry->nWID) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + if(SfxItemState::SET == rFormatSet.GetItemState(XATTR_FILLBMP_STRETCH, false) + || SfxItemState::SET == rFormatSet.GetItemState(XATTR_FILLBMP_TILE, false)) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_AMBIGUOUS_VALUE; + } + } + // for FlyFrames we need to mark the used properties from type RES_BACKGROUND + // as beans::PropertyState_DIRECT_VALUE to let users of this property call + // getPropertyValue where the member properties will be mapped from the + // fill attributes to the according SvxBrushItem entries + else if (RES_BACKGROUND == pEntry->nWID) + { + if (SWUnoHelper::needToMapFillItemsToSvxBrushItemTypes(rFormatSet, pEntry->nMemberId)) + pStates[i] = beans::PropertyState_DIRECT_VALUE; + else + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + else + { + if ((m_eType == FLYCNTTYPE_GRF) && isGRFATR(pEntry->nWID)) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwNoTextNode* pNoText = aIdx.GetNode().GetNoTextNode(); + const SfxItemSet& aSet(pNoText->GetSwAttrSet()); + aSet.GetItemState(pEntry->nWID); + if(SfxItemState::SET == aSet.GetItemState( pEntry->nWID, false )) + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + } + else + { + if(SfxItemState::SET == rFormatSet.GetItemState( pEntry->nWID, false )) + pStates[i] = beans::PropertyState_DIRECT_VALUE; + else + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + } + } + } + else if(IsDescriptor()) + { + std::fill(pStates, end, beans::PropertyState_DIRECT_VALUE); + } + else + throw uno::RuntimeException(); + return aStates; +} + +void SwXFrame::setPropertyToDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw uno::RuntimeException("setPropertyToDefault: property is read-only: " + rPropertyName, getXWeak() ); + + if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + SwDoc* pDoc = pFormat->GetDoc(); + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet(pDoc->GetAttrPool()); + aSet.SetParent(&pFormat->GetAttrSet()); + + aSet.ClearItem(XATTR_FILLBMP_STRETCH); + aSet.ClearItem(XATTR_FILLBMP_TILE); + + SwDocModifyAndUndoGuard guard(*pFormat); + pFormat->SetFormatAttr(aSet); + } + else if( pEntry->nWID && + pEntry->nWID != FN_UNO_ANCHOR_TYPES && + pEntry->nWID != FN_PARAM_LINK_DISPLAY_NAME) + { + if ( (m_eType == FLYCNTTYPE_GRF) && isGRFATR(pEntry->nWID) ) + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + if(pIdx) + { + SwNodeIndex aIdx(*pIdx, 1); + SwNoTextNode* pNoText = aIdx.GetNode().GetNoTextNode(); + { + SfxItemSet aSet(pNoText->GetSwAttrSet()); + aSet.ClearItem(pEntry->nWID); + pNoText->SetAttr(aSet); + } + } + } + // #i73249# + else if( FN_UNO_TITLE == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + rFlyFormat.GetDoc()->SetFlyFrameTitle(rFlyFormat, OUString()); + } + // New attribute Description + else if( FN_UNO_DESCRIPTION == pEntry->nWID ) + { + SwFlyFrameFormat& rFlyFormat = dynamic_cast<SwFlyFrameFormat&>(*pFormat); + // assure that <SdrObject> instance exists. + GetOrCreateSdrObject(rFlyFormat); + rFlyFormat.GetDoc()->SetFlyFrameDescription(rFlyFormat, OUString()); + } + else if (rPropertyName != UNO_NAME_ANCHOR_TYPE) + { + SwDoc* pDoc = pFormat->GetDoc(); + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aSet( pDoc->GetAttrPool() ); + aSet.SetParent(&pFormat->GetAttrSet()); + aSet.ClearItem(pEntry->nWID); + SwDocModifyAndUndoGuard guard(*pFormat); + pFormat->SetFormatAttr(aSet); + } + } + else + { + bool bNextFrame = rPropertyName == UNO_NAME_CHAIN_NEXT_NAME; + if( bNextFrame || rPropertyName == UNO_NAME_CHAIN_PREV_NAME ) + { + SwDoc* pDoc = pFormat->GetDoc(); + if(bNextFrame) + pDoc->Unchain(*pFormat); + else + { + const SwFormatChain& aChain( pFormat->GetChain() ); + SwFrameFormat *pPrev = aChain.GetPrev(); + if(pPrev) + pDoc->Unchain(*pPrev); + } + } + } + } + else if(!IsDescriptor()) + throw uno::RuntimeException(); + +} + +uno::Any SwXFrame::getPropertyDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + if(!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nWID < RES_FRMATR_END ) + { + const SfxPoolItem& rDefItem = + pFormat->GetDoc()->GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(aRet, pEntry->nMemberId); + } + + } + else if(!IsDescriptor()) + throw uno::RuntimeException(); + return aRet; +} + +void SAL_CALL SwXFrame::addEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXFrame::removeEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +void SwXFrame::DisposeInternal() +{ + mxStyleData.clear(); + mxStyleFamily.clear(); + m_pDoc = nullptr; + uno::Reference<uno::XInterface> const xThis(m_pImpl->m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + { + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard, ev); + } + m_pFrameFormat = nullptr; + EndListeningAll(); +} +void SwXFrame::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + DisposeInternal(); +} + +void SwXFrame::dispose() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if (!pFormat) + return; + + DisposeInternal(); + SdrObject* pObj = pFormat->FindSdrObject(); + // OD 11.09.2003 #112039# - add condition to perform delete of + // format/anchor sign, not only if the object is inserted, but also + // if a contact object is registered, which isn't in the destruction. + if ( pObj && + ( pObj->IsInserted() || + ( pObj->GetUserCall() && + !static_cast<SwContact*>(pObj->GetUserCall())->IsInDTOR() ) ) ) + { + const SwFormatAnchor& rFormatAnchor = pFormat->GetAnchor(); + if (rFormatAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + SwTextNode *pTextNode = rFormatAnchor.GetAnchorNode()->GetTextNode(); + const sal_Int32 nIdx = rFormatAnchor.GetAnchorContentOffset(); + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); + } + else + pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(pFormat); + } + +} + +uno::Reference< text::XTextRange > SwXFrame::getAnchor() +{ + SolarMutexGuard aGuard; + rtl::Reference<SwXTextRange> aRef; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!pFormat) + throw uno::RuntimeException(); + + const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); + // return an anchor for non-page bound frames + // and for page bound frames that have a page no == NULL and a content position + if ((rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) || + (rAnchor.GetAnchorNode() && !rAnchor.GetPageNum())) + { + if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) + { // ensure that SwXTextRange has SwContentIndex + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), SwPosition(*rAnchor.GetAnchorNode()), nullptr); + } + else + { + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), *rAnchor.GetContentAnchor(), nullptr); + } + } + + return aRef; +} + +void SwXFrame::ResetDescriptor() +{ + m_bIsDescriptor = false; + mxStyleData.clear(); + mxStyleFamily.clear(); + m_pProps.reset(); +} + +void SwXFrame::attachToRange(uno::Reference<text::XTextRange> const& xTextRange, + SwPaM const*const pCopySource) +{ + SolarMutexGuard aGuard; + if(!IsDescriptor()) + throw uno::RuntimeException(); + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr; + if(!pDoc) + throw lang::IllegalArgumentException(); + + SwUnoInternalPaM aIntPam(*pDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aIntPam, xTextRange); + + SwNode& rNode = pDoc->GetNodes().GetEndOfContent(); + SwPaM aPam(rNode); + aPam.Move( fnMoveBackward, GoInDoc ); + + SfxItemSetFixed<RES_GRFATR_BEGIN, RES_GRFATR_END-1> aGrSet(pDoc->GetAttrPool()); + + SfxItemSetFixed< + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER, + + // FillAttribute support + XATTR_FILL_FIRST, XATTR_FILL_LAST, + + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> + aFrameSet(pDoc->GetAttrPool() ); + + // set correct parent to get the XFILL_NONE FillStyle as needed + aFrameSet.SetParent(&pDoc->GetDfltFrameFormat()->GetAttrSet()); + + // no the related items need to be added to the set + bool bSizeFound; + if (!m_pProps->AnyToItemSet(pDoc, aFrameSet, aGrSet, bSizeFound)) + throw lang::IllegalArgumentException(); + // a TextRange is handled separately + *aPam.GetPoint() = *aIntPam.GetPoint(); + if(aIntPam.HasMark()) + { + aPam.SetMark(); + *aPam.GetMark() = *aIntPam.GetMark(); + } + + RndStdIds eAnchorId = RndStdIds::FLY_AT_PARA; + if(const SwFormatAnchor* pItem = aFrameSet.GetItemIfSet(RES_ANCHOR, false) ) + { + eAnchorId = pItem->GetAnchorId(); + if( RndStdIds::FLY_AT_FLY == eAnchorId && + !aPam.GetPointNode().FindFlyStartNode()) + { + // framebound only where a frame exists + SwFormatAnchor aAnchor(RndStdIds::FLY_AT_PARA); + aFrameSet.Put(aAnchor); + } + else if ((RndStdIds::FLY_AT_PAGE == eAnchorId) && + 0 == pItem->GetPageNum() ) + { + SwFormatAnchor aAnchor( *pItem ); + aAnchor.SetType(RndStdIds::FLY_AT_CHAR); // convert invalid at-page + aAnchor.SetAnchor( aPam.GetPoint() ); + aFrameSet.Put(aAnchor); + } + + if (eAnchorId == RndStdIds::FLY_AT_PAGE) + { + sal_Int16 nRelOrient(aFrameSet.Get(RES_HORI_ORIENT).GetRelationOrient()); + if (sw::GetAtPageRelOrientation(nRelOrient, true)) + { + SAL_WARN("sw.core", "SwXFrame: fixing invalid horizontal RelOrientation for at-page anchor"); + + SwFormatHoriOrient item(aFrameSet.Get(RES_HORI_ORIENT)); + item.SetRelationOrient(nRelOrient); + aFrameSet.Put(item); + } + } + } + + const ::uno::Any* pStyle; + SwFrameFormat *pParentFrameFormat = nullptr; + if (m_pProps->GetProperty(FN_UNO_FRAME_STYLE_NAME, 0, pStyle)) + pParentFrameFormat = lcl_GetFrameFormat( *pStyle, pDoc ); + + SwFlyFrameFormat* pFormat = nullptr; + if( m_eType == FLYCNTTYPE_FRM) + { + UnoActionContext aCont(pDoc); + if (pCopySource) + { + std::unique_ptr<SwFormatAnchor> pAnchorItem; + // the frame is inserted bound to page + // to prevent conflicts if the to-be-anchored position is part of the to-be-copied text + if (eAnchorId != RndStdIds::FLY_AT_PAGE) + { + pAnchorItem.reset(aFrameSet.Get(RES_ANCHOR).Clone()); + aFrameSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 )); + } + + // park these no longer needed PaMs somewhere safe so MakeFlyAndMove + // can delete what it likes without any assert these are pointing to + // that content + aPam.DeleteMark(); + aIntPam.DeleteMark(); + aIntPam.GetPoint()->Assign(*pDoc->GetNodes()[SwNodeOffset(0)]); + *aPam.GetPoint() = *aIntPam.GetPoint(); + + pFormat = pDoc->MakeFlyAndMove( *pCopySource, aFrameSet, + nullptr, + pParentFrameFormat ); + if(pAnchorItem && pFormat) + { + pFormat->DelFrames(); + pAnchorItem->SetAnchor( pCopySource->Start() ); + SfxItemSetFixed<RES_ANCHOR, RES_ANCHOR> aAnchorSet( pDoc->GetAttrPool() ); + aAnchorSet.Put( std::move(pAnchorItem) ); + pDoc->SetFlyFrameAttr( *pFormat, aAnchorSet ); + } + } + else + { + pFormat = pDoc->MakeFlySection( RndStdIds::FLY_AT_PARA, aPam.GetPoint(), + &aFrameSet, pParentFrameFormat ); + } + if(pFormat) + { + EndListeningAll(); + m_pFrameFormat = pFormat; + StartListening(pFormat->GetNotifier()); + if(!m_sName.isEmpty()) + pDoc->SetFlyName(*pFormat, m_sName); + } + // wake up the SwXTextFrame + static_cast<SwXTextFrame*>(this)->SetDoc( m_bIsDescriptor ? m_pDoc : GetFrameFormat()->GetDoc() ); + } + else if( m_eType == FLYCNTTYPE_GRF) + { + UnoActionContext aActionContext(pDoc); + Graphic aGraphic; + + // Read graphic URL from the descriptor, if it has any. + const ::uno::Any* pGraphicURL; + if (m_pProps->GetProperty(FN_UNO_GRAPHIC_URL, 0, pGraphicURL)) + { + OUString sGraphicURL; + uno::Reference<awt::XBitmap> xBitmap; + if (((*pGraphicURL) >>= sGraphicURL) && !sGraphicURL.isEmpty()) + aGraphic = vcl::graphic::loadFromURL(sGraphicURL); + else if ((*pGraphicURL) >>= xBitmap) + { + uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY); + if (xGraphic.is()) + aGraphic = xGraphic; + } + } + + const ::uno::Any* pGraphicAny; + const bool bHasGraphic = m_pProps->GetProperty(FN_UNO_GRAPHIC, 0, pGraphicAny); + if (bHasGraphic) + { + uno::Reference<graphic::XGraphic> xGraphic; + (*pGraphicAny) >>= xGraphic; + aGraphic = Graphic(xGraphic); + } + + OUString sFilterName; + const uno::Any* pFilterAny; + if (m_pProps->GetProperty(FN_UNO_GRAPHIC_FILTER, 0, pFilterAny)) + { + (*pFilterAny) >>= sFilterName; + } + + pFormat = pDoc->getIDocumentContentOperations().InsertGraphic( + aPam, OUString(), sFilterName, &aGraphic, &aFrameSet, &aGrSet, pParentFrameFormat); + if (pFormat) + { + SwGrfNode *pGrfNd = pDoc->GetNodes()[ pFormat->GetContent().GetContentIdx() + ->GetIndex()+1 ]->GetGrfNode(); + if (pGrfNd) + pGrfNd->SetChgTwipSize( !bSizeFound ); + m_pFrameFormat = pFormat; + EndListeningAll(); + StartListening(m_pFrameFormat->GetNotifier()); + if(!m_sName.isEmpty()) + pDoc->SetFlyName(*pFormat, m_sName); + + } + const ::uno::Any* pSurroundContour; + if (m_pProps->GetProperty(RES_SURROUND, MID_SURROUND_CONTOUR, pSurroundContour)) + setPropertyValue(UNO_NAME_SURROUND_CONTOUR, *pSurroundContour); + const ::uno::Any* pContourOutside; + if (m_pProps->GetProperty(RES_SURROUND, MID_SURROUND_CONTOUROUTSIDE, pContourOutside)) + setPropertyValue(UNO_NAME_CONTOUR_OUTSIDE, *pContourOutside); + const ::uno::Any* pContourPoly; + if (m_pProps->GetProperty(FN_PARAM_CONTOUR_PP, 0, pContourPoly)) + setPropertyValue(UNO_NAME_CONTOUR_POLY_POLYGON, *pContourPoly); + const ::uno::Any* pPixelContour; + if (m_pProps->GetProperty(FN_UNO_IS_PIXEL_CONTOUR, 0, pPixelContour)) + setPropertyValue(UNO_NAME_IS_PIXEL_CONTOUR, *pPixelContour); + const ::uno::Any* pAutoContour; + if (m_pProps->GetProperty(FN_UNO_IS_AUTOMATIC_CONTOUR, 0, pAutoContour)) + setPropertyValue(UNO_NAME_IS_AUTOMATIC_CONTOUR, *pAutoContour); + } + else + { + const ::uno::Any* pCLSID = nullptr; + const ::uno::Any* pStreamName = nullptr; + const ::uno::Any* pEmbeddedObject = nullptr; + if (!m_pProps->GetProperty(FN_UNO_CLSID, 0, pCLSID) + && !m_pProps->GetProperty(FN_UNO_STREAM_NAME, 0, pStreamName) + && !m_pProps->GetProperty(FN_EMBEDDED_OBJECT, 0, pEmbeddedObject)) + { + throw uno::RuntimeException(); + } + if(pCLSID) + { + OUString aCLSID; + SvGlobalName aClassName; + uno::Reference < embed::XEmbeddedObject > xIPObj; + std::unique_ptr < comphelper::EmbeddedObjectContainer > pCnt; + if( (*pCLSID) >>= aCLSID ) + { + if( !aClassName.MakeId( aCLSID ) ) + { + throw lang::IllegalArgumentException("CLSID invalid", nullptr, 0); + } + + pCnt.reset( new comphelper::EmbeddedObjectContainer ); + OUString aName; + + OUString sDocumentBaseURL = pDoc->GetPersist()->getDocumentBaseURL(); + xIPObj = pCnt->CreateEmbeddedObject(aClassName.GetByteSequence(), aName, + &sDocumentBaseURL); + } + if ( xIPObj.is() ) + { + UnoActionContext aAction(pDoc); + pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + + // tdf#99631 set imported VisibleArea settings of embedded XLSX OLE objects + if ( m_nDrawAspect == embed::Aspects::MSOLE_CONTENT + && m_nVisibleAreaWidth && m_nVisibleAreaHeight ) + { + sal_Int64 nAspect = m_nDrawAspect; + MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xIPObj->getMapUnit( nAspect ) ); + Size aSize( OutputDevice::LogicToLogic(Size( m_nVisibleAreaWidth, m_nVisibleAreaHeight), + MapMode(MapUnit::MapTwip), MapMode(aUnit))); + awt::Size aSz; + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xIPObj->setVisualAreaSize(m_nDrawAspect, aSz); + } + + if(!bSizeFound) + { + //TODO/LATER: how do I transport it to the OLENode? + sal_Int64 nAspect = m_nDrawAspect; + + // TODO/LEAN: VisualArea still needs running state + (void)svt::EmbeddedObjectRef::TryRunningState( xIPObj ); + + // set parent to get correct VisArea(in case of object needing parent printer) + uno::Reference < container::XChild > xChild( xIPObj, uno::UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( pDoc->GetDocShell()->GetModel() ); + + //The Size should be suggested by the OLE server if not manually set + MapUnit aRefMap = VCLUnoHelper::UnoEmbed2VCLMapUnit( xIPObj->getMapUnit( nAspect ) ); + awt::Size aSize; + try + { + aSize = xIPObj->getVisualAreaSize( nAspect ); + } + catch ( embed::NoVisualAreaSizeException& ) + { + // the default size will be set later + } + + Size aSz( aSize.Width, aSize.Height ); + if ( !aSz.Width() || !aSz.Height() ) + { + aSz.setWidth(5000); + aSz.setHeight(5000); + aSz = OutputDevice::LogicToLogic(aSz, + MapMode(MapUnit::Map100thMM), MapMode(aRefMap)); + } + MapMode aMyMap( MapUnit::MapTwip ); + aSz = OutputDevice::LogicToLogic(aSz, MapMode(aRefMap), aMyMap); + SwFormatFrameSize aFrameSz; + aFrameSz.SetSize(aSz); + aFrameSet.Put(aFrameSz); + } + SwFlyFrameFormat* pFormat2 = nullptr; + + ::svt::EmbeddedObjectRef xObjRef( xIPObj, m_nDrawAspect); + pFormat2 = pDoc->getIDocumentContentOperations().InsertEmbObject( + aPam, xObjRef, &aFrameSet ); + + // store main document name to show in the title bar + uno::Reference< frame::XTitle > xModelTitle( pDoc->GetDocShell()->GetModel(), css::uno::UNO_QUERY ); + if( xModelTitle.is() ) + xIPObj->setContainerName( xModelTitle->getTitle() ); + + assert(pFormat2 && "Doc->Insert(notxt) failed."); + + pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); + m_pFrameFormat = pFormat2; + EndListeningAll(); + StartListening(m_pFrameFormat->GetNotifier()); + if(!m_sName.isEmpty()) + pDoc->SetFlyName(*pFormat2, m_sName); + } + } + else if( pStreamName ) + { + OUString sStreamName; + (*pStreamName) >>= sStreamName; + pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + + SwFlyFrameFormat* pFrameFormat = pDoc->getIDocumentContentOperations().InsertOLE( + aPam, sStreamName, m_nDrawAspect, &aFrameSet, nullptr); + + // store main document name to show in the title bar + SwOLENode* pNd = nullptr; + const SwNodeIndex* pIdx = pFrameFormat->GetContent().GetContentIdx(); + if( pIdx ) + { + SwNodeIndex aIdx( *pIdx, 1 ); + SwNoTextNode* pNoText = aIdx.GetNode().GetNoTextNode(); + pNd = pNoText->GetOLENode(); + } + if( pNd ) + { + uno::Reference < embed::XEmbeddedObject > xObj = pNd->GetOLEObj().GetOleRef(); + if( xObj.is() ) + { + uno::Reference< frame::XTitle > xModelTitle( pDoc->GetDocShell()->GetModel(), css::uno::UNO_QUERY ); + if( xModelTitle.is() ) + xObj->setContainerName( xModelTitle->getTitle() ); + } + } + + pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); + m_pFrameFormat = pFrameFormat; + EndListeningAll(); + StartListening(m_pFrameFormat->GetNotifier()); + if(!m_sName.isEmpty()) + pDoc->SetFlyName(*pFrameFormat, m_sName); + } + else if (pEmbeddedObject) + { + uno::Reference< embed::XEmbeddedObject > obj; + (*pEmbeddedObject) >>= obj; + svt::EmbeddedObjectRef xObj; + xObj.Assign( obj, embed::Aspects::MSOLE_CONTENT ); + + pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + + // Do not call here container::XChild(obj)->setParent() and + // pDoc->GetPersist()->GetEmbeddedObjectContainer().InsertEmbeddedObject: + // they are called indirectly by pDoc->getIDocumentContentOperations().InsertEmbObject + // below. Calling them twice will add the same object twice to EmbeddedObjectContainer's + // pImpl->maNameToObjectMap, and then it will misbehave in + // EmbeddedObjectContainer::StoreAsChildren and SfxObjectShell::SaveCompletedChildren. + + SwFlyFrameFormat* pFrameFormat + = pDoc->getIDocumentContentOperations().InsertEmbObject(aPam, xObj, &aFrameSet); + pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); + m_pFrameFormat = pFrameFormat; + EndListeningAll(); + StartListening(m_pFrameFormat->GetNotifier()); + if(!m_sName.isEmpty()) + pDoc->SetFlyName(*pFrameFormat, m_sName); + } + } + if( pFormat && pDoc->getIDocumentDrawModelAccess().GetDrawModel() ) + GetOrCreateSdrObject(*pFormat); + const ::uno::Any* pOrder; + if (m_pProps->GetProperty(FN_UNO_Z_ORDER, 0, pOrder)) + setPropertyValue(UNO_NAME_Z_ORDER, *pOrder); + const ::uno::Any* pReplacement; + if (m_pProps->GetProperty(FN_UNO_REPLACEMENT_GRAPHIC, 0, pReplacement)) + setPropertyValue(UNO_NAME_GRAPHIC, *pReplacement); + // new attribute Title + const ::uno::Any* pTitle; + if (m_pProps->GetProperty(FN_UNO_TITLE, 0, pTitle)) + { + setPropertyValue(UNO_NAME_TITLE, *pTitle); + } + // new attribute Description + const ::uno::Any* pDescription; + if (m_pProps->GetProperty(FN_UNO_DESCRIPTION, 0, pDescription)) + { + setPropertyValue(UNO_NAME_DESCRIPTION, *pDescription); + } + + // For grabbag + const uno::Any* pFrameIntropgrabbagItem; + if (m_pProps->GetProperty(RES_FRMATR_GRABBAG, 0, pFrameIntropgrabbagItem)) + { + setPropertyValue(UNO_NAME_FRAME_INTEROP_GRAB_BAG, *pFrameIntropgrabbagItem); + } + + // reset the flag and delete Descriptor pointer + ResetDescriptor(); +} + +void SwXFrame::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard g; + + if(IsDescriptor()) + { + attachToRange(xTextRange); + return; + } + + SwFrameFormat* pFormat = GetFrameFormat(); + if( !pFormat ) + return; + + SwDoc* pDoc = pFormat->GetDoc(); + SwUnoInternalPaM aIntPam(*pDoc); + if (!::sw::XTextRangeToSwPaM(aIntPam, xTextRange)) + throw lang::IllegalArgumentException(); + + SfxItemSetFixed<RES_ANCHOR, RES_ANCHOR> aSet( pDoc->GetAttrPool() ); + aSet.SetParent(&pFormat->GetAttrSet()); + SwFormatAnchor aAnchor = aSet.Get(RES_ANCHOR); + + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + throw lang::IllegalArgumentException( + "SwXFrame::attach(): re-anchoring AS_CHAR not supported", + *this, 0); + } + + aAnchor.SetAnchor( aIntPam.Start() ); + aSet.Put(aAnchor); + pDoc->SetFlyFrameAttr( *pFormat, aSet ); +} + +awt::Point SwXFrame::getPosition() +{ + throw uno::RuntimeException("position cannot be determined with this method"); +} + +void SwXFrame::setPosition(const awt::Point& /*aPosition*/) +{ + throw uno::RuntimeException("position cannot be changed with this method"); +} + +awt::Size SwXFrame::getSize() +{ + const ::uno::Any aVal = getPropertyValue("Size"); + awt::Size const * pRet = o3tl::doAccess<awt::Size>(aVal); + return *pRet; +} + +void SwXFrame::setSize(const awt::Size& aSize) +{ + const ::uno::Any aVal(&aSize, ::cppu::UnoType<awt::Size>::get()); + setPropertyValue("Size", aVal); +} + +OUString SwXFrame::getShapeType() +{ + return "FrameShape"; +} + +SwXTextFrame::SwXTextFrame( SwDoc *_pDoc ) : + SwXTextFrameBaseClass(FLYCNTTYPE_FRM, aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_FRAME), _pDoc ), + SwXText(nullptr, CursorType::Frame) +{ +} + +SwXTextFrame::SwXTextFrame(SwFrameFormat& rFormat) : + SwXTextFrameBaseClass(rFormat, FLYCNTTYPE_FRM, aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_FRAME)), + SwXText(rFormat.GetDoc(), CursorType::Frame) +{ + +} + +SwXTextFrame::~SwXTextFrame() +{ +} + +rtl::Reference<SwXTextFrame> +SwXTextFrame::CreateXTextFrame(SwDoc & rDoc, SwFrameFormat *const pFrameFormat) +{ + return CreateXFrame<SwXTextFrame>(rDoc, pFrameFormat); +} + +void SAL_CALL SwXTextFrame::acquire( )noexcept +{ + SwXFrame::acquire(); +} + +void SAL_CALL SwXTextFrame::release( )noexcept +{ + SwXFrame::release(); +} + +::uno::Any SAL_CALL SwXTextFrame::queryInterface( const uno::Type& aType ) +{ + ::uno::Any aRet = SwXFrame::queryInterface(aType); + if(aRet.getValueType() == cppu::UnoType<void>::get()) + aRet = SwXText::queryInterface(aType); + if(aRet.getValueType() == cppu::UnoType<void>::get()) + aRet = SwXTextFrameBaseClass::queryInterface(aType); + return aRet; +} + +uno::Sequence< uno::Type > SAL_CALL SwXTextFrame::getTypes( ) +{ + return comphelper::concatSequences( + SwXTextFrameBaseClass::getTypes(), + SwXFrame::getTypes(), + SwXText::getTypes() + ); +} + +uno::Sequence< sal_Int8 > SAL_CALL SwXTextFrame::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Reference< text::XText > SwXTextFrame::getText() +{ + return this; +} + +const SwStartNode *SwXTextFrame::GetStartNode() const +{ + const SwStartNode *pSttNd = nullptr; + + const SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const SwFormatContent& rFlyContent = pFormat->GetContent(); + if( rFlyContent.GetContentIdx() ) + pSttNd = rFlyContent.GetContentIdx()->GetNode().GetStartNode(); + } + + return pSttNd; +} + +rtl::Reference<SwXTextCursor> SwXTextFrame::createXTextCursor() +{ + SwFrameFormat* pFormat = GetFrameFormat(); + if(!pFormat) + throw uno::RuntimeException(); + + //save current start node to be able to check if there is content after the table - + //otherwise the cursor would be in the body text! + const SwNode& rNode = pFormat->GetContent().GetContentIdx()->GetNode(); + const SwStartNode* pOwnStartNode = rNode.FindSttNodeByType(SwFlyStartNode); + + SwPaM aPam(rNode); + aPam.Move(fnMoveForward, GoInNode); + SwTableNode* pTableNode = aPam.GetPointNode().FindTableNode(); + while( pTableNode ) + { + aPam.GetPoint()->Assign( *pTableNode->EndOfSectionNode() ); + SwContentNode* pCont = GetDoc()->GetNodes().GoNext(aPam.GetPoint()); + pTableNode = pCont->FindTableNode(); + } + + const SwStartNode* pNewStartNode = + aPam.GetPointNode().FindSttNodeByType(SwFlyStartNode); + if(!pNewStartNode || pNewStartNode != pOwnStartNode) + { + throw uno::RuntimeException("no text available"); + } + + return new SwXTextCursor( + *pFormat->GetDoc(), this, CursorType::Frame, *aPam.GetPoint()); +} + +rtl::Reference< SwXTextCursor > SwXTextFrame::createXTextCursorByRange(const uno::Reference< text::XTextRange > & aTextPosition) +{ + SwFrameFormat* pFormat = GetFrameFormat(); + if (!pFormat) + throw uno::RuntimeException(); + SwUnoInternalPaM aPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(aPam, aTextPosition)) + throw uno::RuntimeException(); + + rtl::Reference< SwXTextCursor > aRef; + SwNode& rNode = pFormat->GetContent().GetContentIdx()->GetNode(); + if(aPam.GetPointNode().FindFlyStartNode() == rNode.FindFlyStartNode()) + { + aRef = new SwXTextCursor(*pFormat->GetDoc(), this, CursorType::Frame, + *aPam.GetPoint(), aPam.GetMark()); + } + + return aRef; +} + +uno::Reference< container::XEnumeration > SwXTextFrame::createEnumeration() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!pFormat) + return nullptr; + SwPosition aPos(pFormat->GetContent().GetContentIdx()->GetNode()); + auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); + pUnoCursor->Move(fnMoveForward, GoInNode); + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Frame); +} + +uno::Type SwXTextFrame::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SwXTextFrame::hasElements() +{ + return true; +} + +void SwXTextFrame::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SwXFrame::attach(xTextRange); +} + +uno::Reference< text::XTextRange > SwXTextFrame::getAnchor() +{ + SolarMutexGuard aGuard; + return SwXFrame::getAnchor(); +} + +void SwXTextFrame::dispose() +{ + SolarMutexGuard aGuard; + SwXFrame::dispose(); +} + +void SwXTextFrame::addEventListener(const uno::Reference< lang::XEventListener > & aListener) +{ + SwXFrame::addEventListener(aListener); +} + +void SwXTextFrame::removeEventListener(const uno::Reference< lang::XEventListener > & aListener) +{ + SwXFrame::removeEventListener(aListener); +} + +OUString SwXTextFrame::getImplementationName() +{ + return "SwXTextFrame"; +} + +sal_Bool SwXTextFrame::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextFrame::getSupportedServiceNames() +{ + uno::Sequence < OUString > aRet = SwXFrame::getSupportedServiceNames(); + aRet.realloc(aRet.getLength() + 2); + OUString* pArray = aRet.getArray(); + pArray[aRet.getLength() - 2] = "com.sun.star.text.TextFrame"; + pArray[aRet.getLength() - 1] = "com.sun.star.text.Text"; + return aRet; +} + +uno::Reference<container::XNameReplace > SAL_CALL SwXTextFrame::getEvents() +{ + return new SwFrameEventDescriptor( *this ); +} + +::uno::Any SwXTextFrame::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + ::uno::Any aRet; + if(rPropertyName == UNO_NAME_START_REDLINE|| + rPropertyName == UNO_NAME_END_REDLINE) + { + //redline can only be returned if it's a living object + if(!IsDescriptor()) + aRet = SwXText::getPropertyValue(rPropertyName); + } + else + aRet = SwXFrame::getPropertyValue(rPropertyName); + return aRet; +} + +SwXTextGraphicObject::SwXTextGraphicObject( SwDoc *pDoc ) + : SwXTextGraphicObjectBaseClass(FLYCNTTYPE_GRF, + aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_GRAPHIC), pDoc) +{ +} + +SwXTextGraphicObject::SwXTextGraphicObject(SwFrameFormat& rFormat) + : SwXTextGraphicObjectBaseClass(rFormat, FLYCNTTYPE_GRF, + aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_GRAPHIC)) +{ +} + +SwXTextGraphicObject::~SwXTextGraphicObject() +{ +} + +rtl::Reference<SwXTextGraphicObject> +SwXTextGraphicObject::CreateXTextGraphicObject(SwDoc & rDoc, SwFrameFormat *const pFrameFormat) +{ + return CreateXFrame<SwXTextGraphicObject>(rDoc, pFrameFormat); +} + +OUString SwXTextGraphicObject::getImplementationName() +{ + return "SwXTextGraphicObject"; +} + +sal_Bool SwXTextGraphicObject::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextGraphicObject::getSupportedServiceNames() +{ + uno::Sequence < OUString > aRet = SwXFrame::getSupportedServiceNames(); + aRet.realloc(aRet.getLength() + 1); + OUString* pArray = aRet.getArray(); + pArray[aRet.getLength() - 1] = "com.sun.star.text.TextGraphicObject"; + return aRet; +} + +uno::Reference<container::XNameReplace> SAL_CALL + SwXTextGraphicObject::getEvents() +{ + return new SwFrameEventDescriptor( *this ); +} + +SwXTextEmbeddedObject::SwXTextEmbeddedObject( SwDoc *pDoc ) + : SwXTextEmbeddedObjectBaseClass(FLYCNTTYPE_OLE, + aSwMapProvider.GetPropertySet(PROPERTY_MAP_EMBEDDED_OBJECT), pDoc) +{ +} + +SwXTextEmbeddedObject::SwXTextEmbeddedObject(SwFrameFormat& rFormat) + : SwXTextEmbeddedObjectBaseClass(rFormat, FLYCNTTYPE_OLE, + aSwMapProvider.GetPropertySet(PROPERTY_MAP_EMBEDDED_OBJECT)) +{ +} + +SwXTextEmbeddedObject::~SwXTextEmbeddedObject() +{ +} + +rtl::Reference<SwXTextEmbeddedObject> +SwXTextEmbeddedObject::CreateXTextEmbeddedObject(SwDoc & rDoc, SwFrameFormat *const pFrameFormat) +{ + return CreateXFrame<SwXTextEmbeddedObject>(rDoc, pFrameFormat); +} + +uno::Reference< lang::XComponent > SwXTextEmbeddedObject::getEmbeddedObject() +{ + uno::Reference<embed::XEmbeddedObject> xObj(getExtendedControlOverEmbeddedObject()); + return xObj.is() ? uno::Reference<lang::XComponent>(xObj->getComponent(), uno::UNO_QUERY) : nullptr; +} + +uno::Reference< embed::XEmbeddedObject > SAL_CALL SwXTextEmbeddedObject::getExtendedControlOverEmbeddedObject() +{ + uno::Reference< embed::XEmbeddedObject > xResult; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + SwDoc* pDoc = pFormat->GetDoc(); + const SwFormatContent* pCnt = &pFormat->GetContent(); + OSL_ENSURE( pCnt->GetContentIdx() && + pDoc->GetNodes()[ pCnt->GetContentIdx()-> + GetIndex() + 1 ]->GetOLENode(), "no OLE-Node?"); + + SwOLENode* pOleNode = pDoc->GetNodes()[ pCnt->GetContentIdx() + ->GetIndex() + 1 ]->GetOLENode(); + xResult = pOleNode->GetOLEObj().GetOleRef(); + if ( svt::EmbeddedObjectRef::TryRunningState( xResult ) ) + { + // TODO/LATER: the listener registered after client creation should be able to handle scaling, after that the client is not necessary here + if ( pDoc->GetDocShell() ) + pDoc->GetDocShell()->GetIPClient( svt::EmbeddedObjectRef( xResult, embed::Aspects::MSOLE_CONTENT ) ); + + uno::Reference < lang::XComponent > xComp( xResult->getComponent(), uno::UNO_QUERY ); + uno::Reference< util::XModifyBroadcaster > xBrdcst( xComp, uno::UNO_QUERY); + uno::Reference< frame::XModel > xModel( xComp, uno::UNO_QUERY); + if(xBrdcst.is() && xModel.is() && !m_xOLEListener.is()) + { + m_xOLEListener = new SwXOLEListener(*pFormat, xModel); + xBrdcst->addModifyListener( m_xOLEListener ); + } + } + } + return xResult; +} + +sal_Int64 SAL_CALL SwXTextEmbeddedObject::getAspect() +{ + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + SwDoc* pDoc = pFormat->GetDoc(); + const SwFormatContent* pCnt = &pFormat->GetContent(); + OSL_ENSURE( pCnt->GetContentIdx() && + pDoc->GetNodes()[ pCnt->GetContentIdx()-> + GetIndex() + 1 ]->GetOLENode(), "no OLE-Node?"); + + return pDoc->GetNodes()[ pCnt->GetContentIdx()->GetIndex() + 1 ]->GetOLENode()->GetAspect(); + } + + return embed::Aspects::MSOLE_CONTENT; // return the default value +} + +void SAL_CALL SwXTextEmbeddedObject::setAspect( sal_Int64 nAspect ) +{ + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + SwDoc* pDoc = pFormat->GetDoc(); + const SwFormatContent* pCnt = &pFormat->GetContent(); + OSL_ENSURE( pCnt->GetContentIdx() && + pDoc->GetNodes()[ pCnt->GetContentIdx()-> + GetIndex() + 1 ]->GetOLENode(), "no OLE-Node?"); + + pDoc->GetNodes()[ pCnt->GetContentIdx()->GetIndex() + 1 ]->GetOLENode()->SetAspect( nAspect ); + } +} + +uno::Reference< graphic::XGraphic > SAL_CALL SwXTextEmbeddedObject::getReplacementGraphic() +{ + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + SwDoc* pDoc = pFormat->GetDoc(); + const SwFormatContent* pCnt = &pFormat->GetContent(); + OSL_ENSURE( pCnt->GetContentIdx() && + pDoc->GetNodes()[ pCnt->GetContentIdx()-> + GetIndex() + 1 ]->GetOLENode(), "no OLE-Node?"); + + const Graphic* pGraphic = pDoc->GetNodes()[ pCnt->GetContentIdx()->GetIndex() + 1 ]->GetOLENode()->GetGraphic(); + if ( pGraphic ) + return pGraphic->GetXGraphic(); + } + + return uno::Reference< graphic::XGraphic >(); +} + +OUString SwXTextEmbeddedObject::getImplementationName() +{ + return "SwXTextEmbeddedObject"; +} + +sal_Bool SwXTextEmbeddedObject::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextEmbeddedObject::getSupportedServiceNames() +{ + uno::Sequence < OUString > aRet = SwXFrame::getSupportedServiceNames(); + aRet.realloc(aRet.getLength() + 1); + OUString* pArray = aRet.getArray(); + pArray[aRet.getLength() - 1] = "com.sun.star.text.TextEmbeddedObject"; + return aRet; +} + +uno::Reference<container::XNameReplace> SAL_CALL + SwXTextEmbeddedObject::getEvents() +{ + return new SwFrameEventDescriptor( *this ); +} + +namespace +{ + SwOLENode* lcl_GetOLENode(const SwFormat* pFormat) + { + if(!pFormat) + return nullptr; + const SwNodeIndex* pIdx(pFormat->GetContent().GetContentIdx()); + if(!pIdx) + return nullptr; + const SwNodeIndex aIdx(*pIdx, 1); + return aIdx.GetNode().GetNoTextNode()->GetOLENode(); + } +} + +SwXOLEListener::SwXOLEListener( SwFormat& rOLEFormat, uno::Reference< XModel > xOLE) + : m_pOLEFormat(&rOLEFormat) + , m_xOLEModel(std::move(xOLE)) +{ + StartListening(m_pOLEFormat->GetNotifier()); +} + +SwXOLEListener::~SwXOLEListener() +{} + +void SwXOLEListener::modified( const lang::EventObject& /*rEvent*/ ) +{ + SolarMutexGuard aGuard; + const auto pNd = lcl_GetOLENode(m_pOLEFormat); + if(!pNd) + throw uno::RuntimeException(); + const auto xIP = pNd->GetOLEObj().GetOleRef(); + if(xIP.is()) + { + sal_Int32 nState = xIP->getCurrentState(); + if(nState == embed::EmbedStates::INPLACE_ACTIVE || nState == embed::EmbedStates::UI_ACTIVE) + // if the OLE-Node is UI-Active do nothing + return; + } + pNd->SetOLESizeInvalid(true); + pNd->GetDoc().SetOLEObjModified(); +} + +void SwXOLEListener::disposing( const lang::EventObject& rEvent ) +{ + SolarMutexGuard aGuard; + uno::Reference<util::XModifyListener> xListener( this ); + uno::Reference<frame::XModel> xModel(rEvent.Source, uno::UNO_QUERY); + uno::Reference<util::XModifyBroadcaster> xBrdcst(xModel, uno::UNO_QUERY); + if(!xBrdcst.is()) + return; + try + { + xBrdcst->removeModifyListener(xListener); + } + catch(uno::Exception const &) + { + OSL_FAIL("OLE Listener couldn't be removed"); + } +} + +void SwXOLEListener::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_xOLEModel = nullptr; + m_pOLEFormat = nullptr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoftn.cxx b/sw/source/core/unocore/unoftn.cxx new file mode 100644 index 0000000000..1a73e2e617 --- /dev/null +++ b/sw/source/core/unocore/unoftn.cxx @@ -0,0 +1,538 @@ +/* -*- 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 <sal/config.h> + +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svl/listener.hxx> +#include <mutex> + +#include <unofootnote.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unoparagraph.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <doc.hxx> +#include <ftnidx.hxx> +#include <fmtftn.hxx> +#include <txtftn.hxx> +#include <ndtxt.hxx> +#include <unocrsr.hxx> +#include <svl/itemprop.hxx> + +using namespace ::com::sun::star; + +namespace { + +uno::Sequence< OUString > +GetSupportedServiceNamesImpl( + size_t const nServices, char const*const pServices[]) +{ + uno::Sequence< OUString > ret(static_cast<sal_Int32>(nServices)); + + std::transform(pServices, pServices + nServices, ret.getArray(), + [](const char* pService) -> OUString { return OUString::createFromAscii(pService); }); + + return ret; +} + +} + +class SwXFootnote::Impl + : public SvtListener +{ +public: + + SwXFootnote& m_rThis; + unotools::WeakReference<SwXFootnote> m_wThis; + const bool m_bIsEndnote; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + bool m_bIsDescriptor; + SwFormatFootnote* m_pFormatFootnote; + OUString m_sLabel; + + Impl(SwXFootnote& rThis, + SwFormatFootnote* const pFootnote, + const bool bIsEndnote) + : m_rThis(rThis) + , m_bIsEndnote(bIsEndnote) + , m_bIsDescriptor(nullptr == pFootnote) + , m_pFormatFootnote(pFootnote) + { + m_pFormatFootnote && StartListening(m_pFormatFootnote->GetNotifier()); + } + + const SwFormatFootnote* GetFootnoteFormat() const { + return m_rThis.GetDoc() ? m_pFormatFootnote : nullptr; + } + + SwFormatFootnote const& GetFootnoteFormatOrThrow() const { + SwFormatFootnote const*const pFootnote( GetFootnoteFormat() ); + if (!pFootnote) { + throw uno::RuntimeException("SwXFootnote: disposed or invalid", nullptr); + } + return *pFootnote; + } + + void Invalidate(); +protected: + void Notify(const SfxHint& rHint) override; + +}; + +void SwXFootnote::Impl::Invalidate() +{ + EndListeningAll(); + m_pFormatFootnote = nullptr; + m_rThis.SetDoc(nullptr); + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +void SwXFootnote::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + Invalidate(); +} + +SwXFootnote::SwXFootnote(const bool bEndnote) + : SwXText(nullptr, CursorType::Footnote) + , m_pImpl( new SwXFootnote::Impl(*this, nullptr, bEndnote) ) +{ +} + +SwXFootnote::SwXFootnote(SwDoc & rDoc, SwFormatFootnote & rFormat) + : SwXText(& rDoc, CursorType::Footnote) + , m_pImpl( new SwXFootnote::Impl(*this, &rFormat, rFormat.IsEndNote()) ) +{ +} + +SwXFootnote::~SwXFootnote() +{ +} + +rtl::Reference<SwXFootnote> +SwXFootnote::CreateXFootnote(SwDoc & rDoc, SwFormatFootnote *const pFootnoteFormat, + bool const isEndnote) +{ + // i#105557: do not iterate over the registered clients: race condition + rtl::Reference<SwXFootnote> xNote; + if (pFootnoteFormat) + { + xNote = pFootnoteFormat->GetXFootnote(); + } + if (!xNote.is()) + { + xNote = pFootnoteFormat + ? new SwXFootnote(rDoc, *pFootnoteFormat) + : new SwXFootnote(isEndnote); + if (pFootnoteFormat) + { + pFootnoteFormat->SetXFootnote(xNote); + } + // need a permanent Reference to initialize m_wThis + xNote->m_pImpl->m_wThis = xNote.get(); + } + return xNote; +} + +OUString SAL_CALL +SwXFootnote::getImplementationName() +{ + return "SwXFootnote"; +} + +char const*const g_ServicesFootnote[] = +{ + "com.sun.star.text.TextContent", + "com.sun.star.text.Footnote", + "com.sun.star.text.Text", + "com.sun.star.text.Endnote", // NB: only supported for endnotes! +}; + +const size_t g_nServicesEndnote( SAL_N_ELEMENTS(g_ServicesFootnote) ); + +const size_t g_nServicesFootnote( g_nServicesEndnote - 1 ); // NB: omit! + +sal_Bool SAL_CALL SwXFootnote::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXFootnote::getSupportedServiceNames() +{ + SolarMutexGuard g; + return GetSupportedServiceNamesImpl( + (m_pImpl->m_bIsEndnote) ? g_nServicesEndnote : g_nServicesFootnote, + g_ServicesFootnote); +} + +uno::Sequence< uno::Type > SAL_CALL +SwXFootnote::getTypes() +{ + const uno::Sequence< uno::Type > aTypes = SwXFootnote_Base::getTypes(); + const uno::Sequence< uno::Type > aTextTypes = SwXText::getTypes(); + return ::comphelper::concatSequences(aTypes, aTextTypes); +} + +uno::Sequence< sal_Int8 > SAL_CALL +SwXFootnote::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Any SAL_CALL +SwXFootnote::queryInterface(const uno::Type& rType) +{ + const uno::Any ret = SwXFootnote_Base::queryInterface(rType); + return (ret.getValueType() == cppu::UnoType<void>::get()) + ? SwXText::queryInterface(rType) + : ret; +} + +OUString SAL_CALL SwXFootnote::getLabel() +{ + SolarMutexGuard aGuard; + + OUString sRet; + SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat(); + if(pFormat) + { + sRet = pFormat->GetNumStr(); + } + else if (m_pImpl->m_bIsDescriptor) + { + sRet = m_pImpl->m_sLabel; + } + else + { + throw uno::RuntimeException(); + } + return sRet; +} + +void SAL_CALL +SwXFootnote::setLabel(const OUString& aLabel) +{ + SolarMutexGuard aGuard; + OUString newLabel(aLabel); + //new line must not occur as footnote label + if(newLabel.indexOf('\n') >=0 ) + { + newLabel = newLabel.replace('\n', ' '); + } + SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat(); + if(pFormat) + { + const SwTextFootnote* pTextFootnote = pFormat->GetTextFootnote(); + OSL_ENSURE(pTextFootnote, "No TextNode?"); + SwTextNode& rTextNode = const_cast<SwTextNode&>(pTextFootnote->GetTextNode()); + + SwPaM aPam(rTextNode, pTextFootnote->GetStart()); + GetDoc()->SetCurFootnote(aPam, newLabel, pFormat->IsEndNote()); + } + else if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_sLabel = newLabel; + } + else + { + throw uno::RuntimeException(); + } +} + +void SAL_CALL +SwXFootnote::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + SwXTextRange *const pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + SwDoc *const pNewDoc = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pNewDoc) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pNewDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + + UnoActionContext aCont(pNewDoc); + pNewDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); + aPam.DeleteMark(); + SwFormatFootnote aFootNote(m_pImpl->m_bIsEndnote); + if (!m_pImpl->m_sLabel.isEmpty()) + { + aFootNote.SetNumStr(m_pImpl->m_sLabel); + } + + SwXTextCursor const*const pTextCursor( + dynamic_cast<SwXTextCursor*>(pCursor)); + const bool bForceExpandHints( pTextCursor && pTextCursor->IsAtEndOfMeta() ); + const SetAttrMode nInsertFlags = bForceExpandHints + ? SetAttrMode::FORCEHINTEXPAND + : SetAttrMode::DEFAULT; + + pNewDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aFootNote, nInsertFlags); + + SwTextFootnote *const pTextAttr = static_cast<SwTextFootnote*>( + aPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt( + aPam.GetPoint()->GetContentIndex()-1, RES_TXTATR_FTN )); + + if (pTextAttr) + { + m_pImpl->EndListeningAll(); + SwFormatFootnote* pFootnote = const_cast<SwFormatFootnote*>(&pTextAttr->GetFootnote()); + m_pImpl->m_pFormatFootnote = pFootnote; + m_pImpl->StartListening(pFootnote->GetNotifier()); + // force creation of sequence id - is used for references + if (pNewDoc->IsInReading()) + { + pTextAttr->SetSeqNo(pNewDoc->GetFootnoteIdxs().size()); + } + else + { + pTextAttr->SetSeqRefNo(); + } + } + m_pImpl->m_bIsDescriptor = false; + SetDoc(pNewDoc); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXFootnote::getAnchor() +{ + SolarMutexGuard aGuard; + return m_pImpl->GetFootnoteFormatOrThrow().getAnchor(*GetDoc()); +} + +void SAL_CALL SwXFootnote::dispose() +{ + SolarMutexGuard aGuard; + + SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() ); + + SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote(); + OSL_ENSURE(pTextFootnote, "no TextNode?"); + SwTextNode& rTextNode = const_cast<SwTextNode&>(pTextFootnote->GetTextNode()); + const sal_Int32 nPos = pTextFootnote->GetStart(); + SwPaM aPam(rTextNode, nPos, rTextNode, nPos+1); + GetDoc()->getIDocumentContentOperations().DeleteAndJoin( aPam ); +} + +void SAL_CALL +SwXFootnote::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL +SwXFootnote::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +const SwStartNode *SwXFootnote::GetStartNode() const +{ + SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat(); + if(pFormat) + { + const SwTextFootnote* pTextFootnote = pFormat->GetTextFootnote(); + if( pTextFootnote ) + { + return pTextFootnote->GetStartNode()->GetNode().GetStartNode(); + } + } + return nullptr; +} + +rtl::Reference< SwXTextCursor > +SwXFootnote::createXTextCursor() +{ + SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() ); + + SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote(); + SwPosition aPos( *pTextFootnote->GetStartNode() ); + rtl::Reference<SwXTextCursor> pXCursor = + new SwXTextCursor(*GetDoc(), this, CursorType::Footnote, aPos); + auto& rUnoCursor(pXCursor->GetCursor()); + rUnoCursor.Move(fnMoveForward, GoInNode); + return pXCursor; +} + +rtl::Reference< SwXTextCursor > +SwXFootnote::createXTextCursorByRange( + const uno::Reference< text::XTextRange > & xTextPosition) +{ + SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() ); + + SwUnoInternalPaM aPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(aPam, xTextPosition)) + { + throw uno::RuntimeException(); + } + + SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote(); + SwNode const*const pFootnoteStartNode = &pTextFootnote->GetStartNode()->GetNode(); + + const SwNode* pStart = aPam.GetPointNode().FindFootnoteStartNode(); + if (pStart != pFootnoteStartNode) + { + throw uno::RuntimeException(); + } + + const rtl::Reference< SwXTextCursor > xRet = + new SwXTextCursor(*GetDoc(), this, CursorType::Footnote, + *aPam.GetPoint(), aPam.GetMark()); + return xRet; +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXFootnote::createEnumeration() +{ + SolarMutexGuard aGuard; + + SwFormatFootnote const& rFormat( m_pImpl->GetFootnoteFormatOrThrow() ); + + SwTextFootnote const*const pTextFootnote = rFormat.GetTextFootnote(); + SwPosition aPos( *pTextFootnote->GetStartNode() ); + auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); + pUnoCursor->Move(fnMoveForward, GoInNode); + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Footnote); +} + +uno::Type SAL_CALL SwXFootnote::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXFootnote::hasElements() +{ + return true; +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXFootnote::getPropertySetInfo() +{ + SolarMutexGuard g; + static uno::Reference< beans::XPropertySetInfo > xRet = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_FOOTNOTE) + ->getPropertySetInfo(); + return xRet; +} + +void SAL_CALL +SwXFootnote::setPropertyValue(const OUString&, const uno::Any&) +{ + //no values to be set + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL +SwXFootnote::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + if (rPropertyName == UNO_NAME_START_REDLINE || + rPropertyName == UNO_NAME_END_REDLINE) + { + //redline can only be returned if it's a living object + if (!m_pImpl->m_bIsDescriptor) + { + aRet = SwXText::getPropertyValue(rPropertyName); + } + } + else if (rPropertyName == UNO_NAME_REFERENCE_ID) + { + SwFormatFootnote const*const pFormat = m_pImpl->GetFootnoteFormat(); + if (pFormat) + { + SwTextFootnote const*const pTextFootnote = pFormat->GetTextFootnote(); + OSL_ENSURE(pTextFootnote, "no TextNode?"); + aRet <<= static_cast<sal_Int16>(pTextFootnote->GetSeqRefNo()); + } + } + else + { + throw beans::UnknownPropertyException(rPropertyName); + } + } + return aRet; +} + +void SAL_CALL +SwXFootnote::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXFootnote::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFootnote::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXFootnote::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFootnote::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXFootnote::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFootnote::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXFootnote::removeVetoableChangeListener(): not implemented"); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoidx.cxx b/sw/source/core/unocore/unoidx.cxx new file mode 100644 index 0000000000..3617c22b8d --- /dev/null +++ b/sw/source/core/unocore/unoidx.cxx @@ -0,0 +1,3086 @@ +/* -*- 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 <memory> +#include <unoidx.hxx> +#include <unoidxcoll.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/text/ChapterFormat.hpp> +#include <com/sun/star/text/ReferenceFieldPart.hpp> +#include <com/sun/star/text/BibliographyDataField.hpp> +#include <com/sun/star/text/XTextDocument.hpp> + +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <tools/UnitConversion.hxx> +#include <vcl/svapp.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <editeng/memberids.h> +#include <swtypes.hxx> +#include <shellres.hxx> +#include <viewsh.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <docary.hxx> +#include <fmtcntnt.hxx> +#include <unomap.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unosection.hxx> +#include <doctxm.hxx> +#include <txttxmrk.hxx> +#include <ndtxt.hxx> +#include <docsh.hxx> +#include <chpfld.hxx> +#include <editsh.hxx> +#include <SwStyleNameMapper.hxx> +#include <strings.hrc> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <cppuhelper/implbase.hxx> +#include <svl/itemprop.hxx> +#include <svl/listener.hxx> +#include <mutex> + +using namespace ::com::sun::star; + +/// @throws lang::IllegalArgumentException +template<typename T> +static T +lcl_AnyToType(uno::Any const& rVal) +{ + T aRet{}; + if(!(rVal >>= aRet)) + { + throw lang::IllegalArgumentException(); + } + return aRet; +} + +/// @throws lang::IllegalArgumentException +template<typename T> +static void lcl_AnyToBitMask(uno::Any const& rValue, + T & rBitMask, const T nBit) +{ + rBitMask = lcl_AnyToType<bool>(rValue) + ? (rBitMask | nBit) + : (rBitMask & ~nBit); +} + +template<typename T> +static void lcl_BitMaskToAny(uno::Any & o_rValue, + const T nBitMask, const T nBit) +{ + const bool bRet(nBitMask & nBit); + o_rValue <<= bRet; +} + +static void +lcl_ReAssignTOXType(SwDoc& rDoc, SwTOXBase& rTOXBase, const OUString& rNewName) +{ + const sal_uInt16 nUserCount = rDoc.GetTOXTypeCount( TOX_USER ); + const SwTOXType* pNewType = nullptr; + for(sal_uInt16 nUser = 0; nUser < nUserCount; nUser++) + { + const SwTOXType* pType = rDoc.GetTOXType( TOX_USER, nUser ); + if (pType->GetTypeName()==rNewName) + { + pNewType = pType; + break; + } + } + if(!pNewType) + { + SwTOXType aNewType(rDoc, TOX_USER, rNewName); + pNewType = rDoc.InsertTOXType( aNewType ); + } + + rTOXBase.RegisterToTOXType( *const_cast<SwTOXType*>(pNewType) ); +} + +constexpr OUString cUserDefined = u"User-Defined"_ustr; +const char cUserSuffix[] = " (user)"; +#define USER_LEN 12 +#define USER_AND_SUFFIXLEN 19 + +static void lcl_ConvertTOUNameToProgrammaticName(OUString& rTmp) +{ + ShellResource* pShellRes = SwViewShell::GetShellRes(); + + if(rTmp==pShellRes->aTOXUserName) + { + rTmp = cUserDefined; + } + // if the version is not English but the alternative index's name is + // "User-Defined" a " (user)" is appended + else if(rTmp == cUserDefined) + { + rTmp += cUserSuffix; + } +} + +static void +lcl_ConvertTOUNameToUserName(OUString& rTmp) +{ + ShellResource* pShellRes = SwViewShell::GetShellRes(); + if (rTmp == cUserDefined) + { + rTmp = pShellRes->aTOXUserName; + } + else if (pShellRes->aTOXUserName != cUserDefined && + USER_AND_SUFFIXLEN == rTmp.getLength()) + { + //make sure that in non-English versions the " (user)" suffix is removed + if (rTmp.startsWith(cUserDefined) && + rTmp.match(cUserSuffix, USER_LEN)) + { + rTmp = cUserDefined; + } + } +} + +typedef ::cppu::WeakImplHelper +< lang::XServiceInfo +, container::XIndexReplace +> SwXDocumentIndexStyleAccess_Base; + +class SwXDocumentIndex::StyleAccess_Impl + : public SwXDocumentIndexStyleAccess_Base +{ + +private: + /// can be destroyed threadsafely, so no UnoImplPtr here + ::rtl::Reference<SwXDocumentIndex> m_xParent; + + virtual ~StyleAccess_Impl() override; + +public: + explicit StyleAccess_Impl(SwXDocumentIndex& rParentIdx); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService(const OUString& rServiceName) override; + virtual uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override; + + // XIndexReplace + virtual void SAL_CALL + replaceByIndex(sal_Int32 Index, const uno::Any& rElement) override; + +}; + +typedef ::cppu::WeakImplHelper +< lang::XServiceInfo +, container::XIndexReplace +> SwXDocumentIndexTokenAccess_Base; + +class SwXDocumentIndex::TokenAccess_Impl + : public SwXDocumentIndexTokenAccess_Base +{ + +private: + /// can be destroyed threadsafely, so no UnoImplPtr here + ::rtl::Reference<SwXDocumentIndex> m_xParent; + + virtual ~TokenAccess_Impl() override; + +public: + + explicit TokenAccess_Impl(SwXDocumentIndex& rParentIdx); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService(const OUString& rServiceName) override; + virtual uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + // XElementAccess + virtual uno::Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override; + + // XIndexReplace + virtual void SAL_CALL + replaceByIndex(sal_Int32 Index, const uno::Any& rElement) override; + +}; + +namespace { + +class SwDocIndexDescriptorProperties_Impl +{ +private: + std::unique_ptr<SwTOXBase> m_pTOXBase; + OUString m_sUserTOXTypeName; + +public: + explicit SwDocIndexDescriptorProperties_Impl(SwTOXType const*const pType); + + SwTOXBase & GetTOXBase() { return *m_pTOXBase; } + const OUString& GetTypeName() const { return m_sUserTOXTypeName; } + void SetTypeName(const OUString& rSet) { m_sUserTOXTypeName = rSet; } +}; + +} + +SwDocIndexDescriptorProperties_Impl::SwDocIndexDescriptorProperties_Impl( + SwTOXType const*const pType) +{ + SwForm aForm(pType->GetType()); + m_pTOXBase.reset(new SwTOXBase(pType, aForm, + SwTOXElement::Mark, pType->GetTypeName())); + if(pType->GetType() == TOX_CONTENT || pType->GetType() == TOX_USER) + { + m_pTOXBase->SetLevel(MAXLEVEL); + } + m_sUserTOXTypeName = pType->GetTypeName(); +} + +static sal_uInt16 +lcl_TypeToPropertyMap_Index(const TOXTypes eType) +{ + switch (eType) + { + case TOX_INDEX: return PROPERTY_MAP_INDEX_IDX; + case TOX_CONTENT: return PROPERTY_MAP_INDEX_CNTNT; + case TOX_TABLES: return PROPERTY_MAP_INDEX_TABLES; + case TOX_ILLUSTRATIONS: return PROPERTY_MAP_INDEX_ILLUSTRATIONS; + case TOX_OBJECTS: return PROPERTY_MAP_INDEX_OBJECTS; + case TOX_AUTHORITIES: return PROPERTY_MAP_BIBLIOGRAPHY; + //case TOX_USER: + default: + return PROPERTY_MAP_INDEX_USER; + } +} + +class SwXDocumentIndex::Impl final: public SvtListener +{ +private: + SwSectionFormat* m_pFormat; + +public: + unotools::WeakReference<SwXDocumentIndex> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<util::XRefreshListener> m_RefreshListeners; + ::comphelper::OInterfaceContainerHelper4<lang::XEventListener> m_EventListeners; + SfxItemPropertySet const& m_rPropSet; + const TOXTypes m_eTOXType; + bool m_bIsDescriptor; + SwDoc* m_pDoc; + std::optional<SwDocIndexDescriptorProperties_Impl> m_oProps; + uno::WeakReference<container::XIndexReplace> m_wStyleAccess; + uno::WeakReference<container::XIndexReplace> m_wTokenAccess; + + Impl(SwDoc& rDoc, const TOXTypes eType, SwTOXBaseSection *const pBaseSection) + : m_pFormat(pBaseSection ? pBaseSection->GetFormat() : nullptr) + , m_rPropSet(*aSwMapProvider.GetPropertySet(lcl_TypeToPropertyMap_Index(eType))) + , m_eTOXType(eType) + , m_bIsDescriptor(nullptr == pBaseSection) + , m_pDoc(&rDoc) + , m_oProps(m_bIsDescriptor + ? std::optional<SwDocIndexDescriptorProperties_Impl>(rDoc.GetTOXType(eType, 0)) + : std::nullopt) + { + if(m_pFormat) + StartListening(m_pFormat->GetNotifier()); + } + + void SetSectionFormat(SwSectionFormat& rFormat) + { + EndListeningAll(); + m_pFormat = &rFormat; + StartListening(rFormat.GetNotifier()); + } + + SwSectionFormat* GetSectionFormat() const { + return m_pFormat; + } + + SwTOXBase & GetTOXSectionOrThrow() const + { + SwSectionFormat *const pSectionFormat(GetSectionFormat()); + SwTOXBase *const pTOXSection( m_bIsDescriptor + ? &const_cast<SwDocIndexDescriptorProperties_Impl&>(*m_oProps).GetTOXBase() + : (pSectionFormat + ? static_cast<SwTOXBaseSection*>(pSectionFormat->GetSection()) + : nullptr)); + if (!pTOXSection) + { + throw uno::RuntimeException( + "SwXDocumentIndex: disposed or invalid", nullptr); + } + return *pTOXSection; + } + + sal_Int32 GetFormMax() const + { + SwTOXBase & rSection( GetTOXSectionOrThrow() ); + return m_bIsDescriptor + ? SwForm::GetFormMaxLevel(m_eTOXType) + : rSection.GetTOXForm().GetFormMax(); + } + virtual void Notify(const SfxHint&) override; + +}; + +void SwXDocumentIndex::Impl::Notify(const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::SwLegacyModify) + { + auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint); + if(pLegacy->m_pOld && pLegacy->m_pOld->Which() == RES_REMOVE_UNO_OBJECT) + m_pFormat = nullptr; + } + else if(rHint.GetId() == SfxHintId::Dying) + m_pFormat = nullptr; + if(!m_pFormat) + { + EndListeningAll(); + rtl::Reference<SwXDocumentIndex> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + std::unique_lock g(m_Mutex); + lang::EventObject const ev(xThis->getXWeak()); + m_RefreshListeners.disposeAndClear(g, ev); + m_EventListeners.disposeAndClear(g, ev); + } +} + +SwXDocumentIndex::SwXDocumentIndex( + SwTOXBaseSection & rBaseSection, SwDoc & rDoc) + : m_pImpl( new SwXDocumentIndex::Impl( + rDoc, rBaseSection.SwTOXBase::GetType(), & rBaseSection) ) +{ +} + +SwXDocumentIndex::SwXDocumentIndex(const TOXTypes eType, SwDoc& rDoc) + : m_pImpl( new SwXDocumentIndex::Impl(rDoc, eType, nullptr) ) +{ +} + +SwXDocumentIndex::~SwXDocumentIndex() +{ +} + +rtl::Reference<SwXDocumentIndex> +SwXDocumentIndex::CreateXDocumentIndex( + SwDoc & rDoc, SwTOXBaseSection * pSection, TOXTypes const eTypes) +{ + // re-use existing SwXDocumentIndex + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXDocumentIndex> xIndex; + if (pSection) + { + SwSectionFormat const *const pFormat = pSection->GetFormat(); + xIndex = dynamic_cast<SwXDocumentIndex*>(pFormat->GetXObject().get().get()); + } + if (!xIndex.is()) + { + xIndex = pSection + ? new SwXDocumentIndex(*pSection, rDoc) + : new SwXDocumentIndex(eTypes, rDoc); + if (pSection) + { + pSection->GetFormat()->SetXObject(xIndex->getXWeak()); + } + // need a permanent Reference to initialize m_wThis + xIndex->m_pImpl->m_wThis = xIndex.get(); + } + return xIndex; +} + +OUString SAL_CALL +SwXDocumentIndex::getImplementationName() +{ + return "SwXDocumentIndex"; +} + +sal_Bool SAL_CALL +SwXDocumentIndex::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndex::getSupportedServiceNames() +{ + SolarMutexGuard g; + + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = "com.sun.star.text.BaseIndex"; + switch (m_pImpl->m_eTOXType) + { + case TOX_INDEX: + pArray[1] = "com.sun.star.text.DocumentIndex"; + break; + case TOX_CONTENT: + pArray[1] = "com.sun.star.text.ContentIndex"; + break; + case TOX_TABLES: + pArray[1] = "com.sun.star.text.TableIndex"; + break; + case TOX_ILLUSTRATIONS: + pArray[1] = "com.sun.star.text.IllustrationsIndex"; + break; + case TOX_OBJECTS: + pArray[1] = "com.sun.star.text.ObjectIndex"; + break; + case TOX_AUTHORITIES: + pArray[1] = "com.sun.star.text.Bibliography"; + break; + //case TOX_USER: + default: + pArray[1] = "com.sun.star.text.UserDefinedIndex"; + } + return aRet; +} + +OUString SAL_CALL SwXDocumentIndex::getServiceName() +{ + SolarMutexGuard g; + + SwServiceType nObjectType = SwServiceType::TypeIndex; + switch (m_pImpl->m_eTOXType) + { + case TOX_USER: nObjectType = SwServiceType::UserIndex; + break; + case TOX_CONTENT: nObjectType = SwServiceType::ContentIndex; + break; + case TOX_ILLUSTRATIONS: nObjectType = SwServiceType::IndexIllustrations; + break; + case TOX_OBJECTS: nObjectType = SwServiceType::IndexObjects; + break; + case TOX_TABLES: nObjectType = SwServiceType::IndexTables; + break; + case TOX_AUTHORITIES: nObjectType = SwServiceType::IndexBibliography; + break; + default: + break; + } + return SwXServiceProvider::GetProviderName(nObjectType); +} + +void SAL_CALL SwXDocumentIndex::update() +{ + return refresh(); // update is from deprecated XDocumentIndex +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXDocumentIndex::getPropertySetInfo() +{ + SolarMutexGuard g; + + const uno::Reference< beans::XPropertySetInfo > xRef = + m_pImpl->m_rPropSet.getPropertySetInfo(); + return xRef; +} + +void SAL_CALL +SwXDocumentIndex::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException( + "Property is read-only: " + rPropertyName, + getXWeak()); + } + + SwSectionFormat *const pSectionFormat(m_pImpl->GetSectionFormat()); + SwTOXBase & rTOXBase( m_pImpl->GetTOXSectionOrThrow() ); + + SwTOXElement nCreate = rTOXBase.GetCreateType(); + SwTOOElements nOLEOptions = rTOXBase.GetOLEOptions(); + const TOXTypes eTxBaseType = rTOXBase.GetTOXType()->GetType(); + SwTOIOptions nTOIOptions = (eTxBaseType == TOX_INDEX) + ? rTOXBase.GetOptions() : SwTOIOptions::NONE; + SwForm aForm(rTOXBase.GetTOXForm()); + bool bForm = false; + switch (pEntry->nWID) + { + case WID_IDX_TITLE: + { + OUString sNewName; + if (!(rValue >>= sNewName)) + { + throw lang::IllegalArgumentException(); + } + rTOXBase.SetTitle(sNewName); + } + break; + case WID_IDX_NAME: + { + OUString sNewName; + if (!(rValue >>= sNewName)) + { + throw lang::IllegalArgumentException(); + } + rTOXBase.SetTOXName(sNewName); + } + break; + case WID_USER_IDX_NAME: + { + OUString sNewName; + if (!(rValue >>= sNewName)) + { + throw lang::IllegalArgumentException(); + } + lcl_ConvertTOUNameToUserName(sNewName); + OSL_ENSURE(TOX_USER == eTxBaseType, + "tox type name can only be changed for user indexes"); + if (pSectionFormat) + { + if (rTOXBase.GetTOXType()->GetTypeName() != sNewName) + { + lcl_ReAssignTOXType(*pSectionFormat->GetDoc(), + rTOXBase, sNewName); + } + } + else + { + m_pImpl->m_oProps->SetTypeName(sNewName); + } + } + break; + case WID_IDX_LOCALE: + { + lang::Locale aLocale; + if (!(rValue>>= aLocale)) + { + throw lang::IllegalArgumentException(); + } + rTOXBase.SetLanguage( LanguageTag::convertToLanguageType(aLocale)); + } + break; + case WID_IDX_SORT_ALGORITHM: + { + OUString sTmp; + if (!(rValue >>= sTmp)) + { + throw lang::IllegalArgumentException(); + } + rTOXBase.SetSortAlgorithm(sTmp); + } + break; + case WID_LEVEL: + { + rTOXBase.SetLevel(lcl_AnyToType<sal_Int16>(rValue)); + } + break; + case WID_TOC_BOOKMARK: + { + rTOXBase.SetBookmarkName(lcl_AnyToType<OUString>(rValue)); + nCreate = SwTOXElement::Bookmark; + rTOXBase.SetCreate(nCreate); + } + break; + case WID_CREATE_FROM_MARKS: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Mark); + break; + case WID_CREATE_FROM_OUTLINE: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::OutlineLevel); + break; + case WID_TOC_PARAGRAPH_OUTLINE_LEVEL: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::ParagraphOutlineLevel); + break; + case WID_TAB_IN_TOC: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::TableInToc); + break; + case WID_TOC_NEWLINE: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Newline); + break; +// case WID_PARAGRAPH_STYLE_NAMES :OSL_FAIL("not implemented") +// break; + case WID_HIDE_TABLEADER_PAGENUMBERS: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::TableLeader); + break ; + case WID_CREATE_FROM_CHAPTER: + rTOXBase.SetFromChapter(lcl_AnyToType<bool>(rValue)); + break; + case WID_CREATE_FROM_LABELS: + rTOXBase.SetFromObjectNames(! lcl_AnyToType<bool>(rValue)); + break; + case WID_PROTECTED: + { + bool bSet = lcl_AnyToType<bool>(rValue); + rTOXBase.SetProtected(bSet); + if (pSectionFormat) + { + static_cast<SwTOXBaseSection &>(rTOXBase).SetProtect(bSet); + } + } + break; + case WID_USE_ALPHABETICAL_SEPARATORS: + lcl_AnyToBitMask(rValue, nTOIOptions, + SwTOIOptions::AlphaDelimiter); + break; + case WID_USE_KEY_AS_ENTRY: + lcl_AnyToBitMask(rValue, nTOIOptions, + SwTOIOptions::KeyAsEntry); + break; + case WID_USE_COMBINED_ENTRIES: + lcl_AnyToBitMask(rValue, nTOIOptions, + SwTOIOptions::SameEntry); + break; + case WID_IS_CASE_SENSITIVE: + lcl_AnyToBitMask(rValue, nTOIOptions, + SwTOIOptions::CaseSensitive); + break; + case WID_USE_P_P: + lcl_AnyToBitMask(rValue, nTOIOptions, SwTOIOptions::FF); + break; + case WID_USE_DASH: + lcl_AnyToBitMask(rValue, nTOIOptions, SwTOIOptions::Dash); + break; + case WID_USE_UPPER_CASE: + lcl_AnyToBitMask(rValue, nTOIOptions, + SwTOIOptions::InitialCaps); + break; + case WID_IS_COMMA_SEPARATED: + bForm = true; + aForm.SetCommaSeparated(lcl_AnyToType<bool>(rValue)); + break; + case WID_LABEL_CATEGORY: + { + // convert file-format/API/external programmatic english name + // to internal UI name before usage + rTOXBase.SetSequenceName( SwStyleNameMapper::GetSpecialExtraUIName( + lcl_AnyToType<OUString>(rValue) ) ); + } + break; + case WID_LABEL_DISPLAY_TYPE: + { + const sal_Int16 nVal = lcl_AnyToType<sal_Int16>(rValue); + sal_uInt16 nSet = CAPTION_COMPLETE; + switch (nVal) + { + case text::ReferenceFieldPart::TEXT: + nSet = CAPTION_COMPLETE; + break; + case text::ReferenceFieldPart::CATEGORY_AND_NUMBER: + nSet = CAPTION_NUMBER; + break; + case text::ReferenceFieldPart::ONLY_CAPTION: + nSet = CAPTION_TEXT; + break; + default: + throw lang::IllegalArgumentException(); + } + rTOXBase.SetCaptionDisplay(static_cast<SwCaptionDisplay>(nSet)); + } + break; + case WID_USE_LEVEL_FROM_SOURCE: + rTOXBase.SetLevelFromChapter(lcl_AnyToType<bool>(rValue)); + break; + case WID_MAIN_ENTRY_CHARACTER_STYLE_NAME: + { + OUString aString; + SwStyleNameMapper::FillUIName(lcl_AnyToType<OUString>(rValue), + aString, SwGetPoolIdFromName::ChrFmt); + rTOXBase.SetMainEntryCharStyle( aString ); + } + break; + case WID_CREATE_FROM_TABLES: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Table); + break; + case WID_CREATE_FROM_TEXT_FRAMES: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Frame); + break; + case WID_CREATE_FROM_GRAPHIC_OBJECTS: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Graphic); + break; + case WID_CREATE_FROM_EMBEDDED_OBJECTS: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Ole); + break; + case WID_CREATE_FROM_STAR_MATH: + lcl_AnyToBitMask(rValue, nOLEOptions, SwTOOElements::Math); + break; + case WID_CREATE_FROM_STAR_CHART: + lcl_AnyToBitMask(rValue, nOLEOptions, SwTOOElements::Chart); + break; + case WID_CREATE_FROM_STAR_CALC: + lcl_AnyToBitMask(rValue, nOLEOptions, SwTOOElements::Calc); + break; + case WID_CREATE_FROM_STAR_DRAW: + lcl_AnyToBitMask(rValue, nOLEOptions, + SwTOOElements::DrawImpress); + break; + case WID_CREATE_FROM_OTHER_EMBEDDED_OBJECTS: + lcl_AnyToBitMask(rValue, nOLEOptions, SwTOOElements::Other); + break; + case WID_PARA_HEAD: + { + OUString aString; + SwStyleNameMapper::FillUIName( lcl_AnyToType<OUString>(rValue), + aString, SwGetPoolIdFromName::TxtColl); + bForm = true; + // Header is on Pos 0 + aForm.SetTemplate( 0, aString ); + } + break; + case WID_IS_RELATIVE_TABSTOPS: + bForm = true; + aForm.SetRelTabPos(lcl_AnyToType<bool>(rValue)); + break; + case WID_PARA_SEP: + { + OUString aString; + bForm = true; + SwStyleNameMapper::FillUIName( lcl_AnyToType<OUString>(rValue), + aString, SwGetPoolIdFromName::TxtColl); + aForm.SetTemplate( 1, aString ); + } + break; + case WID_CREATE_FROM_PARAGRAPH_STYLES: + lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Template); + break; + case WID_CREATE_FROM_PARAGRAPH_STYLE: + { + OUString style; + if (rValue >>= style) + { + if (style.indexOf(TOX_STYLE_DELIMITER) != -1) + { + throw lang::IllegalArgumentException(); + } + lcl_AnyToBitMask(uno::Any(true), nCreate, SwTOXElement::Template); + OUString uiStyle; + SwStyleNameMapper::FillUIName(style, uiStyle, SwGetPoolIdFromName::TxtColl); + rTOXBase.SetStyleNames(uiStyle, 0); + } + else if (!rValue.hasValue()) + { + lcl_AnyToBitMask(uno::Any(false), nCreate, SwTOXElement::Template); + } + else + { + throw lang::IllegalArgumentException(); + } + } + break; + + case WID_PARA_LEV1: + case WID_PARA_LEV2: + case WID_PARA_LEV3: + case WID_PARA_LEV4: + case WID_PARA_LEV5: + case WID_PARA_LEV6: + case WID_PARA_LEV7: + case WID_PARA_LEV8: + case WID_PARA_LEV9: + case WID_PARA_LEV10: + { + bForm = true; + // in sdbcx::Index Label 1 begins at Pos 2 otherwise at Pos 1 + const sal_uInt16 nLPos = rTOXBase.GetType() == TOX_INDEX ? 2 : 1; + OUString aString; + SwStyleNameMapper::FillUIName( lcl_AnyToType<OUString>(rValue), + aString, SwGetPoolIdFromName::TxtColl); + aForm.SetTemplate(nLPos + pEntry->nWID - WID_PARA_LEV1, aString ); + } + break; + default: + //this is for items only + if (WID_PRIMARY_KEY > pEntry->nWID) + { + const SwAttrSet& rSet = + SwDoc::GetTOXBaseAttrSet(rTOXBase); + SfxItemSet aAttrSet(rSet); + m_pImpl->m_rPropSet.setPropertyValue( + rPropertyName, rValue, aAttrSet); + + const SwSectionFormats& rSects = m_pImpl->m_pDoc->GetSections(); + for (size_t i = 0; i < rSects.size(); ++i) + { + const SwSectionFormat* pTmpFormat = rSects[ i ]; + if (pTmpFormat == pSectionFormat) + { + SwSectionData tmpData( + static_cast<SwTOXBaseSection&>(rTOXBase)); + m_pImpl->m_pDoc->UpdateSection(i, tmpData, & aAttrSet); + break; + } + } + } + } + rTOXBase.SetCreate(nCreate); + rTOXBase.SetOLEOptions(nOLEOptions); + if (rTOXBase.GetTOXType()->GetType() == TOX_INDEX) + { + rTOXBase.SetOptions(nTOIOptions); + } + if (bForm) + { + rTOXBase.SetTOXForm(aForm); + } +} + +uno::Any SAL_CALL +SwXDocumentIndex::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + // TODO: is this the best approach to tell API clients about the change? + if (pEntry->nWID == RES_BACKGROUND && pEntry->nMemberId == MID_GRAPHIC_URL) + { + throw uno::RuntimeException("Getting GraphicURL property is not supported"); + } + + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + SwTOXBase* pTOXBase = nullptr; + if (pSectionFormat) + { + pTOXBase = static_cast<SwTOXBaseSection*>(pSectionFormat->GetSection()); + } + else if (m_pImpl->m_bIsDescriptor) + { + pTOXBase = &m_pImpl->m_oProps->GetTOXBase(); + } + if(pTOXBase) + { + const SwTOXElement nCreate = pTOXBase->GetCreateType(); + const SwTOOElements nOLEOptions = pTOXBase->GetOLEOptions(); + const SwTOIOptions nTOIOptions = + (pTOXBase->GetTOXType()->GetType() == TOX_INDEX) + ? pTOXBase->GetOptions() + : SwTOIOptions::NONE; + const SwForm& rForm = pTOXBase->GetTOXForm(); + switch(pEntry->nWID) + { + case WID_IDX_CONTENT_SECTION: + case WID_IDX_HEADER_SECTION : + if(WID_IDX_CONTENT_SECTION == pEntry->nWID) + { + const uno::Reference <text::XTextSection> xContentSect = + SwXTextSection::CreateXTextSection( pSectionFormat ); + aRet <<= xContentSect; + } + else if (pSectionFormat) + { + SwSections aSectArr; + pSectionFormat->GetChildSections(aSectArr, + SectionSort::Not, false); + for(SwSection* pSect : aSectArr) + { + if(pSect->GetType() == SectionType::ToxHeader) + { + const uno::Reference <text::XTextSection> xHeader = + SwXTextSection::CreateXTextSection( + pSect->GetFormat() ); + aRet <<= xHeader; + break; + } + } + } + break; + case WID_IDX_TITLE : + { + aRet <<= pTOXBase->GetTitle(); + break; + } + case WID_IDX_NAME: + aRet <<= pTOXBase->GetTOXName(); + break; + case WID_USER_IDX_NAME: + { + OUString sTmp((!m_pImpl->m_bIsDescriptor) + ? pTOXBase->GetTOXType()->GetTypeName() + : m_pImpl->m_oProps->GetTypeName()); + //I18N + lcl_ConvertTOUNameToProgrammaticName(sTmp); + aRet <<= sTmp; + } + break; + case WID_IDX_LOCALE: + aRet <<= LanguageTag(pTOXBase->GetLanguage()).getLocale(); + break; + case WID_IDX_SORT_ALGORITHM: + aRet <<= pTOXBase->GetSortAlgorithm(); + break; + case WID_LEVEL : + aRet <<= static_cast<sal_Int16>(pTOXBase->GetLevel()); + break; + case WID_TOC_BOOKMARK : + aRet <<= pTOXBase->GetBookmarkName(); + break; + case WID_CREATE_FROM_MARKS: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Mark); + break; + case WID_CREATE_FROM_OUTLINE: + lcl_BitMaskToAny(aRet, nCreate, + SwTOXElement::OutlineLevel); + break; + case WID_CREATE_FROM_CHAPTER: + { + const bool bRet = pTOXBase->IsFromChapter(); + aRet <<= bRet; + } + break; + case WID_CREATE_FROM_LABELS: + { + const bool bRet = ! pTOXBase->IsFromObjectNames(); + aRet <<= bRet; + } + break; + case WID_PROTECTED: + { + const bool bRet = pTOXBase->IsProtected(); + aRet <<= bRet; + } + break; + case WID_USE_ALPHABETICAL_SEPARATORS: + lcl_BitMaskToAny(aRet, nTOIOptions, + SwTOIOptions::AlphaDelimiter); + break; + case WID_USE_KEY_AS_ENTRY: + lcl_BitMaskToAny(aRet, nTOIOptions, + SwTOIOptions::KeyAsEntry); + break; + case WID_USE_COMBINED_ENTRIES: + lcl_BitMaskToAny(aRet, nTOIOptions, + SwTOIOptions::SameEntry); + break; + case WID_IS_CASE_SENSITIVE: + lcl_BitMaskToAny(aRet, nTOIOptions, + SwTOIOptions::CaseSensitive); + break; + case WID_USE_P_P: + lcl_BitMaskToAny(aRet, nTOIOptions, SwTOIOptions::FF); + break; + case WID_USE_DASH: + lcl_BitMaskToAny(aRet, nTOIOptions, SwTOIOptions::Dash); + break; + case WID_USE_UPPER_CASE: + lcl_BitMaskToAny(aRet, nTOIOptions, + SwTOIOptions::InitialCaps); + break; + case WID_IS_COMMA_SEPARATED: + { + const bool bRet = rForm.IsCommaSeparated(); + aRet <<= bRet; + } + break; + case WID_LABEL_CATEGORY: + { + // convert internal UI name to + // file-format/API/external programmatic english name + // before usage + aRet <<= SwStyleNameMapper::GetSpecialExtraProgName( + pTOXBase->GetSequenceName() ); + } + break; + case WID_LABEL_DISPLAY_TYPE: + { + sal_Int16 nSet = text::ReferenceFieldPart::TEXT; + switch (pTOXBase->GetCaptionDisplay()) + { + case CAPTION_COMPLETE: + nSet = text::ReferenceFieldPart::TEXT; + break; + case CAPTION_NUMBER: + nSet = text::ReferenceFieldPart::CATEGORY_AND_NUMBER; + break; + case CAPTION_TEXT: + nSet = text::ReferenceFieldPart::ONLY_CAPTION; + break; + } + aRet <<= nSet; + } + break; + case WID_USE_LEVEL_FROM_SOURCE: + { + const bool bRet = pTOXBase->IsLevelFromChapter(); + aRet <<= bRet; + } + break; + case WID_LEVEL_FORMAT: + { + uno::Reference< container::XIndexReplace > xTokenAccess( + m_pImpl->m_wTokenAccess); + if (!xTokenAccess.is()) + { + xTokenAccess = new TokenAccess_Impl(*this); + m_pImpl->m_wTokenAccess = xTokenAccess; + } + aRet <<= xTokenAccess; + } + break; + case WID_LEVEL_PARAGRAPH_STYLES: + { + uno::Reference< container::XIndexReplace > xStyleAccess( + m_pImpl->m_wStyleAccess); + if (!xStyleAccess.is()) + { + xStyleAccess = new StyleAccess_Impl(*this); + m_pImpl->m_wStyleAccess = xStyleAccess; + } + aRet <<= xStyleAccess; + } + break; + case WID_MAIN_ENTRY_CHARACTER_STYLE_NAME: + { + OUString aString; + SwStyleNameMapper::FillProgName( + pTOXBase->GetMainEntryCharStyle(), + aString, + SwGetPoolIdFromName::ChrFmt); + aRet <<= aString; + } + break; + case WID_CREATE_FROM_TABLES: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Table); + break; + case WID_CREATE_FROM_TEXT_FRAMES: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Frame); + break; + case WID_CREATE_FROM_GRAPHIC_OBJECTS: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Graphic); + break; + case WID_CREATE_FROM_EMBEDDED_OBJECTS: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Ole); + break; + case WID_CREATE_FROM_STAR_MATH: + lcl_BitMaskToAny(aRet, nOLEOptions, SwTOOElements::Math); + break; + case WID_CREATE_FROM_STAR_CHART: + lcl_BitMaskToAny(aRet, nOLEOptions, SwTOOElements::Chart); + break; + case WID_CREATE_FROM_STAR_CALC: + lcl_BitMaskToAny(aRet, nOLEOptions, SwTOOElements::Calc); + break; + case WID_CREATE_FROM_STAR_DRAW: + lcl_BitMaskToAny(aRet, nOLEOptions, + SwTOOElements::DrawImpress); + break; + case WID_CREATE_FROM_OTHER_EMBEDDED_OBJECTS: + lcl_BitMaskToAny(aRet, nOLEOptions, SwTOOElements::Other); + break; + case WID_CREATE_FROM_PARAGRAPH_STYLES: + lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Template); + break; + case WID_CREATE_FROM_PARAGRAPH_STYLE: + { + if (nCreate & SwTOXElement::Template) + { // there is only one style, at top level + OUString const& rStyle(pTOXBase->GetStyleNames(0)); + if (!rStyle.isEmpty()) + { + assert(rStyle.indexOf(TOX_STYLE_DELIMITER) == -1); + OUString ret; + SwStyleNameMapper::FillProgName(rStyle, ret, + SwGetPoolIdFromName::TxtColl); + aRet <<= ret; + } + } + } + break; + + case WID_PARA_HEAD: + { + //Header is at position 0 + OUString aString; + SwStyleNameMapper::FillProgName(rForm.GetTemplate( 0 ), aString, + SwGetPoolIdFromName::TxtColl ); + aRet <<= aString; + } + break; + case WID_PARA_SEP: + { + OUString aString; + SwStyleNameMapper::FillProgName( + rForm.GetTemplate( 1 ), + aString, + SwGetPoolIdFromName::TxtColl); + aRet <<= aString; + } + break; + case WID_PARA_LEV1: + case WID_PARA_LEV2: + case WID_PARA_LEV3: + case WID_PARA_LEV4: + case WID_PARA_LEV5: + case WID_PARA_LEV6: + case WID_PARA_LEV7: + case WID_PARA_LEV8: + case WID_PARA_LEV9: + case WID_PARA_LEV10: + { + // in sdbcx::Index Label 1 begins at Pos 2 otherwise at Pos 1 + const sal_uInt16 nLPos = pTOXBase->GetType() == TOX_INDEX ? 2 : 1; + OUString aString; + SwStyleNameMapper::FillProgName( + rForm.GetTemplate(nLPos + pEntry->nWID - WID_PARA_LEV1), + aString, + SwGetPoolIdFromName::TxtColl); + aRet <<= aString; + } + break; + case WID_IS_RELATIVE_TABSTOPS: + { + const bool bRet = rForm.IsRelTabPos(); + aRet <<= bRet; + } + break; + case WID_INDEX_MARKS: + { + SwTOXMarks aMarks; + const SwTOXType* pType = pTOXBase->GetTOXType(); + pType->CollectTextMarks(aMarks); + uno::Sequence< uno::Reference<text::XDocumentIndexMark> > aXMarks(aMarks.size()); + uno::Reference<text::XDocumentIndexMark>* pxMarks = aXMarks.getArray(); + for(size_t i = 0; i < aMarks.size(); ++i) + { + SwTOXMark* pMark = aMarks[i]; + pxMarks[i] = SwXDocumentIndexMark::CreateXDocumentIndexMark( + *m_pImpl->m_pDoc, pMark); + } + aRet <<= aXMarks; + } + break; + default: + //this is for items only + if(WID_PRIMARY_KEY > pEntry->nWID) + { + const SwAttrSet& rSet = + SwDoc::GetTOXBaseAttrSet(*pTOXBase); + aRet = m_pImpl->m_rPropSet.getPropertyValue( + rPropertyName, rSet); + } + } + } + return aRet; +} + +void SAL_CALL +SwXDocumentIndex::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndex::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndex::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndex::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndex::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndex::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndex::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndex::removeVetoableChangeListener(): not implemented"); +} + +static void lcl_CalcLayout(SwDoc *pDoc) +{ + SwViewShell *pViewShell = nullptr; + SwEditShell* pEditShell = nullptr; + if( pDoc ) + { + pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + pEditShell = pDoc->GetEditShell(); + } + + if (pEditShell) + { + pEditShell->CalcLayout(); + } + else if (pViewShell) + { + pViewShell->CalcLayout(); + } +} + +// XRefreshable +void SAL_CALL SwXDocumentIndex::refresh() +{ + { + SolarMutexGuard g; + + SwSectionFormat *const pFormat = m_pImpl->GetSectionFormat(); + SwTOXBaseSection *const pTOXBase = pFormat ? + static_cast<SwTOXBaseSection*>(pFormat->GetSection()) : nullptr; + if (!pTOXBase) + { + throw uno::RuntimeException( + "SwXDocumentIndex::refresh: must be in attached state", + getXWeak()); + } + pTOXBase->Update(nullptr, m_pImpl->m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + + // the insertion of TOC will affect the document layout + lcl_CalcLayout(m_pImpl->m_pDoc); + + // page numbers + pTOXBase->UpdatePageNum(); + } + + std::unique_lock g(m_pImpl->m_Mutex); + if (m_pImpl->m_RefreshListeners.getLength(g)) + { + lang::EventObject const event(getXWeak()); + m_pImpl->m_RefreshListeners.notifyEach(g, & util::XRefreshListener::refreshed, event); + } +} + +void SAL_CALL SwXDocumentIndex::addRefreshListener( + const uno::Reference<util::XRefreshListener>& xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock g(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.addInterface(g, xListener); +} + +void SAL_CALL SwXDocumentIndex::removeRefreshListener( + const uno::Reference<util::XRefreshListener>& xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock g(m_pImpl->m_Mutex); + m_pImpl->m_RefreshListeners.removeInterface(g, xListener); +} + +void SAL_CALL +SwXDocumentIndex::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + SwXTextRange *const pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwDoc *const pDoc = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDoc) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + + const SwTOXBase* pOld = SwDoc::GetCurTOX( *aPam.Start() ); + if (pOld) + { + throw lang::IllegalArgumentException(); + } + + UnoActionContext aAction(pDoc); + + SwTOXBase & rTOXBase = m_pImpl->m_oProps->GetTOXBase(); + SwTOXType const*const pTOXType = rTOXBase.GetTOXType(); + if ((TOX_USER == pTOXType->GetType()) && + m_pImpl->m_oProps->GetTypeName() != pTOXType->GetTypeName()) + { + lcl_ReAssignTOXType(*pDoc, rTOXBase, m_pImpl->m_oProps->GetTypeName()); + } + //TODO: apply Section attributes (columns and background) + SwTOXBaseSection *const pTOX = + pDoc->InsertTableOf( aPam, rTOXBase, nullptr, false, + m_pImpl->m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + + pDoc->SetTOXBaseName(*pTOX, m_pImpl->m_oProps->GetTOXBase().GetTOXName()); + + // update page numbers + m_pImpl->SetSectionFormat(*pTOX->GetFormat()); + pTOX->GetFormat()->SetXObject(getXWeak()); + pTOX->UpdatePageNum(); + + m_pImpl->m_oProps.reset(); + m_pImpl->m_pDoc = pDoc; + m_pImpl->m_bIsDescriptor = false; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXDocumentIndex::getAnchor() +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (!pSectionFormat) + { + throw uno::RuntimeException(); + } + + rtl::Reference<SwXTextRange> xRet; + SwNodeIndex const*const pIdx( pSectionFormat->GetContent().GetContentIdx() ); + if (pIdx && pIdx->GetNode().GetNodes().IsDocNodes()) + { + SwPaM aPaM(*pIdx); + aPaM.Move( fnMoveForward, GoInContent ); + aPaM.SetMark(); + aPaM.GetPoint()->Assign( *pIdx->GetNode().EndOfSectionNode() ); + aPaM.Move( fnMoveBackward, GoInContent ); + xRet = SwXTextRange::CreateXTextRange(*pSectionFormat->GetDoc(), + *aPaM.GetMark(), aPaM.GetPoint()); + } + return xRet; +} + +void SAL_CALL SwXDocumentIndex::dispose() +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (pSectionFormat) + { + pSectionFormat->GetDoc()->DeleteTOX( + *static_cast<SwTOXBaseSection*>(pSectionFormat->GetSection()), + true); + } +} + +void SAL_CALL +SwXDocumentIndex::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock g(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(g, xListener); +} + +void SAL_CALL +SwXDocumentIndex::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock g(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(g, xListener); +} + +OUString SAL_CALL SwXDocumentIndex::getName() +{ + SolarMutexGuard g; + + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (m_pImpl->m_bIsDescriptor) + { + return m_pImpl->m_oProps->GetTOXBase().GetTOXName(); + } + + if(!pSectionFormat) + { + throw uno::RuntimeException(); + } + + return pSectionFormat->GetSection()->GetSectionName(); +} + +void SAL_CALL +SwXDocumentIndex::setName(const OUString& rName) +{ + SolarMutexGuard g; + + if (rName.isEmpty()) + { + throw uno::RuntimeException(); + } + + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_oProps->GetTOXBase().SetTOXName(rName); + } + else if (pSectionFormat) + { + const bool bSuccess = pSectionFormat->GetDoc()->SetTOXBaseName( + *static_cast<SwTOXBaseSection*>(pSectionFormat->GetSection()), rName); + if (!bSuccess) + { + throw uno::RuntimeException(); + } + } + else + { + throw uno::RuntimeException(); + } +} + +// MetadatableMixin +::sfx2::Metadatable* SwXDocumentIndex::GetCoreObject() +{ + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + return pSectionFormat; +} + +uno::Reference<frame::XModel> SwXDocumentIndex::GetModel() +{ + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (pSectionFormat) + { + SwDocShell const*const pShell( pSectionFormat->GetDoc()->GetDocShell() ); + return pShell ? pShell->GetModel() : nullptr; + } + return nullptr; +} + +static sal_uInt16 +lcl_TypeToPropertyMap_Mark(const TOXTypes eType) +{ + switch (eType) + { + case TOX_INDEX: return PROPERTY_MAP_INDEX_MARK; + case TOX_CONTENT: return PROPERTY_MAP_CNTIDX_MARK; + case TOX_CITATION : return PROPERTY_MAP_FLDTYP_BIBLIOGRAPHY; + //case TOX_USER: + default: + return PROPERTY_MAP_USER_MARK; + } +} + +class SwXDocumentIndexMark::Impl final: public SvtListener +{ +private: + SwXDocumentIndexMark & m_rThis; + bool m_bInReplaceMark; + +public: + + unotools::WeakReference<SwXDocumentIndexMark> m_wThis; + SfxItemPropertySet const& m_rPropSet; + const TOXTypes m_eTOXType; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + bool m_bIsDescriptor; + const SwTOXType* m_pTOXType; + const SwTOXMark* m_pTOXMark; + SwDoc* m_pDoc; + + bool m_bMainEntry; + sal_uInt16 m_nLevel; + OUString m_aBookmarkName; + OUString m_sAltText; + OUString m_sPrimaryKey; + OUString m_sSecondaryKey; + OUString m_sTextReading; + OUString m_sPrimaryKeyReading; + OUString m_sSecondaryKeyReading; + OUString m_sUserIndexName; + + Impl(SwXDocumentIndexMark& rThis, + SwDoc* const pDoc, + const enum TOXTypes eType, + const SwTOXType* pType, + SwTOXMark const* pMark) + : m_rThis(rThis) + , m_bInReplaceMark(false) + , m_rPropSet( + *aSwMapProvider.GetPropertySet(lcl_TypeToPropertyMap_Mark(eType))) + , m_eTOXType(eType) + , m_bIsDescriptor(nullptr == pMark) + , m_pTOXType(pType) + , m_pTOXMark(pMark) + , m_pDoc(pDoc) + , m_bMainEntry(false) + , m_nLevel(0) + { + auto pMarkNonConst = const_cast<SwTOXMark*>(m_pTOXMark); + auto pTypeNonConst = const_cast<SwTOXType*>(m_pTOXType); + + if(pMarkNonConst) + StartListening(pMarkNonConst->GetNotifier()); + if(pTypeNonConst) + StartListening(pTypeNonConst->GetNotifier()); + } + + SwTOXType* GetTOXType() const { + return const_cast<SwTOXType*>(m_pTOXType); + } + + void DeleteTOXMark() + { + m_pDoc->DeleteTOXMark(m_pTOXMark); + Invalidate(); + } + + void InsertTOXMark(const SwTOXType & rTOXType, SwTOXMark & rMark, SwPaM & rPam, + SwXTextCursor const*const pTextCursor); + + void ReplaceTOXMark(const SwTOXType & rTOXType, SwTOXMark & rMark, SwPaM & rPam) + { + m_bInReplaceMark = true; + DeleteTOXMark(); + m_bInReplaceMark = false; + try { + InsertTOXMark(rTOXType, rMark, rPam, nullptr); + } catch (...) { + OSL_FAIL("ReplaceTOXMark() failed!"); + lang::EventObject const ev(m_rThis.getXWeak()); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); + throw; + } + } + + void Invalidate(); + virtual void Notify(const SfxHint&) override; +}; + +void SwXDocumentIndexMark::Impl::Invalidate() +{ + if (!m_bInReplaceMark) // #i109983# only dispose on delete, not on replace! + { + rtl::Reference<SwXDocumentIndexMark> const xThis(m_wThis); + // fdo#72695: if UNO object is already dead, don't revive it with event + if (xThis.is()) + { + lang::EventObject const ev(xThis->getXWeak()); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); + } + } + EndListeningAll(); + m_pDoc = nullptr; + m_pTOXMark = nullptr; + m_pTOXType = nullptr; +} + +void SwXDocumentIndexMark::Impl::Notify(const SfxHint& rHint) +{ + if(auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint)) + { + if(auto pNewType = dynamic_cast<const SwTOXType*>(pModifyChangedHint->m_pNew)) + m_pTOXType = pNewType; + + else + Invalidate(); + } +} + +SwXDocumentIndexMark::SwXDocumentIndexMark(const TOXTypes eToxType) + : m_pImpl( new SwXDocumentIndexMark::Impl(*this, nullptr, eToxType, nullptr, nullptr) ) +{ +} + +SwXDocumentIndexMark::SwXDocumentIndexMark(SwDoc & rDoc, + const SwTOXType & rType, const SwTOXMark & rMark) + : m_pImpl( new SwXDocumentIndexMark::Impl(*this, &rDoc, rType.GetType(), + &rType, &rMark) ) +{ +} + +SwXDocumentIndexMark::~SwXDocumentIndexMark() +{ +} + +rtl::Reference<SwXDocumentIndexMark> +SwXDocumentIndexMark::CreateXDocumentIndexMark( + SwDoc & rDoc, SwTOXMark *const pMark, TOXTypes const eType) +{ + // re-use existing SwXDocumentIndexMark + // NB: xmloff depends on this caching to generate ID from the address! + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXDocumentIndexMark> xTOXMark; + if (pMark) + { + xTOXMark = pMark->GetXTOXMark(); + } + if (!xTOXMark.is()) + { + xTOXMark = pMark + ? new SwXDocumentIndexMark(rDoc, + *const_cast<SwTOXType*>(pMark->GetTOXType()), *pMark) + : new SwXDocumentIndexMark(eType); + if (pMark) + { + pMark->SetXTOXMark(xTOXMark); + } + // need a permanent Reference to initialize m_wThis + xTOXMark->m_pImpl->m_wThis = xTOXMark.get(); + } + return xTOXMark; +} + +namespace +{ +} + +OUString SAL_CALL +SwXDocumentIndexMark::getImplementationName() +{ + return "SwXDocumentIndexMark"; +} + +sal_Bool SAL_CALL SwXDocumentIndexMark::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndexMark::getSupportedServiceNames() +{ + SolarMutexGuard g; + + const sal_Int32 nCnt = (m_pImpl->m_eTOXType == TOX_INDEX) ? 4 : 3; + uno::Sequence< OUString > aRet(nCnt); + OUString* pArray = aRet.getArray(); + pArray[0] = "com.sun.star.text.BaseIndexMark"; + pArray[1] = "com.sun.star.text.TextContent"; + switch (m_pImpl->m_eTOXType) + { + case TOX_USER: + pArray[2] = "com.sun.star.text.UserIndexMark"; + break; + case TOX_CONTENT: + pArray[2] = "com.sun.star.text.ContentIndexMark"; + break; + case TOX_INDEX: + pArray[2] = "com.sun.star.text.DocumentIndexMark"; + pArray[3] = "com.sun.star.text.DocumentIndexMarkAsian"; + break; + + default: + ; + } + return aRet; +} + +OUString SAL_CALL +SwXDocumentIndexMark::getMarkEntry() +{ + SolarMutexGuard aGuard; + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (pType && m_pImpl->m_pTOXMark) + { + return m_pImpl->m_pTOXMark->GetAlternativeText(); + } + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + return m_pImpl->m_sAltText; +} + +void SAL_CALL +SwXDocumentIndexMark::setMarkEntry(const OUString& rIndexEntry) +{ + SolarMutexGuard aGuard; + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (pType && m_pImpl->m_pTOXMark) + { + SwTOXMark aMark(*m_pImpl->m_pTOXMark); + aMark.SetAlternativeText(rIndexEntry); + SwTextTOXMark const*const pTextMark = + m_pImpl->m_pTOXMark->GetTextTOXMark(); + SwPaM aPam(pTextMark->GetTextNode(), pTextMark->GetStart()); + aPam.SetMark(); + if(pTextMark->End()) + { + aPam.GetPoint()->SetContent( *pTextMark->End() ); + } + else + aPam.GetPoint()->AdjustContent(1); + + m_pImpl->ReplaceTOXMark(*pType, aMark, aPam); + } + else if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_sAltText = rIndexEntry; + } + else + { + throw uno::RuntimeException(); + } +} + +void SAL_CALL +SwXDocumentIndexMark::attach( + const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + SwXTextRange *const pRange = + dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = + dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + SwDoc *const pDoc = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDoc) + { + throw lang::IllegalArgumentException(); + } + + const SwTOXType* pTOXType = nullptr; + switch (m_pImpl->m_eTOXType) + { + case TOX_INDEX: + case TOX_CONTENT: + case TOX_CITATION: + pTOXType = pDoc->GetTOXType( m_pImpl->m_eTOXType, 0 ); + break; + case TOX_USER: + { + if (m_pImpl->m_sUserIndexName.isEmpty()) + { + pTOXType = pDoc->GetTOXType( m_pImpl->m_eTOXType, 0 ); + } + else + { + const sal_uInt16 nCount = + pDoc->GetTOXTypeCount(m_pImpl->m_eTOXType); + for (sal_uInt16 i = 0; i < nCount; i++) + { + SwTOXType const*const pTemp = + pDoc->GetTOXType( m_pImpl->m_eTOXType, i ); + if (m_pImpl->m_sUserIndexName == pTemp->GetTypeName()) + { + pTOXType = pTemp; + break; + } + } + if (!pTOXType) + { + SwTOXType aUserType(*pDoc, TOX_USER, m_pImpl->m_sUserIndexName); + pTOXType = pDoc->InsertTOXType(aUserType); + } + } + } + break; + + default: + break; + } + if (!pTOXType) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + SwTOXMark aMark (pTOXType); + if (!m_pImpl->m_sAltText.isEmpty()) + { + aMark.SetAlternativeText(m_pImpl->m_sAltText); + } + switch (m_pImpl->m_eTOXType) + { + case TOX_INDEX: + if (!m_pImpl->m_sPrimaryKey.isEmpty()) + { + aMark.SetPrimaryKey(m_pImpl->m_sPrimaryKey); + } + if (!m_pImpl->m_sSecondaryKey.isEmpty()) + { + aMark.SetSecondaryKey(m_pImpl->m_sSecondaryKey); + } + if (!m_pImpl->m_sTextReading.isEmpty()) + { + aMark.SetTextReading(m_pImpl->m_sTextReading); + } + if (!m_pImpl->m_sPrimaryKeyReading.isEmpty()) + { + aMark.SetPrimaryKeyReading(m_pImpl->m_sPrimaryKeyReading); + } + if (!m_pImpl->m_sSecondaryKeyReading.isEmpty()) + { + aMark.SetSecondaryKeyReading(m_pImpl->m_sSecondaryKeyReading); + } + aMark.SetMainEntry(m_pImpl->m_bMainEntry); + break; + case TOX_CITATION: + aMark.SetMainEntry(m_pImpl->m_bMainEntry); + break; + case TOX_USER: + case TOX_CONTENT: + if (USHRT_MAX != m_pImpl->m_nLevel) + { + aMark.SetLevel(m_pImpl->m_nLevel+1); + } + break; + + default: + break; + } + + m_pImpl->InsertTOXMark(*const_cast<SwTOXType *>(pTOXType), aMark, aPam, + dynamic_cast<SwXTextCursor const*>(pCursor)); + + m_pImpl->m_bIsDescriptor = false; +} + +namespace { + +template<typename T> struct NotContainedIn +{ + std::vector<T> const& m_rVector; + explicit NotContainedIn(std::vector<T> const& rVector) + : m_rVector(rVector) { } + bool operator() (T const& rT) { + return std::find(m_rVector.begin(), m_rVector.end(), rT) + == m_rVector.end(); + } +}; + +} + +void SwXDocumentIndexMark::Impl::InsertTOXMark( + const SwTOXType & rTOXType, SwTOXMark & rMark, SwPaM & rPam, + SwXTextCursor const*const pTextCursor) +{ + SwDoc& rDoc(rPam.GetDoc()); + UnoActionContext aAction(&rDoc); + bool bMark = *rPam.GetPoint() != *rPam.GetMark(); + // n.b.: toxmarks must have either alternative text or an extent + if (bMark && !rMark.GetAlternativeText().isEmpty()) + { + rPam.Normalize(); + rPam.DeleteMark(); + bMark = false; + } + // Marks without alternative text and without selected text cannot be inserted, + // thus use a space - is this really the ideal solution? + if (!bMark && rMark.GetAlternativeText().isEmpty()) + { + rMark.SetAlternativeText( " " ); + } + + const bool bForceExpandHints( !bMark && pTextCursor && pTextCursor->IsAtEndOfMeta() ); + const SetAttrMode nInsertFlags = bForceExpandHints + ? ( SetAttrMode::FORCEHINTEXPAND + | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND; + + // rMark gets copied into the document pool; + // pNewTextAttr comes back with the real format + SwTextAttr *pNewTextAttr = nullptr; + rDoc.getIDocumentContentOperations().InsertPoolItem(rPam, rMark, nInsertFlags, + /*pLayout*/nullptr, &pNewTextAttr); + if (bMark && *rPam.GetPoint() > *rPam.GetMark()) + { + rPam.Exchange(); + } + + if (!pNewTextAttr) + { + throw uno::RuntimeException( + "SwXDocumentIndexMark::InsertTOXMark(): cannot insert attribute", + nullptr); + } + + m_pDoc = &rDoc; + m_pTOXMark = &pNewTextAttr->GetTOXMark(); + m_pTOXType = &rTOXType; + EndListeningAll(); + StartListening(const_cast<SwTOXMark*>(m_pTOXMark)->GetNotifier()); + StartListening(const_cast<SwTOXType*>(m_pTOXType)->GetNotifier()); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXDocumentIndexMark::getAnchor() +{ + SolarMutexGuard aGuard; + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (!pType || !m_pImpl->m_pTOXMark) + { + throw uno::RuntimeException(); + } + if (!m_pImpl->m_pTOXMark->GetTextTOXMark()) + { + throw uno::RuntimeException(); + } + const SwTextTOXMark* pTextMark = m_pImpl->m_pTOXMark->GetTextTOXMark(); + SwPaM aPam(pTextMark->GetTextNode(), pTextMark->GetStart()); + aPam.SetMark(); + if(pTextMark->End()) + { + aPam.GetPoint()->SetContent( *pTextMark->End() ); + } + else + { + aPam.GetPoint()->AdjustContent(1); + } + const uno::Reference< frame::XModel > xModel = + m_pImpl->m_pDoc->GetDocShell()->GetBaseModel(); + const uno::Reference< text::XTextDocument > xTDoc(xModel, uno::UNO_QUERY); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aPam, xTDoc->getText()); + + return xRet; +} + +void SAL_CALL +SwXDocumentIndexMark::dispose() +{ + SolarMutexGuard aGuard; + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (pType && m_pImpl->m_pTOXMark) + { + m_pImpl->DeleteTOXMark(); // call Invalidate() via modify! + } +} + +void SAL_CALL +SwXDocumentIndexMark::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL +SwXDocumentIndexMark::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXDocumentIndexMark::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xInfos[3]; + int nPos = 0; + switch (m_pImpl->m_eTOXType) + { + case TOX_INDEX: nPos = 0; break; + case TOX_CONTENT: nPos = 1; break; + case TOX_USER: nPos = 2; break; + default: + ; + } + if(!xInfos[nPos].is()) + { + const uno::Reference< beans::XPropertySetInfo > xInfo = + m_pImpl->m_rPropSet.getPropertySetInfo(); + // extend PropertySetInfo! + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + xInfos[nPos] = new SfxExtItemPropertySetInfo( + aSwMapProvider.GetPropertyMapEntries( + PROPERTY_MAP_PARAGRAPH_EXTENSIONS), + aPropSeq ); + } + return xInfos[nPos]; +} + +void SAL_CALL +SwXDocumentIndexMark::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException( + "Property is read-only: " + rPropertyName, + getXWeak()); + } + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (pType && m_pImpl->m_pTOXMark) + { + SwTOXMark aMark(*m_pImpl->m_pTOXMark); + switch(pEntry->nWID) + { + case WID_ALT_TEXT: + aMark.SetAlternativeText(lcl_AnyToType<OUString>(rValue)); + break; + case WID_LEVEL: + aMark.SetLevel(std::min( static_cast<sal_Int8>( MAXLEVEL ), + static_cast<sal_Int8>(lcl_AnyToType<sal_Int16>(rValue)+1))); + break; + case WID_TOC_BOOKMARK : + aMark.SetBookmarkName(lcl_AnyToType<OUString>(rValue)); + break; + case WID_PRIMARY_KEY : + aMark.SetPrimaryKey(lcl_AnyToType<OUString>(rValue)); + break; + case WID_SECONDARY_KEY: + aMark.SetSecondaryKey(lcl_AnyToType<OUString>(rValue)); + break; + case WID_MAIN_ENTRY: + aMark.SetMainEntry(lcl_AnyToType<bool>(rValue)); + break; + case WID_TEXT_READING: + aMark.SetTextReading(lcl_AnyToType<OUString>(rValue)); + break; + case WID_PRIMARY_KEY_READING: + aMark.SetPrimaryKeyReading(lcl_AnyToType<OUString>(rValue)); + break; + case WID_SECONDARY_KEY_READING: + aMark.SetSecondaryKeyReading(lcl_AnyToType<OUString>(rValue)); + break; + } + SwTextTOXMark const*const pTextMark = + m_pImpl->m_pTOXMark->GetTextTOXMark(); + SwPaM aPam(pTextMark->GetTextNode(), pTextMark->GetStart()); + aPam.SetMark(); + if(pTextMark->End()) + { + aPam.GetPoint()->SetContent(*pTextMark->End()); + } + else + { + aPam.GetPoint()->AdjustContent(1); + } + + m_pImpl->ReplaceTOXMark(*pType, aMark, aPam); + } + else if (m_pImpl->m_bIsDescriptor) + { + switch(pEntry->nWID) + { + case WID_ALT_TEXT: + m_pImpl->m_sAltText = lcl_AnyToType<OUString>(rValue); + break; + case WID_LEVEL: + { + const sal_Int16 nVal = lcl_AnyToType<sal_Int16>(rValue); + if(nVal < 0 || nVal >= MAXLEVEL) + { + throw lang::IllegalArgumentException(); + } + m_pImpl->m_nLevel = nVal; + } + break; + case WID_TOC_BOOKMARK : + { + m_pImpl->m_aBookmarkName = lcl_AnyToType<OUString>(rValue); + } + break; + case WID_PRIMARY_KEY: + m_pImpl->m_sPrimaryKey = lcl_AnyToType<OUString>(rValue); + break; + case WID_SECONDARY_KEY: + m_pImpl->m_sSecondaryKey = lcl_AnyToType<OUString>(rValue); + break; + case WID_TEXT_READING: + m_pImpl->m_sTextReading = lcl_AnyToType<OUString>(rValue); + break; + case WID_PRIMARY_KEY_READING: + m_pImpl->m_sPrimaryKeyReading = lcl_AnyToType<OUString>(rValue); + break; + case WID_SECONDARY_KEY_READING: + m_pImpl->m_sSecondaryKeyReading = lcl_AnyToType<OUString>(rValue); + break; + case WID_USER_IDX_NAME: + { + OUString sTmp(lcl_AnyToType<OUString>(rValue)); + lcl_ConvertTOUNameToUserName(sTmp); + m_pImpl->m_sUserIndexName = sTmp; + } + break; + case WID_MAIN_ENTRY: + m_pImpl->m_bMainEntry = lcl_AnyToType<bool>(rValue); + break; + case PROPERTY_MAP_INDEX_OBJECTS: + // unsupported + break; + } + } + else + { + throw uno::RuntimeException(); + } +} + +uno::Any SAL_CALL +SwXDocumentIndexMark::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + if (::sw::GetDefaultTextContentValue(aRet, rPropertyName, pEntry->nWID)) + { + return aRet; + } + + SwTOXType *const pType = m_pImpl->GetTOXType(); + if (pType && m_pImpl->m_pTOXMark) + { + switch(pEntry->nWID) + { + case WID_ALT_TEXT: + aRet <<= m_pImpl->m_pTOXMark->GetAlternativeText(); + break; + case WID_LEVEL: + aRet <<= static_cast<sal_Int16>( + m_pImpl->m_pTOXMark->GetLevel() - 1); + break; + case WID_TOC_BOOKMARK : + aRet <<= m_pImpl->m_pTOXMark->GetBookmarkName(); + break; + case WID_PRIMARY_KEY : + aRet <<= m_pImpl->m_pTOXMark->GetPrimaryKey(); + break; + case WID_SECONDARY_KEY: + aRet <<= m_pImpl->m_pTOXMark->GetSecondaryKey(); + break; + case WID_TEXT_READING: + aRet <<= m_pImpl->m_pTOXMark->GetTextReading(); + break; + case WID_PRIMARY_KEY_READING: + aRet <<= m_pImpl->m_pTOXMark->GetPrimaryKeyReading(); + break; + case WID_SECONDARY_KEY_READING: + aRet <<= m_pImpl->m_pTOXMark->GetSecondaryKeyReading(); + break; + case WID_USER_IDX_NAME : + { + OUString sTmp(pType->GetTypeName()); + lcl_ConvertTOUNameToProgrammaticName(sTmp); + aRet <<= sTmp; + } + break; + case WID_MAIN_ENTRY: + { + const bool bTemp = m_pImpl->m_pTOXMark->IsMainEntry(); + aRet <<= bTemp; + } + break; + } + } + else if (m_pImpl->m_bIsDescriptor) + { + switch(pEntry->nWID) + { + case WID_ALT_TEXT: + aRet <<= m_pImpl->m_sAltText; + break; + case WID_LEVEL: + aRet <<= static_cast<sal_Int16>(m_pImpl->m_nLevel); + break; + case WID_TOC_BOOKMARK : + aRet <<= m_pImpl->m_aBookmarkName; + break; + case WID_PRIMARY_KEY: + aRet <<= m_pImpl->m_sPrimaryKey; + break; + case WID_SECONDARY_KEY: + aRet <<= m_pImpl->m_sSecondaryKey; + break; + case WID_TEXT_READING: + aRet <<= m_pImpl->m_sTextReading; + break; + case WID_PRIMARY_KEY_READING: + aRet <<= m_pImpl->m_sPrimaryKeyReading; + break; + case WID_SECONDARY_KEY_READING: + aRet <<= m_pImpl->m_sSecondaryKeyReading; + break; + case WID_USER_IDX_NAME : + aRet <<= m_pImpl->m_sUserIndexName; + break; + case WID_MAIN_ENTRY: + aRet <<= m_pImpl->m_bMainEntry; + break; + } + } + else + { + throw uno::RuntimeException(); + } + return aRet; +} + +void SAL_CALL +SwXDocumentIndexMark::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndexMark::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndexMark::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndexMark::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndexMark::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndexMark::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXDocumentIndexMark::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXDocumentIndexMark::removeVetoableChangeListener(): not implemented"); +} + +SwXDocumentIndexes::SwXDocumentIndexes(SwDoc *const _pDoc) + : SwUnoCollection(_pDoc) +{ +} + +SwXDocumentIndexes::~SwXDocumentIndexes() +{ +} + +OUString SAL_CALL +SwXDocumentIndexes::getImplementationName() +{ + return "SwXDocumentIndexes"; +} + +sal_Bool SAL_CALL SwXDocumentIndexes::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndexes::getSupportedServiceNames() +{ + return { "com.sun.star.text.DocumentIndexes" }; +} + +sal_Int32 SAL_CALL +SwXDocumentIndexes::getCount() +{ + SolarMutexGuard aGuard; + + sal_uInt32 nRet = 0; + const SwSectionFormats& rFormats = GetDoc().GetSections(); + for( size_t n = 0; n < rFormats.size(); ++n ) + { + const SwSection* pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode() ) + { + ++nRet; + } + } + return nRet; +} + +uno::Any SAL_CALL +SwXDocumentIndexes::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + + sal_Int32 nIdx = 0; + + auto& rDoc = GetDoc(); + const SwSectionFormats& rFormats = rDoc.GetSections(); + for( size_t n = 0; n < rFormats.size(); ++n ) + { + SwSection* pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode() && + nIdx++ == nIndex ) + { + const uno::Reference< text::XDocumentIndex > xTmp = + SwXDocumentIndex::CreateXDocumentIndex( + rDoc, static_cast<SwTOXBaseSection *>(pSect)); + uno::Any aRet; + aRet <<= xTmp; + return aRet; + } + } + + throw lang::IndexOutOfBoundsException(); +} + +uno::Any SAL_CALL +SwXDocumentIndexes::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + auto& rDoc = GetDoc(); + const SwSectionFormats& rFormats = rDoc.GetSections(); + for( size_t n = 0; n < rFormats.size(); ++n ) + { + SwSection* pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode() && + (static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName() + == rName)) + { + const uno::Reference< text::XDocumentIndex > xTmp = + SwXDocumentIndex::CreateXDocumentIndex( + rDoc, static_cast<SwTOXBaseSection *>(pSect)); + uno::Any aRet; + aRet <<= xTmp; + return aRet; + } + } + throw container::NoSuchElementException(); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndexes::getElementNames() +{ + SolarMutexGuard aGuard; + + const SwSectionFormats& rFormats = GetDoc().GetSections(); + sal_Int32 nCount = 0; + for( size_t n = 0; n < rFormats.size(); ++n ) + { + SwSection const*const pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode() ) + { + ++nCount; + } + } + + uno::Sequence< OUString > aRet(nCount); + OUString* pArray = aRet.getArray(); + sal_Int32 nCnt = 0; + for( size_t n = 0; n < rFormats.size(); ++n ) + { + SwSection const*const pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode()) + { + pArray[nCnt++] = static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName(); + } + } + return aRet; +} + +sal_Bool SAL_CALL +SwXDocumentIndexes::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + const SwSectionFormats& rFormats = GetDoc().GetSections(); + for( size_t n = 0; n < rFormats.size(); ++n ) + { + SwSection const*const pSect = rFormats[ n ]->GetSection(); + if( SectionType::ToxContent == pSect->GetType() && + pSect->GetFormat()->GetSectionNode()) + { + if (static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName() + == rName) + { + return true; + } + } + } + return false; +} + +uno::Type SAL_CALL +SwXDocumentIndexes::getElementType() +{ + return cppu::UnoType<text::XDocumentIndex>::get(); +} + +sal_Bool SAL_CALL +SwXDocumentIndexes::hasElements() +{ + return 0 != getCount(); +} + +SwXDocumentIndex::StyleAccess_Impl::StyleAccess_Impl( + SwXDocumentIndex& rParentIdx) + : m_xParent(&rParentIdx) +{ +} + +SwXDocumentIndex::StyleAccess_Impl::~StyleAccess_Impl() +{ +} + +OUString SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::getImplementationName() +{ + return "SwXDocumentIndex::StyleAccess_Impl"; +} + +sal_Bool SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::getSupportedServiceNames() +{ + return { "com.sun.star.text.DocumentIndexParagraphStyles" }; +} + +void SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::replaceByIndex( + sal_Int32 nIndex, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + + if(nIndex < 0 || nIndex >= MAXLEVEL) + { + throw lang::IndexOutOfBoundsException(); + } + + SwTOXBase & rTOXBase( m_xParent->m_pImpl->GetTOXSectionOrThrow() ); + + uno::Sequence<OUString> aSeq; + if(!(rElement >>= aSeq)) + { + throw lang::IllegalArgumentException(); + } + + const sal_Int32 nStyles = aSeq.getLength(); + const OUString* pStyles = aSeq.getConstArray(); + OUStringBuffer sSetStyles; + OUString aString; + for(sal_Int32 i = 0; i < nStyles; i++) + { + if(i) + { + sSetStyles.append(TOX_STYLE_DELIMITER); + } + SwStyleNameMapper::FillUIName(pStyles[i], aString, + SwGetPoolIdFromName::TxtColl); + sSetStyles.append(aString); + } + rTOXBase.SetStyleNames(sSetStyles.makeStringAndClear(), o3tl::narrowing<sal_uInt16>(nIndex)); +} + +sal_Int32 SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::getCount() +{ + return MAXLEVEL; +} + +uno::Any SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + + if(nIndex < 0 || nIndex >= MAXLEVEL) + { + throw lang::IndexOutOfBoundsException(); + } + + SwTOXBase & rTOXBase( m_xParent->m_pImpl->GetTOXSectionOrThrow() ); + + const OUString& rStyles = + rTOXBase.GetStyleNames(o3tl::narrowing<sal_uInt16>(nIndex)); + const sal_Int32 nStyles = comphelper::string::getTokenCount(rStyles, TOX_STYLE_DELIMITER); + uno::Sequence<OUString> aStyles(nStyles); + OUString* pStyles = aStyles.getArray(); + OUString aString; + sal_Int32 nPos = 0; + for(sal_Int32 i = 0; i < nStyles; ++i) + { + SwStyleNameMapper::FillProgName( + rStyles.getToken(0, TOX_STYLE_DELIMITER, nPos), + aString, + SwGetPoolIdFromName::TxtColl); + pStyles[i] = aString; + } + uno::Any aRet(&aStyles, cppu::UnoType<uno::Sequence<OUString>>::get()); + return aRet; +} + +uno::Type SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::getElementType() +{ + return cppu::UnoType<uno::Sequence<OUString>>::get(); +} + +sal_Bool SAL_CALL +SwXDocumentIndex::StyleAccess_Impl::hasElements() +{ + return true; +} + +SwXDocumentIndex::TokenAccess_Impl::TokenAccess_Impl( + SwXDocumentIndex& rParentIdx) + : m_xParent(&rParentIdx) +{ +} + +SwXDocumentIndex::TokenAccess_Impl::~TokenAccess_Impl() +{ +} + +OUString SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::getImplementationName() +{ + return "SwXDocumentIndex::TokenAccess_Impl"; +} + +sal_Bool SAL_CALL SwXDocumentIndex::TokenAccess_Impl::supportsService( + const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::getSupportedServiceNames() +{ + return { "com.sun.star.text.DocumentIndexLevelFormat" }; +} + +namespace { + +struct TokenType_ { + const char *pName; + enum FormTokenType eTokenType; +}; + +} + +const struct TokenType_ g_TokenTypes[] = +{ + { "TokenEntryNumber", TOKEN_ENTRY_NO }, + { "TokenEntryText", TOKEN_ENTRY_TEXT }, + { "TokenTabStop", TOKEN_TAB_STOP }, + { "TokenText", TOKEN_TEXT }, + { "TokenPageNumber", TOKEN_PAGE_NUMS }, + { "TokenChapterInfo", TOKEN_CHAPTER_INFO }, + { "TokenHyperlinkStart", TOKEN_LINK_START }, + { "TokenHyperlinkEnd", TOKEN_LINK_END }, + { "TokenBibliographyDataField", TOKEN_AUTHORITY }, + { nullptr, static_cast<enum FormTokenType>(0) } +}; + +void SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::replaceByIndex( + sal_Int32 nIndex, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + + SwTOXBase & rTOXBase( m_xParent->m_pImpl->GetTOXSectionOrThrow() ); + + if ((nIndex < 0) || (nIndex > rTOXBase.GetTOXForm().GetFormMax())) + { + throw lang::IndexOutOfBoundsException(); + } + + uno::Sequence<beans::PropertyValues> aSeq; + if(!(rElement >>= aSeq)) + { + throw lang::IllegalArgumentException(); + } + + OUStringBuffer sPattern; + for(const beans::PropertyValues& rToken : std::as_const(aSeq)) + { + const beans::PropertyValue* pProperties = rToken.getConstArray(); + const sal_Int32 nProperties = rToken.getLength(); + //create an invalid token + SwFormToken aToken(TOKEN_END); + for(sal_Int32 j = 0; j < nProperties; j++) + { + if ( pProperties[j].Name == "TokenType" ) + { + const OUString sTokenType = + lcl_AnyToType<OUString>(pProperties[j].Value); + for (TokenType_ const* pTokenType = g_TokenTypes; + pTokenType->pName; ++pTokenType) + { + if (sTokenType.equalsAscii(pTokenType->pName)) + { + aToken.eTokenType = pTokenType->eTokenType; + break; + } + } + } + else if ( pProperties[j].Name == "CharacterStyleName" ) + { + OUString sCharStyleName; + SwStyleNameMapper::FillUIName( + lcl_AnyToType<OUString>(pProperties[j].Value), + sCharStyleName, + SwGetPoolIdFromName::ChrFmt); + aToken.sCharStyleName = sCharStyleName; + aToken.nPoolId = SwStyleNameMapper::GetPoolIdFromUIName ( + sCharStyleName, SwGetPoolIdFromName::ChrFmt ); + } + else if ( pProperties[j].Name == "TabStopRightAligned" ) + { + const bool bRight = lcl_AnyToType<bool>(pProperties[j].Value); + aToken.eTabAlign = bRight ? + SvxTabAdjust::End : SvxTabAdjust::Left; + } + else if ( pProperties[j].Name == "TabStopPosition" ) + { + sal_Int32 nPosition = 0; + if (!(pProperties[j].Value >>= nPosition)) + { + throw lang::IllegalArgumentException(); + } + nPosition = o3tl::toTwips(nPosition, o3tl::Length::mm100); + if(nPosition < 0) + { + throw lang::IllegalArgumentException(); + } + aToken.nTabStopPosition = nPosition; + } + else if ( pProperties[j].Name == "TabStopFillCharacter" ) + { + const OUString sFillChar = + lcl_AnyToType<OUString>(pProperties[j].Value); + if (sFillChar.getLength() > 1) + { + throw lang::IllegalArgumentException(); + } + aToken.cTabFillChar = + sFillChar.isEmpty() ? ' ' : sFillChar[0]; + } + else if ( pProperties[j].Name == "Text" ) + { + aToken.sText = lcl_AnyToType<OUString>(pProperties[j].Value); + } + else if ( pProperties[j].Name == "ChapterFormat" ) + { + sal_Int16 nFormat = lcl_AnyToType<sal_Int16>(pProperties[j].Value); + switch(nFormat) + { + case text::ChapterFormat::NUMBER: + nFormat = CF_NUMBER; + break; + case text::ChapterFormat::NAME: + nFormat = CF_TITLE; + break; + case text::ChapterFormat::NAME_NUMBER: + nFormat = CF_NUM_TITLE; + break; + case text::ChapterFormat::NO_PREFIX_SUFFIX: + nFormat = CF_NUMBER_NOPREPST; + break; + case text::ChapterFormat::DIGIT: + nFormat = CF_NUM_NOPREPST_TITLE; + break; + default: + throw lang::IllegalArgumentException(); + } + aToken.nChapterFormat = nFormat; + } +// #i53420# + else if ( pProperties[j].Name == "ChapterLevel" ) + { + const sal_Int16 nLevel = lcl_AnyToType<sal_Int16>(pProperties[j].Value); + if( nLevel < 1 || nLevel > MAXLEVEL ) + { + throw lang::IllegalArgumentException(); + } + aToken.nOutlineLevel = nLevel; + } + else if ( pProperties[j].Name == "BibliographyDataField" ) + { + sal_Int16 nType = 0; + pProperties[j].Value >>= nType; + if(nType < 0 || nType > text::BibliographyDataField::LOCAL_URL) + { + throw lang::IllegalArgumentException("BibliographyDataField - wrong value", nullptr, j); + } + aToken.nAuthorityField = nType; + } + // #i21237# + else if ( pProperties[j].Name == "WithTab" ) + { + aToken.bWithTab = lcl_AnyToType<bool>(pProperties[j].Value); + } + + } + //exception if wrong TokenType + if(TOKEN_END <= aToken.eTokenType ) + { + throw lang::IllegalArgumentException(); + } + // set TokenType from TOKEN_ENTRY_TEXT to TOKEN_ENTRY if it is + // not a content index + if(TOKEN_ENTRY_TEXT == aToken.eTokenType && + (TOX_CONTENT != rTOXBase.GetType())) + { + aToken.eTokenType = TOKEN_ENTRY; + } +// #i53420# +// check for chapter format allowed values if it was TOKEN_ENTRY_NO type +// only allowed value are CF_NUMBER and CF_NUM_NOPREPST_TITLE +// reading from file + if( TOKEN_ENTRY_NO == aToken.eTokenType ) + { + switch(aToken.nChapterFormat) + { + case CF_NUMBER: + case CF_NUM_NOPREPST_TITLE: + break; + default: + throw lang::IllegalArgumentException(); + } + } + + if (rTOXBase.GetType() == TOX_CONTENT) + { + if (aToken.eTokenType == TOKEN_LINK_START && aToken.sCharStyleName.isEmpty()) + { + aToken.sCharStyleName = SwResId(STR_POOLCHR_TOXJUMP); + } + } + + sPattern.append(aToken.GetString()); + } + SwForm aForm(rTOXBase.GetTOXForm()); + aForm.SetPattern(o3tl::narrowing<sal_uInt16>(nIndex), sPattern.makeStringAndClear()); + rTOXBase.SetTOXForm(aForm); +} + +sal_Int32 SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::getCount() +{ + SolarMutexGuard aGuard; + + const sal_Int32 nRet = m_xParent->m_pImpl->GetFormMax(); + return nRet; +} + +uno::Any SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + + SwTOXBase & rTOXBase( m_xParent->m_pImpl->GetTOXSectionOrThrow() ); + + if ((nIndex < 0) || (nIndex > rTOXBase.GetTOXForm().GetFormMax())) + { + throw lang::IndexOutOfBoundsException(); + } + + // #i21237# + SwFormTokens aPattern = rTOXBase.GetTOXForm(). + GetPattern(o3tl::narrowing<sal_uInt16>(nIndex)); + + sal_Int32 nTokenCount = 0; + uno::Sequence< beans::PropertyValues > aRetSeq; + OUString aProgCharStyle; + for(const SwFormToken& aToken : aPattern) // #i21237# + { + nTokenCount++; + aRetSeq.realloc(nTokenCount); + beans::PropertyValues* pTokenProps = aRetSeq.getArray(); + + uno::Sequence< beans::PropertyValue >& rCurTokenSeq = + pTokenProps[nTokenCount-1]; + SwStyleNameMapper::FillProgName( + aToken.sCharStyleName, + aProgCharStyle, + SwGetPoolIdFromName::ChrFmt); + switch(aToken.eTokenType) + { + case TOKEN_ENTRY_NO: + { +// #i53420# +// writing to file (from doc to properties) + sal_Int32 nElements = 2; + sal_Int32 nCurrentElement = 0; + + // check for default value + if (aToken.nChapterFormat != CF_NUMBER) + { + nElements++;//we need the element + } + if( aToken.nOutlineLevel != MAXLEVEL ) + { + nElements++; + } + + rCurTokenSeq.realloc( nElements ); + + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[nCurrentElement].Name = "TokenType"; + pArr[nCurrentElement++].Value <<= + OUString("TokenEntryNumber"); + + pArr[nCurrentElement].Name = "CharacterStyleName"; + pArr[nCurrentElement++].Value <<= aProgCharStyle; + if( aToken.nChapterFormat != CF_NUMBER ) + { + pArr[nCurrentElement].Name = "ChapterFormat"; + sal_Int16 nVal; +// the allowed values for chapter format, when used as entry number, +// are CF_NUMBER and CF_NUM_NOPREPST_TITLE only, all else forced to +//CF_NUMBER + switch(aToken.nChapterFormat) + { + default: + case CF_NUMBER: + nVal = text::ChapterFormat::NUMBER; + break; + case CF_NUM_NOPREPST_TITLE: + nVal = text::ChapterFormat::DIGIT; + break; + } + pArr[nCurrentElement++].Value <<= nVal; + } + + // only a ChapterLevel != MAXLEVEL is registered + if (aToken.nOutlineLevel != MAXLEVEL) + { + pArr[nCurrentElement].Name = "ChapterLevel"; + pArr[nCurrentElement].Value <<= aToken.nOutlineLevel; + } + } + break; + case TOKEN_ENTRY: // no difference between Entry and Entry Text + case TOKEN_ENTRY_TEXT: + { + rCurTokenSeq.realloc( 2 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= OUString("TokenEntryText"); + + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + } + break; + case TOKEN_TAB_STOP: + { + rCurTokenSeq.realloc(5); // #i21237# + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= OUString("TokenTabStop"); + + if(SvxTabAdjust::End == aToken.eTabAlign) + { + pArr[1].Name = "TabStopRightAligned"; + pArr[1].Value <<= true; + } + else + { + pArr[1].Name = "TabStopPosition"; + sal_Int32 nPos = convertTwipToMm100(aToken.nTabStopPosition); + if(nPos < 0) + nPos = 0; + pArr[1].Value <<= nPos; + } + pArr[2].Name = "TabStopFillCharacter"; + pArr[2].Value <<= OUString(aToken.cTabFillChar); + pArr[3].Name = "CharacterStyleName"; + pArr[3].Value <<= aProgCharStyle; + // #i21237# + pArr[4].Name = "WithTab"; + pArr[4].Value <<= aToken.bWithTab; + } + break; + case TOKEN_TEXT: + { + rCurTokenSeq.realloc( 3 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= OUString("TokenText"); + + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + + pArr[2].Name = "Text"; + pArr[2].Value <<= aToken.sText; + } + break; + case TOKEN_PAGE_NUMS: + { + rCurTokenSeq.realloc( 2 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= OUString("TokenPageNumber"); + + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + } + break; + case TOKEN_CHAPTER_INFO: + { + rCurTokenSeq.realloc( 4 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= OUString("TokenChapterInfo"); + + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + + pArr[2].Name = "ChapterFormat"; + sal_Int16 nVal = text::ChapterFormat::NUMBER; + switch(aToken.nChapterFormat) + { + case CF_NUMBER: + nVal = text::ChapterFormat::NUMBER; + break; + case CF_TITLE: + nVal = text::ChapterFormat::NAME; + break; + case CF_NUM_TITLE: + nVal = text::ChapterFormat::NAME_NUMBER; + break; + case CF_NUMBER_NOPREPST: + nVal = text::ChapterFormat::NO_PREFIX_SUFFIX; + break; + case CF_NUM_NOPREPST_TITLE: + nVal = text::ChapterFormat::DIGIT; + break; + } + pArr[2].Value <<= nVal; +// #i53420# + pArr[3].Name = "ChapterLevel"; + pArr[3].Value <<= aToken.nOutlineLevel; + } + break; + case TOKEN_LINK_START: + { + rCurTokenSeq.realloc( 2 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= + OUString("TokenHyperlinkStart"); + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + } + break; + case TOKEN_LINK_END: + { + rCurTokenSeq.realloc( 1 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= + OUString("TokenHyperlinkEnd"); + } + break; + case TOKEN_AUTHORITY: + { + rCurTokenSeq.realloc( 3 ); + beans::PropertyValue* pArr = rCurTokenSeq.getArray(); + + pArr[0].Name = "TokenType"; + pArr[0].Value <<= + OUString("TokenBibliographyDataField"); + + pArr[1].Name = "CharacterStyleName"; + pArr[1].Value <<= aProgCharStyle; + + pArr[2].Name = "BibliographyDataField"; + pArr[2].Value <<= sal_Int16(aToken.nAuthorityField); + } + break; + + default: + ; + } + } + + uno::Any aRet; + aRet <<= aRetSeq; + return aRet; +} + +uno::Type SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::getElementType() +{ + return cppu::UnoType<uno::Sequence< beans::PropertyValues >>::get(); +} + +sal_Bool SAL_CALL +SwXDocumentIndex::TokenAccess_Impl::hasElements() +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unolinebreak.cxx b/sw/source/core/unocore/unolinebreak.cxx new file mode 100644 index 0000000000..d040113290 --- /dev/null +++ b/sw/source/core/unocore/unolinebreak.cxx @@ -0,0 +1,283 @@ +/* -*- 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 <unolinebreak.hxx> + +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> +#include <svl/listener.hxx> +#include <svl/itemprop.hxx> + +#include <IDocumentContentOperations.hxx> +#include <doc.hxx> +#include <formatlinebreak.hxx> +#include <unotextrange.hxx> +#include <ndtxt.hxx> +#include <textlinebreak.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> + +using namespace com::sun::star; + +/// The inner part SwXLineBreak, which is deleted with a locked SolarMutex. +class SwXLineBreak::Impl : public SvtListener +{ +public: + bool m_bIsDescriptor; + SwFormatLineBreak* m_pFormatLineBreak; + SwLineBreakClear m_eClear; + + Impl(SwFormatLineBreak* const pLineBreak) + : m_bIsDescriptor(pLineBreak == nullptr) + , m_pFormatLineBreak(pLineBreak) + , m_eClear(SwLineBreakClear::NONE) + { + if (m_pFormatLineBreak) + { + StartListening(m_pFormatLineBreak->GetNotifier()); + } + } + + const SwFormatLineBreak* GetLineBreakFormat() const; + + const SwFormatLineBreak& GetLineBreakFormatOrThrow() const; + + void Invalidate(); + +protected: + void Notify(const SfxHint& rHint) override; +}; + +const SwFormatLineBreak* SwXLineBreak::Impl::GetLineBreakFormat() const +{ + return m_pFormatLineBreak; +} + +const SwFormatLineBreak& SwXLineBreak::Impl::GetLineBreakFormatOrThrow() const +{ + const SwFormatLineBreak* pLineBreak(GetLineBreakFormat()); + if (!pLineBreak) + { + throw uno::RuntimeException("SwXLineBreak: disposed or invalid", nullptr); + } + + return *pLineBreak; +} + +void SwXLineBreak::Impl::Invalidate() +{ + EndListeningAll(); + m_pFormatLineBreak = nullptr; +} + +void SwXLineBreak::Impl::Notify(const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::Dying) + { + Invalidate(); + } +} + +SwXLineBreak::SwXLineBreak(SwFormatLineBreak& rFormat) + : m_pImpl(new SwXLineBreak::Impl(&rFormat)) +{ +} + +SwXLineBreak::SwXLineBreak() + : m_pImpl(new SwXLineBreak::Impl(nullptr)) +{ +} + +SwXLineBreak::~SwXLineBreak() {} + +rtl::Reference<SwXLineBreak> SwXLineBreak::CreateXLineBreak(SwFormatLineBreak* pLineBreakFormat) +{ + rtl::Reference<SwXLineBreak> xLineBreak; + if (pLineBreakFormat) + { + xLineBreak = pLineBreakFormat->GetXTextContent(); + } + if (!xLineBreak.is()) + { + xLineBreak = pLineBreakFormat ? new SwXLineBreak(*pLineBreakFormat) : new SwXLineBreak; + if (pLineBreakFormat) + { + pLineBreakFormat->SetXLineBreak(xLineBreak); + } + } + return xLineBreak; +} + +OUString SAL_CALL SwXLineBreak::getImplementationName() { return "SwXLineBreak"; } + +sal_Bool SAL_CALL SwXLineBreak::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL SwXLineBreak::getSupportedServiceNames() +{ + return { "com.sun.star.text.LineBreak" }; +} + +void SAL_CALL SwXLineBreak::attach(const uno::Reference<text::XTextRange>& xTextRange) +{ + SolarMutexGuard aGuard; + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + auto pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + if (!pRange) + { + throw lang::IllegalArgumentException(); + } + + SwDoc& rNewDoc = pRange->GetDoc(); + SwUnoInternalPaM aPam(rNewDoc); + sw::XTextRangeToSwPaM(aPam, xTextRange); + UnoActionContext aContext(&rNewDoc); + SwFormatLineBreak aLineBreak(m_pImpl->m_eClear); + SetAttrMode nInsertFlags = SetAttrMode::DEFAULT; + rNewDoc.getIDocumentContentOperations().InsertPoolItem(aPam, aLineBreak, nInsertFlags); + auto pTextAttr + = static_cast<SwTextLineBreak*>(aPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt( + aPam.GetPoint()->GetContentIndex() - 1, RES_TXTATR_LINEBREAK)); + if (pTextAttr) + { + m_pImpl->EndListeningAll(); + auto pLineBreak = const_cast<SwFormatLineBreak*>(&pTextAttr->GetLineBreak()); + m_pImpl->m_pFormatLineBreak = pLineBreak; + m_pImpl->StartListening(pLineBreak->GetNotifier()); + } + m_pImpl->m_bIsDescriptor = false; +} + +uno::Reference<text::XTextRange> SAL_CALL SwXLineBreak::getAnchor() +{ + SolarMutexGuard aGuard; + + return m_pImpl->GetLineBreakFormatOrThrow().GetAnchor(); +} + +void SAL_CALL SwXLineBreak::dispose() +{ + SAL_WARN("sw.uno", "SwXLineBreak::dispose: not implemented"); +} + +void SAL_CALL +SwXLineBreak::addEventListener(const uno::Reference<lang::XEventListener>& /*xListener*/) +{ +} + +void SAL_CALL +SwXLineBreak::removeEventListener(const uno::Reference<lang::XEventListener>& /*xListener*/) +{ +} + +uno::Reference<beans::XPropertySetInfo> SAL_CALL SwXLineBreak::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + + static uno::Reference<beans::XPropertySetInfo> xRet + = aSwMapProvider.GetPropertySet(PROPERTY_MAP_LINEBREAK)->getPropertySetInfo(); + return xRet; +} + +void SAL_CALL SwXLineBreak::setPropertyValue(const OUString& rPropertyName, + const css::uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + if (rPropertyName != UNO_NAME_CLEAR) + { + throw lang::IllegalArgumentException(); + } + + if (m_pImpl->m_bIsDescriptor) + { + sal_Int16 eValue{}; + if (rValue >>= eValue) + { + m_pImpl->m_eClear = static_cast<SwLineBreakClear>(eValue); + } + } + else + { + m_pImpl->m_pFormatLineBreak->PutValue(rValue, 0); + } +} + +uno::Any SAL_CALL SwXLineBreak::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + if (sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + return aRet; + } + + if (rPropertyName != UNO_NAME_CLEAR) + { + throw beans::UnknownPropertyException(rPropertyName); + } + + if (m_pImpl->m_bIsDescriptor) + { + auto eValue = static_cast<sal_Int16>(m_pImpl->m_eClear); + aRet <<= eValue; + } + else + { + aRet <<= m_pImpl->m_pFormatLineBreak->GetEnumValue(); + } + return aRet; +} + +void SAL_CALL SwXLineBreak::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXLineBreak::addPropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXLineBreak::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXLineBreak::removePropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXLineBreak::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXLineBreak::addVetoableChangeListener: not implemented"); +} + +void SAL_CALL SwXLineBreak::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXLineBreak::removeVetoableChangeListener: not implemented"); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx new file mode 100644 index 0000000000..3004fb684e --- /dev/null +++ b/sw/source/core/unocore/unomap.cxx @@ -0,0 +1,1558 @@ +/* -*- 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 <hintids.hxx> + +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/i18n/XForbiddenCharacters.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/table/BorderLine.hpp> +#include <com/sun/star/text/PageNumberType.hpp> +#include <com/sun/star/text/TableColumnSeparator.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/XDependentTextField.hpp> +#include <com/sun/star/text/XDocumentIndexMark.hpp> +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/XTheme.hpp> +#include <com/sun/star/util/XComplexColor.hpp> +#include <com/sun/star/view/PaperOrientation.hpp> +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <osl/diagnose.h> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unomid.h> +#include <cmdid.h> +#include <unofldmid.h> +#include <editeng/memberids.h> +#include <editeng/unoprnms.hxx> +#include <svl/itemprop.hxx> +#include "unomapproperties.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +#define COMMON_FLDTYP_PROPERTIES \ + { UNO_NAME_IS_FIELD_USED, FIELD_PROP_IS_FIELD_USED, cppu::UnoType<float>::get(), PropertyAttribute::READONLY, 0},\ + { UNO_NAME_IS_FIELD_DISPLAYED, FIELD_PROP_IS_FIELD_DISPLAYED, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::READONLY, 0},\ + { UNO_NAME_TITLE, FIELD_PROP_TITLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},\ + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetPropertyMapEntries(sal_uInt16 nPropertyId) +{ + OSL_ENSURE(nPropertyId < PROPERTY_MAP_END, "Id ?" ); + if( m_aMapEntriesArr[ nPropertyId ].empty() ) + { + switch(nPropertyId) + { + case PROPERTY_MAP_TEXT_CURSOR: + { + m_aMapEntriesArr[nPropertyId] = GetTextCursorPropertyMap(); + } + break; + case PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE: + { + m_aMapEntriesArr[nPropertyId] = GetAccessibilityTextAttrPropertyMap(); + } + break; + case PROPERTY_MAP_PARAGRAPH: + { + m_aMapEntriesArr[nPropertyId] = GetParagraphPropertyMap(); + } + break; + case PROPERTY_MAP_PARA_AUTO_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetAutoParaStylePropertyMap(); + } + break; + case PROPERTY_MAP_CHAR_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetCharStylePropertyMap(); + } + break; + case PROPERTY_MAP_CHAR_AUTO_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetAutoCharStylePropertyMap(); + } + break; + case PROPERTY_MAP_RUBY_AUTO_STYLE : + { + static SfxItemPropertyMapEntry const aAutoRubyStyleMap [] = + { + { UNO_NAME_RUBY_ADJUST, RES_TXTATR_CJK_RUBY, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_ADJUST }, + { UNO_NAME_RUBY_IS_ABOVE, RES_TXTATR_CJK_RUBY, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_ABOVE }, + { UNO_NAME_RUBY_POSITION, RES_TXTATR_CJK_RUBY, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_POSITION }, + }; + m_aMapEntriesArr[nPropertyId] = aAutoRubyStyleMap; + } + break; + case PROPERTY_MAP_PARA_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetParaStylePropertyMap(); + } + break; + case PROPERTY_MAP_CONDITIONAL_PARA_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetConditionalParaStylePropertyMap(); + } + break; + case PROPERTY_MAP_FRAME_STYLE: + { + m_aMapEntriesArr[nPropertyId] = GetFrameStylePropertyMap(); + } + break; + case PROPERTY_MAP_PAGE_STYLE : + { + m_aMapEntriesArr[nPropertyId] = GetPageStylePropertyMap(); + } + break; + case PROPERTY_MAP_NUM_STYLE : + { + static SfxItemPropertyMapEntry const aNumStyleMap [] = + { + { UNO_NAME_NUMBERING_RULES, FN_UNO_NUM_RULES, cppu::UnoType<css::container::XIndexReplace>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_HIDDEN, FN_UNO_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_STYLE_INTEROP_GRAB_BAG, FN_UNO_STYLE_INTEROP_GRAB_BAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aNumStyleMap; + } + break; + case PROPERTY_MAP_TEXT_TABLE : + { + m_aMapEntriesArr[nPropertyId] = GetTablePropertyMap(); + } + break; + case PROPERTY_MAP_TABLE_CELL : + { + static SfxItemPropertyMapEntry const aCellMap_Impl[] = + { + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_NUMBER_FORMAT, RES_BOXATR_FORMAT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID ,0 }, + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_TOP_COLOR }, + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_BOTTOM_COLOR }, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_TEXT_SECTION, FN_UNO_TEXT_SECTION, cppu::UnoType<css::text::XTextSection>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_IS_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), 0, MID_PROTECT_CONTENT}, + { UNO_NAME_CELL_NAME, FN_UNO_CELL_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY,0}, + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_ORIENT }, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_ROW_SPAN, FN_UNO_CELL_ROW_SPAN, cppu::UnoType<sal_Int32>::get(), 0, 0 }, + { UNO_NAME_CELL_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_PARENT_TEXT, FN_UNO_PARENT_TEXT, cppu::UnoType<text::XText>::get(), PropertyAttribute::MAYBEVOID | PropertyAttribute::READONLY, 0 }, + { UNO_NAME_HAS_TEXT_CHANGES_ONLY, RES_PRINT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + REDLINE_NODE_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aCellMap_Impl; + } + break; + case PROPERTY_MAP_TABLE_RANGE: + { + m_aMapEntriesArr[nPropertyId] = GetRangePropertyMap(); + } + break; + case PROPERTY_MAP_SECTION: + { + m_aMapEntriesArr[nPropertyId] = GetSectionPropertyMap(); + } + break; + case PROPERTY_MAP_TEXT_SEARCH: + { + static SfxItemPropertyMapEntry const aSearchPropertyMap_Impl[] = + { + { UNO_NAME_SEARCH_ALL, WID_SEARCH_ALL, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_BACKWARDS, WID_BACKWARDS, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_CASE_SENSITIVE, WID_CASE_SENSITIVE, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_REGULAR_EXPRESSION, WID_REGULAR_EXPRESSION, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_SIMILARITY, WID_SIMILARITY, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_SIMILARITY_ADD, WID_SIMILARITY_ADD, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_SIMILARITY_EXCHANGE, WID_SIMILARITY_EXCHANGE,cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_SIMILARITY_RELAX, WID_SIMILARITY_RELAX, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_SIMILARITY_REMOVE, WID_SIMILARITY_REMOVE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_STYLES, WID_STYLES, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEARCH_WORDS, WID_WORDS, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aSearchPropertyMap_Impl; + } + break; + case PROPERTY_MAP_TEXT_FRAME: + { + m_aMapEntriesArr[nPropertyId] = GetFramePropertyMap(); + } + break; + case PROPERTY_MAP_TEXT_GRAPHIC: + { + m_aMapEntriesArr[nPropertyId] = GetGraphicPropertyMap(); + } + break; + case PROPERTY_MAP_EMBEDDED_OBJECT: + { + m_aMapEntriesArr[nPropertyId] = GetEmbeddedPropertyMap(); + } + break; + case PROPERTY_MAP_TEXT_PAGE: + { + static SfxItemPropertyMapEntry const aPageMap_Impl[] = + { + { u"BorderBottom"_ustr, WID_PAGE_BOTTOM, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"BorderLeft"_ustr, WID_PAGE_LEFT, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"BorderRight"_ustr, WID_PAGE_RIGHT, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"BorderTop"_ustr, WID_PAGE_TOP, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"Height"_ustr, WID_PAGE_HEIGHT, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"Width"_ustr, WID_PAGE_WIDTH, ::cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"Number"_ustr, WID_PAGE_NUMBER, ::cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"Orientation"_ustr, WID_PAGE_ORIENT, ::cppu::UnoType<view::PaperOrientation>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { u"UserDefinedAttributes"_ustr, WID_PAGE_USERATTRIBS, ::cppu::UnoType<container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"IsBackgroundDark"_ustr, WID_PAGE_ISDARK, ::cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { u"NavigationOrder"_ustr, WID_NAVORDER, ::cppu::UnoType<container::XIndexAccess>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"BackgroundFullSize"_ustr, WID_PAGE_BACKFULL, ::cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0}, + { u"Theme"_ustr, WID_PAGE_THEME, cppu::UnoType<util::XTheme>::get(), PropertyAttribute::MAYBEVOID, 0} + }; + m_aMapEntriesArr[nPropertyId] = aPageMap_Impl; + } + break; + case PROPERTY_MAP_TEXT_SHAPE: + { + static SfxItemPropertyMapEntry const aShapeMap_Impl[] = + { + { UNO_NAME_ANCHOR_PAGE_NO, RES_ANCHOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_ANCHOR_PAGENUM }, + { UNO_NAME_ANCHOR_TYPE, RES_ANCHOR, cppu::UnoType<css::text::TextContentAnchorType>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_ANCHOR_ANCHORTYPE}, + { UNO_NAME_ANCHOR_FRAME, RES_ANCHOR, cppu::UnoType<css::text::XTextFrame>::get(), PropertyAttribute::MAYBEVOID, MID_ANCHOR_ANCHORFRAME}, + { UNO_NAME_HORI_ORIENT, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_HORIORIENT_ORIENT }, + { UNO_NAME_HORI_ORIENT_POSITION, RES_HORI_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_HORIORIENT_POSITION|CONVERT_TWIPS }, + { UNO_NAME_HORI_ORIENT_RELATION, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_HORIORIENT_RELATION }, + { UNO_NAME_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_SURROUND, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_SURROUND_SURROUNDTYPE }, + { UNO_NAME_TEXT_WRAP, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE, MID_SURROUND_SURROUNDTYPE }, + { UNO_NAME_SURROUND_ANCHORONLY, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID, MID_SURROUND_ANCHORONLY }, + { UNO_NAME_SURROUND_CONTOUR, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUR }, + { UNO_NAME_CONTOUR_OUTSIDE, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUROUTSIDE }, + { UNO_NAME_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_VERTORIENT_ORIENT }, + { UNO_NAME_VERT_ORIENT_POSITION, RES_VERT_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_VERTORIENT_POSITION|CONVERT_TWIPS }, + { UNO_NAME_VERT_ORIENT_RELATION, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE|PropertyAttribute::MAYBEVOID ,MID_VERTORIENT_RELATION }, + { UNO_NAME_TEXT_RANGE, FN_TEXT_RANGE, cppu::UnoType<css::text::XTextRange>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_OPAQUE, RES_OPAQUE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_ANCHOR_POSITION, FN_ANCHOR_POSITION, cppu::UnoType<css::awt::Point>::get(), PropertyAttribute::READONLY, 0}, + // #i26791# + { UNO_NAME_IS_FOLLOWING_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FOLLOW_TEXT_FLOW}, + // #i28701# + { UNO_NAME_WRAP_INFLUENCE_ON_POSITION, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, MID_WRAP_INFLUENCE}, + { UNO_NAME_ALLOW_OVERLAP, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_ALLOW_OVERLAP}, + // #i28749# + { UNO_NAME_TRANSFORMATION_IN_HORI_L2R, + FN_SHAPE_TRANSFORMATION_IN_HORI_L2R, + cppu::UnoType<css::drawing::HomogenMatrix3>::get(), + PropertyAttribute::READONLY, 0}, + { UNO_NAME_POSITION_LAYOUT_DIR, + FN_SHAPE_POSITION_LAYOUT_DIR, + cppu::UnoType<sal_Int16>::get(), + PROPERTY_NONE, 0}, + // #i36248# + { UNO_NAME_STARTPOSITION_IN_HORI_L2R, + FN_SHAPE_STARTPOSITION_IN_HORI_L2R, + cppu::UnoType<css::awt::Point>::get(), + PropertyAttribute::READONLY, 0}, + { UNO_NAME_ENDPOSITION_IN_HORI_L2R, + FN_SHAPE_ENDPOSITION_IN_HORI_L2R, + cppu::UnoType<css::awt::Point>::get(), + PropertyAttribute::READONLY, 0}, + // #i71182# + // missing map entry for property <PageToggle> + { UNO_NAME_PAGE_TOGGLE, RES_HORI_ORIENT, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_HORIORIENT_PAGETOGGLE }, + { UNO_NAME_RELATIVE_HEIGHT, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT }, + { UNO_NAME_RELATIVE_HEIGHT_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT_RELATION }, + { UNO_NAME_RELATIVE_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH }, + { UNO_NAME_RELATIVE_WIDTH_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH_RELATION }, + { UNO_NAME_TEXT_BOX, FN_TEXT_BOX, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TEXT_BOX}, + { UNO_NAME_TEXT_BOX_CONTENT, FN_TEXT_BOX, cppu::UnoType<text::XTextFrame>::get(), PROPERTY_NONE, MID_TEXT_BOX_CONTENT}, + { UNO_NAME_CHAIN_NEXT_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_NEXTNAME}, + { UNO_NAME_CHAIN_PREV_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_PREVNAME}, + { UNO_NAME_CHAIN_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_NAME }, + }; + m_aMapEntriesArr[nPropertyId] = aShapeMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_MARK: + { + m_aMapEntriesArr[nPropertyId] = GetIndexMarkPropertyMap(); + } + break; + case PROPERTY_MAP_CNTIDX_MARK: + { + m_aMapEntriesArr[nPropertyId] = GetContentMarkPropertyMap(); + } + break; + case PROPERTY_MAP_USER_MARK: + { + m_aMapEntriesArr[nPropertyId] = GetUserMarkPropertyMap(); + } + break; + case PROPERTY_MAP_INDEX_IDX: + { + static SfxItemPropertyMapEntry const aTOXIndexMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_ALPHABETICAL_SEPARATORS, WID_USE_ALPHABETICAL_SEPARATORS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_KEY_AS_ENTRY, WID_USE_KEY_AS_ENTRY , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_COMBINED_ENTRIES, WID_USE_COMBINED_ENTRIES , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_CASE_SENSITIVE, WID_IS_CASE_SENSITIVE , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_P_P, WID_USE_P_P , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_DASH, WID_USE_DASH , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_UPPER_CASE, WID_USE_UPPER_CASE , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_MAIN_ENTRY_CHARACTER_STYLE_NAME, WID_MAIN_ENTRY_CHARACTER_STYLE_NAME , cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLESEPARATOR, WID_PARA_SEP, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL2, WID_PARA_LEV2, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL3, WID_PARA_LEV3, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_IS_COMMA_SEPARATED, WID_IS_COMMA_SEPARATED, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_DOCUMENT_INDEX_MARKS, WID_INDEX_MARKS, cppu::UnoType< cppu::UnoSequenceType<css::text::XDocumentIndexMark> >::get(), PropertyAttribute::READONLY ,0 }, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_LOCALE, WID_IDX_LOCALE, cppu::UnoType<css::lang::Locale>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SORT_ALGORITHM, WID_IDX_SORT_ALGORITHM, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aTOXIndexMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_CNTNT: + { + static SfxItemPropertyMapEntry const aTOXContentMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_LEVEL, WID_LEVEL , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_MARKS, WID_CREATE_FROM_MARKS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_HIDE_TAB_LEADER_AND_PAGE_NUMBERS, WID_HIDE_TABLEADER_PAGENUMBERS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TAB_IN_TOC, WID_TAB_IN_TOC, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_BOOKMARK, WID_TOC_BOOKMARK, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_NEWLINE, WID_TOC_NEWLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_PARAGRAPH_OUTLINE_LEVEL, WID_TOC_PARAGRAPH_OUTLINE_LEVEL, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_OUTLINE, WID_CREATE_FROM_OUTLINE , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_PARAGRAPH_STYLES, WID_LEVEL_PARAGRAPH_STYLES , cppu::UnoType<css::container::XIndexReplace>::get() , PropertyAttribute::READONLY, 0}, + { UNO_NAME_CREATE_FROM_LEVEL_PARAGRAPH_STYLES, WID_CREATE_FROM_PARAGRAPH_STYLES, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE ,MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL2, WID_PARA_LEV2, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL3, WID_PARA_LEV3, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL4, WID_PARA_LEV4, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL5, WID_PARA_LEV5, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL6, WID_PARA_LEV6, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL7, WID_PARA_LEV7, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL8, WID_PARA_LEV8, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL9, WID_PARA_LEV9, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL10, WID_PARA_LEV10, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DOCUMENT_INDEX_MARKS, WID_INDEX_MARKS, cppu::UnoType< cppu::UnoSequenceType<css::text::XDocumentIndexMark> >::get(), PropertyAttribute::READONLY ,0 }, + }; + m_aMapEntriesArr[nPropertyId] = aTOXContentMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_USER: + { + static SfxItemPropertyMapEntry const aTOXUserMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_CREATE_FROM_MARKS, WID_CREATE_FROM_MARKS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_HIDE_TAB_LEADER_AND_PAGE_NUMBERS, WID_HIDE_TABLEADER_PAGENUMBERS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TAB_IN_TOC, WID_TAB_IN_TOC, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_BOOKMARK, WID_TOC_BOOKMARK, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_NEWLINE, WID_TOC_NEWLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TOC_PARAGRAPH_OUTLINE_LEVEL, WID_TOC_PARAGRAPH_OUTLINE_LEVEL, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_LEVEL_FROM_SOURCE, WID_USE_LEVEL_FROM_SOURCE , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE,0}, + { UNO_NAME_LEVEL_PARAGRAPH_STYLES, WID_LEVEL_PARAGRAPH_STYLES , cppu::UnoType<css::container::XIndexReplace>::get() , PropertyAttribute::READONLY,0}, + { UNO_NAME_CREATE_FROM_LEVEL_PARAGRAPH_STYLES, WID_CREATE_FROM_PARAGRAPH_STYLES, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_TABLES, WID_CREATE_FROM_TABLES , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_TEXT_FRAMES, WID_CREATE_FROM_TEXT_FRAMES , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_GRAPHIC_OBJECTS, WID_CREATE_FROM_GRAPHIC_OBJECTS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_EMBEDDED_OBJECTS, WID_CREATE_FROM_EMBEDDED_OBJECTS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE ,MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL2, WID_PARA_LEV2, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL3, WID_PARA_LEV3, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL4, WID_PARA_LEV4, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL5, WID_PARA_LEV5, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL6, WID_PARA_LEV6, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL7, WID_PARA_LEV7, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL8, WID_PARA_LEV8, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL9, WID_PARA_LEV9, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL10, WID_PARA_LEV10, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_DOCUMENT_INDEX_MARKS, WID_INDEX_MARKS, cppu::UnoType< cppu::UnoSequenceType<css::text::XDocumentIndexMark> >::get(), PropertyAttribute::READONLY ,0 }, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_USER_INDEX_NAME, WID_USER_IDX_NAME, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aTOXUserMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_TABLES: + { + static SfxItemPropertyMapEntry const aTOXTablesMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_LABELS, WID_CREATE_FROM_LABELS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_PARAGRAPH_STYLE, WID_CREATE_FROM_PARAGRAPH_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LABEL_CATEGORY, WID_LABEL_CATEGORY , cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LABEL_DISPLAY_TYPE, WID_LABEL_DISPLAY_TYPE , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE,0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aTOXTablesMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_OBJECTS: + { + static SfxItemPropertyMapEntry const aTOXObjectsMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_ALPHABETICAL_SEPARATORS, WID_USE_ALPHABETICAL_SEPARATORS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE,0}, + { UNO_NAME_CREATE_FROM_STAR_MATH, WID_CREATE_FROM_STAR_MATH , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_STAR_CHART, WID_CREATE_FROM_STAR_CHART , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_STAR_CALC, WID_CREATE_FROM_STAR_CALC , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_STAR_DRAW, WID_CREATE_FROM_STAR_DRAW , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_OTHER_EMBEDDED_OBJECTS, WID_CREATE_FROM_OTHER_EMBEDDED_OBJECTS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_PARAGRAPH_STYLE, WID_CREATE_FROM_PARAGRAPH_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aTOXObjectsMap_Impl; + } + break; + case PROPERTY_MAP_INDEX_ILLUSTRATIONS: + { + static SfxItemPropertyMapEntry const aTOXIllustrationsMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_CREATE_FROM_CHAPTER, WID_CREATE_FROM_CHAPTER , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_LABELS, WID_CREATE_FROM_LABELS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CREATE_FROM_PARAGRAPH_STYLE, WID_CREATE_FROM_PARAGRAPH_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USE_ALPHABETICAL_SEPARATORS, WID_USE_ALPHABETICAL_SEPARATORS , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LABEL_CATEGORY, WID_LABEL_CATEGORY , cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LABEL_DISPLAY_TYPE, WID_LABEL_DISPLAY_TYPE , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE,0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aTOXIllustrationsMap_Impl; + } + break; + case PROPERTY_MAP_TEXT_TABLE_ROW: + { + static SfxItemPropertyMapEntry const aTableRowPropertyMap_Impl[] = + { + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_TABLE_COLUMN_SEPARATORS, FN_UNO_TABLE_COLUMN_SEPARATORS, cppu::UnoType< cppu::UnoSequenceType<css::text::TableColumnSeparator> >::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_HEIGHT, FN_UNO_ROW_HEIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,CONVERT_TWIPS }, + { UNO_NAME_IS_AUTO_HEIGHT, FN_UNO_ROW_AUTO_HEIGHT, cppu::UnoType<bool>::get(), PROPERTY_NONE , 0 }, + { UNO_NAME_SIZE_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_SIZE_TYPE }, + { UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH_TYPE }, + { UNO_NAME_IS_SPLIT_ALLOWED, RES_ROW_SPLIT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_HAS_TEXT_CHANGES_ONLY, RES_PRINT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_ROW_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, + }; + + m_aMapEntriesArr[nPropertyId] = aTableRowPropertyMap_Impl; + } + break; + case PROPERTY_MAP_TEXT_TABLE_CURSOR: + { + m_aMapEntriesArr[nPropertyId] = GetTextTableCursorPropertyMap(); + } + break; + case PROPERTY_MAP_BOOKMARK: + { + m_aMapEntriesArr[nPropertyId] = GetBookmarkPropertyMap(); + } + break; + case PROPERTY_MAP_FIELDMARK: + { + static SfxItemPropertyMapEntry const aFieldmarkMap_Impl[] = + { + // FIXME: is this supposed to actually exist as UNO property, or is it supposed to be in the "parameters" of the field? + { u"Checked"_ustr, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aFieldmarkMap_Impl; + } + break; + case PROPERTY_MAP_PARAGRAPH_EXTENSIONS: + { + m_aMapEntriesArr[nPropertyId] = GetParagraphExtensionsPropertyMap(); + } + break; + case PROPERTY_MAP_BIBLIOGRAPHY : + { + static SfxItemPropertyMapEntry const aBibliographyMap_Impl[] = + { + BASE_INDEX_PROPERTIES_ + { UNO_NAME_IS_PROTECTED, WID_PROTECTED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_PARA_STYLEHEADING, WID_PARA_HEAD, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_PARA_STYLELEVEL1, WID_PARA_LEV1, cppu::UnoType<OUString>::get() , 0, 0}, + { UNO_NAME_LEVEL_FORMAT, WID_LEVEL_FORMAT , cppu::UnoType<css::container::XIndexReplace>::get() , PROPERTY_NONE,0}, + { UNO_NAME_LOCALE, WID_IDX_LOCALE, cppu::UnoType<css::lang::Locale>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SORT_ALGORITHM, WID_IDX_SORT_ALGORITHM, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aBibliographyMap_Impl; + } + break; + case PROPERTY_MAP_TEXT_DOCUMENT: + { + static SfxItemPropertyMapEntry const aDocMap_Impl[] = + { + { UNO_NAME_BASIC_LIBRARIES, WID_DOC_BASIC_LIBRARIES, cppu::UnoType<css::script::XLibraryContainer>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_CHAR_FONT_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + { UNO_NAME_CHAR_FONT_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + { UNO_NAME_CHAR_FONT_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + { UNO_NAME_CHAR_LOCALE, RES_CHRATR_LANGUAGE , cppu::UnoType<css::lang::Locale>::get(), PropertyAttribute::MAYBEVOID, MID_LANG_LOCALE }, + { UNO_NAME_CHARACTER_COUNT, WID_DOC_CHAR_COUNT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_DIALOG_LIBRARIES, WID_DOC_DIALOG_LIBRARIES, cppu::UnoType<css::script::XLibraryContainer>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_VBA_DOCOBJ, WID_DOC_VBA_DOCOBJ, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_INDEX_AUTO_MARK_FILE_U_R_L, WID_DOC_AUTO_MARK_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PARAGRAPH_COUNT, WID_DOC_PARA_COUNT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_RECORD_CHANGES, WID_DOC_CHANGES_RECORD, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SHOW_CHANGES, WID_DOC_CHANGES_SHOW, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_WORD_COUNT, WID_DOC_WORD_COUNT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_IS_TEMPLATE, WID_DOC_ISTEMPLATEID, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_WORD_SEPARATOR, WID_DOC_WORD_SEPARATOR, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_HIDE_FIELD_TIPS, WID_DOC_HIDE_TIPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_REDLINE_DISPLAY_TYPE, WID_DOC_REDLINE_DISPLAY, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_REDLINE_PROTECTION_KEY, WID_DOC_CHANGES_PASSWORD, cppu::UnoType< cppu::UnoSequenceType<sal_Int8> >::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_FORBIDDEN_CHARACTERS, WID_DOC_FORBIDDEN_CHARS, cppu::UnoType<css::i18n::XForbiddenCharacters>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TWO_DIGIT_YEAR, WID_DOC_TWO_DIGIT_YEAR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_AUTOMATIC_CONTROL_FOCUS, WID_DOC_AUTOMATIC_CONTROL_FOCUS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_APPLY_FORM_DESIGN_MODE, WID_DOC_APPLY_FORM_DESIGN_MODE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_RUNTIME_UID, WID_DOC_RUNTIME_UID, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_LOCK_UPDATES, WID_DOC_LOCK_UPDATES, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { u"UndocumentedWriterfilterHack"_ustr, WID_DOC_WRITERFILTER, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_HAS_VALID_SIGNATURES, WID_DOC_HAS_VALID_SIGNATURES, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_BUILDID, WID_DOC_BUILDID, cppu::UnoType<OUString>::get(), 0, 0}, + { UNO_NAME_DOC_INTEROP_GRAB_BAG, WID_DOC_INTEROP_GRAB_BAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DEFAULT_PAGE_MODE, WID_DOC_DEFAULT_PAGE_MODE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aDocMap_Impl; + } + break; + case PROPERTY_MAP_LINK_TARGET: + { + static SfxItemPropertyMapEntry const aLinkTargetMap_Impl[] = + { + { UNO_LINK_DISPLAY_BITMAP, 0, cppu::UnoType<css::awt::XBitmap>::get(), PropertyAttribute::READONLY, 0xbf}, + { UNO_LINK_DISPLAY_NAME, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0xbf}, + }; + m_aMapEntriesArr[nPropertyId] = aLinkTargetMap_Impl; + } + break; + case PROPERTY_MAP_AUTO_TEXT_GROUP : + { + static SfxItemPropertyMapEntry const aAutoTextGroupMap_Impl[] = + { + { UNO_NAME_FILE_PATH, WID_GROUP_PATH, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_TITLE, WID_GROUP_TITLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aAutoTextGroupMap_Impl; + } + break; + case PROPERTY_MAP_TEXTPORTION_EXTENSIONS: + { + m_aMapEntriesArr[nPropertyId] = GetTextPortionExtensionPropertyMap(); + } + break; + case PROPERTY_MAP_FOOTNOTE: + { + m_aMapEntriesArr[nPropertyId] = GetFootnotePropertyMap(); + } + break; + case PROPERTY_MAP_REDLINE : + { + m_aMapEntriesArr[nPropertyId] = GetRedlinePropertyMap(); + } + break; + case PROPERTY_MAP_TEXT_DEFAULT : + { + std::span<SfxItemPropertyMapEntry> aTextDefaultMap_Impl = GetTextDefaultPropertyMap(); + m_aMapEntriesArr[nPropertyId] = aTextDefaultMap_Impl; + for( auto & rEntry : aTextDefaultMap_Impl ) + { + // UNO_NAME_PAGE_DESC_NAME should keep its MAYBEVOID flag + if (RES_PAGEDESC != rEntry.nWID || MID_PAGEDESC_PAGEDESCNAME != rEntry.nMemberId) + rEntry.nFlags &= ~PropertyAttribute::MAYBEVOID; + } + } + break; + case PROPERTY_MAP_REDLINE_PORTION : + { + m_aMapEntriesArr[nPropertyId] = GetRedlinePortionPropertyMap(); + } + break; + case PROPERTY_MAP_FLDTYP_DATETIME: + { + static SfxItemPropertyMapEntry const aDateTimeFieldPropMap[] = + { + {UNO_NAME_ADJUST, FIELD_PROP_SUBTYPE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATE_TIME_VALUE, FIELD_PROP_DATE_TIME, cppu::UnoType<css::util::DateTime>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + {UNO_NAME_IS_DATE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDateTimeFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_USER : + { + static SfxItemPropertyMapEntry const aUserFieldPropMap[] = + { + {UNO_NAME_IS_SHOW_FORMULA, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_VISIBLE, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + + m_aMapEntriesArr[nPropertyId] = aUserFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_SET_EXP : + { + static SfxItemPropertyMapEntry const aSetExpFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_HINT, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBERING_TYPE, FIELD_PROP_USHORT2, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_INPUT, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + // #i69733# wrong name - UNO_NAME_IS_INPUT expanded to "Input" instead of "IsInput" + {UNO_NAME_INPUT, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_SHOW_FORMULA, FIELD_PROP_BOOL3, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_VISIBLE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SEQUENCE_VALUE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SUB_TYPE, FIELD_PROP_SUBTYPE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_VALUE, FIELD_PROP_DOUBLE, cppu::UnoType<double>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_VARIABLE_NAME, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aSetExpFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_GET_EXP : + { + static SfxItemPropertyMapEntry const aGetExpFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_SHOW_FORMULA, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SUB_TYPE, FIELD_PROP_SUBTYPE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_VALUE, FIELD_PROP_DOUBLE, cppu::UnoType<double>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_VARIABLE_SUBTYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aGetExpFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_FILE_NAME: + { + static SfxItemPropertyMapEntry const aFileNameFieldPropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_FILE_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aFileNameFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_PAGE_NUM : + { + static SfxItemPropertyMapEntry const aPageNumFieldPropMap [] = + { + {UNO_NAME_NUMBERING_TYPE, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_OFFSET, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SUB_TYPE, FIELD_PROP_SUBTYPE, cppu::UnoType<css::text::PageNumberType>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_USERTEXT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aPageNumFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_AUTHOR : + { + static SfxItemPropertyMapEntry const aAuthorFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_FULL_NAME,FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aAuthorFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_CHAPTER : + { + static SfxItemPropertyMapEntry const aChapterFieldPropMap [] = + { + {UNO_NAME_CHAPTER_FORMAT,FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_LEVEL,FIELD_PROP_BYTE1, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aChapterFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_GET_REFERENCE : + { + static SfxItemPropertyMapEntry const aGetRefFieldPropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_REFERENCE_FIELD_PART,FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_REFERENCE_FIELD_SOURCE,FIELD_PROP_USHORT2, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_REFERENCE_FIELD_FLAGS, FIELD_PROP_USHORT3, cppu::UnoType<sal_uInt16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SEQUENCE_NUMBER, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SOURCE_NAME, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_REFERENCE_FIELD_LANGUAGE, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aGetRefFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_CONDITIONED_TEXT : + { + static SfxItemPropertyMapEntry const aConditionedTextFieldPropMap [] = + { + {UNO_NAME_CONDITION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_FALSE_CONTENT, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_CONDITION_TRUE , FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_TRUE_CONTENT , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aConditionedTextFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_HIDDEN_TEXT : + { + static SfxItemPropertyMapEntry const aHiddenTextFieldPropMap [] = + { + {UNO_NAME_CONDITION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONTENT , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_HIDDEN , FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aHiddenTextFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_ANNOTATION : + { + static SfxItemPropertyMapEntry const aAnnotationFieldPropMap [] = + { + {UNO_NAME_AUTHOR, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INITIALS, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PARA_ID_PARENT, FIELD_PROP_PAR5, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PARA_ID, FIELD_PROP_PAR6, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PARENT_NAME, FIELD_PROP_PAR7, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_RESOLVED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATE_TIME_VALUE, FIELD_PROP_DATE_TIME, cppu::UnoType<css::util::DateTime>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATE, FIELD_PROP_DATE, cppu::UnoType<css::util::Date>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_TEXT_RANGE, FIELD_PROP_TEXT, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::READONLY, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aAnnotationFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_INPUT: + { + static SfxItemPropertyMapEntry const aInputFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_HINT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_HELP, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_TOOLTIP, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_MISC_OBJ_INTEROPGRABBAG, FIELD_PROP_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aInputFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_MACRO : + { + static SfxItemPropertyMapEntry const aMacroFieldPropMap [] = + { + {UNO_NAME_HINT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_MACRO_NAME,FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_MACRO_LIBRARY,FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(),PROPERTY_NONE, 0}, + {UNO_NAME_SCRIPT_URL,FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(),PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aMacroFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DDE : + { + static SfxItemPropertyMapEntry const aDDEFieldPropMap [] = + { + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDDEFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DROPDOWN : + { + static SfxItemPropertyMapEntry const aDropDownMap [] = + { + {UNO_NAME_ITEMS, FIELD_PROP_STRINGS, cppu::UnoType< cppu::UnoSequenceType<OUString> >::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SELITEM, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_HELP, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_TOOLTIP, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDropDownMap; + } + break; + case PROPERTY_MAP_FLDTYP_HIDDEN_PARA : + { + static SfxItemPropertyMapEntry const aHiddenParaFieldPropMap [] = + { + {UNO_NAME_CONDITION,FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_HIDDEN , FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aHiddenParaFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOC_INFO : + { + static SfxItemPropertyMapEntry const aDocInfoFieldPropMap [] = + { + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INFO_FORMAT, FIELD_PROP_USHORT2, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INFO_TYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_TEMPLATE_NAME : + { + static SfxItemPropertyMapEntry const aTmplNameFieldPropMap [] = + { + {UNO_NAME_FILE_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aTmplNameFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_USER_EXT : + { + static SfxItemPropertyMapEntry const aUsrExtFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_USER_DATA_TYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId]= aUsrExtFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_REF_PAGE_SET : + { + static SfxItemPropertyMapEntry const aRefPgSetFieldPropMap [] = + { + {UNO_NAME_OFFSET, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_ON, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aRefPgSetFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_REF_PAGE_GET : + { + static SfxItemPropertyMapEntry const aRefPgGetFieldPropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBERING_TYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aRefPgGetFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_JUMP_EDIT : + { + static SfxItemPropertyMapEntry const aJumpEdtFieldPropMap [] = + { + {UNO_NAME_HINT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PLACEHOLDER, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PLACEHOLDER_TYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aJumpEdtFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_SCRIPT : + { + static SfxItemPropertyMapEntry const aScriptFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SCRIPT_TYPE, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_URL_CONTENT, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aScriptFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET : + { + static SfxItemPropertyMapEntry const aDBNextSetFieldPropMap [] = + { + // Note: DATA_BASE_NAME and DATA_BASE_URL + // are mapped to the same nMId, because internally we only use + // them as DataSource and it does not matter which one it is. + + {UNO_NAME_DATA_BASE_NAME , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_TABLE_NAME , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONDITION , FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_BASE_URL , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COMMAND_TYPE, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDBNextSetFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NUM_SET : + { + static SfxItemPropertyMapEntry const aDBNumSetFieldPropMap [] = + { + // Note: DATA_BASE_NAME and DATA_BASE_URL + // are mapped to the same nMId, because internally we only use + // them as DataSource and it does not matter which one it is. + + {UNO_NAME_DATA_BASE_NAME , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_TABLE_NAME, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONDITION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_BASE_URL , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COMMAND_TYPE, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SET_NUMBER, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDBNumSetFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_SET_NUM : + { + static SfxItemPropertyMapEntry const aDBSetNumFieldPropMap [] = + { + // Note: DATA_BASE_NAME and DATA_BASE_URL + // are mapped to the same nMId, because internally we only use + // them as DataSource and it does not matter which one it is. + + {UNO_NAME_DATA_BASE_NAME , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_TABLE_NAME , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_BASE_URL , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COMMAND_TYPE, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBERING_TYPE, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SET_NUMBER, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_VISIBLE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDBSetNumFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE : + { + static SfxItemPropertyMapEntry const aDBFieldPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_FIELD_CODE, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_DATA_BASE_FORMAT,FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_VISIBLE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDBFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NAME : + { + static SfxItemPropertyMapEntry const aDBNameFieldPropMap [] = + { + // Note: DATA_BASE_NAME and DATA_BASE_URL + // are mapped to the same nMId, because internally we only use + // them as DataSource and it does not matter which one it is. + + {UNO_NAME_DATA_BASE_NAME , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_TABLE_NAME , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_BASE_URL , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COMMAND_TYPE, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_VISIBLE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDBNameFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCSTAT: + { + static SfxItemPropertyMapEntry const aDocstatFieldPropMap [] = + { + {UNO_NAME_NUMBERING_TYPE, FIELD_PROP_USHORT2, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + // {UNO_NAME_STATISTIC_TYPE_ID,FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocstatFieldPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR: + { + static SfxItemPropertyMapEntry const aDocInfoAuthorPropMap [] = + { + {UNO_NAME_AUTHOR, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoAuthorPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME: + { + static SfxItemPropertyMapEntry const aDocInfoDateTimePropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATE_TIME_VALUE, FIELD_PROP_DOUBLE, cppu::UnoType<double>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_IS_DATE, FIELD_PROP_BOOL2, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + {UNO_NAME_NUMBER_FORMAT,FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoDateTimePropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME : + { + static SfxItemPropertyMapEntry const aDocInfoEditTimePropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATE_TIME_VALUE, FIELD_PROP_DOUBLE, cppu::UnoType<double>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_NUMBER_FORMAT,FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoEditTimePropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_MISC: + { + static SfxItemPropertyMapEntry const aDocInfoStringContentPropMap [] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoStringContentPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM: + { + static SfxItemPropertyMapEntry const aDocInfoCustomPropMap [] = + { + {UNO_NAME_NAME, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED_LANGUAGE, FIELD_PROP_BOOL4, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoCustomPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_REVISION : + { + static SfxItemPropertyMapEntry const aDocInfoRevisionPropMap [] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_REVISION, FIELD_PROP_USHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_FIXED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get() , PROPERTY_NONE,0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aDocInfoRevisionPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS: + { + static SfxItemPropertyMapEntry const aCombinedCharactersPropMap[] = + { + {UNO_NAME_CONTENT, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aCombinedCharactersPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_TABLE_FORMULA: + { + static SfxItemPropertyMapEntry const aTableFormulaPropMap[] = + { + {UNO_NAME_CURRENT_PRESENTATION, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_SHOW_FORMULA, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBER_FORMAT, FIELD_PROP_FORMAT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aTableFormulaPropMap; + } + break; + case PROPERTY_MAP_FLDTYP_DUMMY_0: + { + static SfxItemPropertyMapEntry const aEmptyPropMap [] = + { + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aEmptyPropMap; + } + break; + case PROPERTY_MAP_FLDMSTR_USER : + { + static SfxItemPropertyMapEntry const aUserFieldTypePropMap[] = + { + {UNO_NAME_DEPENDENT_TEXT_FIELDS, FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::text::XDependentTextField> >::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_IS_EXPRESSION, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + {UNO_NAME_VALUE, FIELD_PROP_DOUBLE, cppu::UnoType<double>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aUserFieldTypePropMap; + } + break; + case PROPERTY_MAP_FLDMSTR_DDE : + { + static SfxItemPropertyMapEntry const aDDEFieldTypePropMap[] = + { + {UNO_NAME_DDE_COMMAND_ELEMENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DDE_COMMAND_FILE, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DDE_COMMAND_TYPE, FIELD_PROP_SUBTYPE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DEPENDENT_TEXT_FIELDS, FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::text::XDependentTextField> >::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_IS_AUTOMATIC_UPDATE, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_CONTENT, FIELD_PROP_PAR5, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aDDEFieldTypePropMap; + } + break; + case PROPERTY_MAP_FLDMSTR_SET_EXP : + { + static SfxItemPropertyMapEntry const aSetExpFieldTypePropMap[] = + { + {UNO_NAME_CHAPTER_NUMBERING_LEVEL,FIELD_PROP_SHORT1, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DEPENDENT_TEXT_FIELDS, FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::text::XDependentTextField> >::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NUMBERING_SEPARATOR, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SUB_TYPE, FIELD_PROP_SUBTYPE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aSetExpFieldTypePropMap; + } + break; + case PROPERTY_MAP_FLDMSTR_DATABASE : + { + static SfxItemPropertyMapEntry const aDBFieldTypePropMap [] = + { + // Note: DATA_BASE_NAME and DATA_BASE_URL + // are mapped to the same nMId, because internally we only use + // them as DataSource and it does not matter which one it is. + + {UNO_NAME_DATA_BASE_NAME , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_NAME, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + {UNO_NAME_DATA_TABLE_NAME, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COLUMN_NAME, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_DATA_BASE_URL , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DATA_COMMAND_TYPE, FIELD_PROP_SHORT1, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_DEPENDENT_TEXT_FIELDS, FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::text::XDependentTextField> >::get(), PropertyAttribute::READONLY, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aDBFieldTypePropMap; + } + break; + case PROPERTY_MAP_FLDMSTR_DUMMY0 : + { + static SfxItemPropertyMapEntry const aStandardFieldMasterMap[] = + { + {UNO_NAME_DEPENDENT_TEXT_FIELDS, 0, cppu::UnoType< cppu::UnoSequenceType<css::text::XDependentTextField> >::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_NAME, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aStandardFieldMasterMap; + } + break; + case PROPERTY_MAP_FLDTYP_BIBLIOGRAPHY: + { + static SfxItemPropertyMapEntry const aBibliographyFieldMap[] = + { + {UNO_NAME_FIELDS , FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(),PROPERTY_NONE, 0}, + COMMON_FLDTYP_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aBibliographyFieldMap; + } + break; + case PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY: + { + static SfxItemPropertyMapEntry const aBibliographyFieldMasterMap[] = + { + {UNO_NAME_BRACKET_BEFORE , FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_BRACKET_AFTER , FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_NUMBER_ENTRIES , FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_SORT_BY_POSITION , FIELD_PROP_BOOL2, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_LOCALE, FIELD_PROP_LOCALE, cppu::UnoType<css::lang::Locale>::get() , PROPERTY_NONE, 0}, + {UNO_NAME_SORT_ALGORITHM, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_SORT_KEYS , FIELD_PROP_PROP_SEQ, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValues> >::get(), PROPERTY_NONE, 0}, + {UNO_NAME_INSTANCE_NAME, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aBibliographyFieldMasterMap; + } + break; + case PROPERTY_MAP_TEXT : + { + static SfxItemPropertyMapEntry const aTextMap[] = + { + REDLINE_NODE_PROPERTIES + }; + m_aMapEntriesArr[nPropertyId] = aTextMap; + } + break; + case PROPERTY_MAP_MAILMERGE : + { + static SfxItemPropertyMapEntry const aMailMergeMap[] = + { + { UNO_NAME_SELECTION, WID_SELECTION, cppu::UnoType< cppu::UnoSequenceType<css::uno::Any> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_RESULT_SET, WID_RESULT_SET, cppu::UnoType<css::sdbc::XResultSet>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CONNECTION, WID_CONNECTION, cppu::UnoType<css::sdbc::XConnection>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_MODEL, WID_MODEL, cppu::UnoType<css::frame::XModel>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_DATA_SOURCE_NAME, WID_DATA_SOURCE_NAME, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DAD_COMMAND, WID_DATA_COMMAND, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_FILTER, WID_FILTER, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DOCUMENT_URL, WID_DOCUMENT_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_OUTPUT_URL, WID_OUTPUT_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DAD_COMMAND_TYPE, WID_DATA_COMMAND_TYPE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_OUTPUT_TYPE, WID_OUTPUT_TYPE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_ESCAPE_PROCESSING, WID_ESCAPE_PROCESSING, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SINGLE_PRINT_JOBS, WID_SINGLE_PRINT_JOBS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_FILE_NAME_FROM_COLUMN, WID_FILE_NAME_FROM_COLUMN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_FILE_NAME_PREFIX, WID_FILE_NAME_PREFIX, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SUBJECT, WID_MAIL_SUBJECT, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_ADDRESS_FROM_COLUMN, WID_ADDRESS_FROM_COLUMN, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SEND_AS_HTML, WID_SEND_AS_HTML, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SEND_AS_ATTACHMENT, WID_SEND_AS_ATTACHMENT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_MAIL_BODY, WID_MAIL_BODY, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_ATTACHMENT_NAME, WID_ATTACHMENT_NAME, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_ATTACHMENT_FILTER, WID_ATTACHMENT_FILTER, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PRINT_OPTIONS, WID_PRINT_OPTIONS, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SAVE_AS_SINGLE_FILE, WID_SAVE_AS_SINGLE_FILE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SAVE_FILTER, WID_SAVE_FILTER, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SAVE_FILTER_OPTIONS, WID_SAVE_FILTER_OPTIONS, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SAVE_FILTER_DATA, WID_SAVE_FILTER_DATA, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_COPIES_TO, WID_COPIES_TO, cppu::UnoType< cppu::UnoSequenceType<OUString> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_BLIND_COPIES_TO, WID_BLIND_COPIES_TO, cppu::UnoType< cppu::UnoSequenceType<OUString> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IN_SERVER_PASSWORD, WID_IN_SERVER_PASSWORD, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_OUT_SERVER_PASSWORD, WID_OUT_SERVER_PASSWORD, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + m_aMapEntriesArr[nPropertyId] = aMailMergeMap; + } + break; + case PROPERTY_MAP_TEXT_VIEW : + { + static SfxItemPropertyMapEntry pTextViewMap[] = + { + {UNO_NAME_PAGE_COUNT, WID_PAGE_COUNT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_LINE_COUNT, WID_LINE_COUNT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_IS_CONSTANT_SPELLCHECK, WID_IS_CONSTANT_SPELLCHECK, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_IS_HIDE_SPELL_MARKS, WID_IS_HIDE_SPELL_MARKS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, // deprecated #i91949 + }; + m_aMapEntriesArr[nPropertyId] = pTextViewMap; + } + break; + case PROPERTY_MAP_CHART2_DATA_SEQUENCE : + { + static SfxItemPropertyMapEntry const aChart2DataSequenceMap[] = + { + {UNO_NAME_ROLE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + }; + m_aMapEntriesArr[nPropertyId] = aChart2DataSequenceMap; + } + break; + case PROPERTY_MAP_METAFIELD: + { + static SfxItemPropertyMapEntry const aMetaFieldMap[] = + { + { UNO_NAME_NUMBER_FORMAT, 0, + cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_IS_FIXED_LANGUAGE, 0, + cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + }; + m_aMapEntriesArr[nPropertyId] = aMetaFieldMap; + } + break; + case PROPERTY_MAP_TABLE_STYLE: + { + static SfxItemPropertyMapEntry const aTableStyleMap[] = + { + { UNO_NAME_TABLE_FIRST_ROW_END_COLUMN, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TABLE_FIRST_ROW_START_COLUMN, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TABLE_LAST_ROW_END_COLUMN, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TABLE_LAST_ROW_START_COLUMN, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DISPLAY_NAME, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 }, + }; + m_aMapEntriesArr[nPropertyId] = aTableStyleMap; + } + break; + case PROPERTY_MAP_CELL_STYLE: + { + static SfxItemPropertyMapEntry const aCellStyleMap[] = + { + // SvxBrushItem + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + // SvxBoxItem + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, LEFT_BORDER|CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, RIGHT_BORDER|CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, TOP_BORDER|CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BORDER_TOP_COLOR }, + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BORDER_BOTTOM_COLOR }, + // SwFormatVertOrient + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_VERTORIENT_ORIENT }, + // SvxFrameDirectionItem + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + // SvNumberformat + { UNO_NAME_NUMBER_FORMAT, RES_BOXATR_FORMAT, cppu::UnoType<sal_Int32>::get(),PropertyAttribute::MAYBEVOID, 0 }, + // SvxAdjustItem + { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(),PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST }, + // SvxColorItem + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE }, + { UNO_NAME_CHAR_COMPLEX_COLOR, RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_COMPLEX_COLOR }, + // SvxShadowedItem + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + // SvxContouredItem + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + // SvxCrossedOutItem + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(),PropertyAttribute::MAYBEVOID, MID_CROSS_OUT }, + // SvxUnderlineItem + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE }, + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE,cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR }, + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_TL_COMPLEX_COLOR }, + { UNO_NAME_CHAR_UNDERLINE_HAS_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR }, + // standard font + // SvxFontHeightItem + { UNO_NAME_CHAR_HEIGHT, RES_CHRATR_FONTSIZE, cppu::UnoType<float>::get(),PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS }, + // SvxWeightItem + { UNO_NAME_CHAR_WEIGHT, RES_CHRATR_WEIGHT, cppu::UnoType<float>::get(),PropertyAttribute::MAYBEVOID, MID_WEIGHT }, + // SvxPostureItem + { UNO_NAME_CHAR_POSTURE, RES_CHRATR_POSTURE, cppu::UnoType<css::awt::FontSlant>::get(),PropertyAttribute::MAYBEVOID, MID_POSTURE }, + // SvxFontItem + { UNO_NAME_CHAR_FONT_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + // cjk font + { UNO_NAME_CHAR_HEIGHT_ASIAN, RES_CHRATR_CJK_FONTSIZE, cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS }, + { UNO_NAME_CHAR_WEIGHT_ASIAN, RES_CHRATR_CJK_WEIGHT, cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT }, + { UNO_NAME_CHAR_POSTURE_ASIAN, RES_CHRATR_CJK_POSTURE, cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE }, + { UNO_NAME_CHAR_FONT_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + // ctl font + { UNO_NAME_CHAR_HEIGHT_COMPLEX, RES_CHRATR_CTL_FONTSIZE, cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS }, + { UNO_NAME_CHAR_WEIGHT_COMPLEX, RES_CHRATR_CTL_WEIGHT, cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT }, + { UNO_NAME_CHAR_POSTURE_COMPLEX, RES_CHRATR_CTL_POSTURE, cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE }, + { UNO_NAME_CHAR_FONT_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, + { UNO_NAME_CHAR_FONT_STYLE_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, + { UNO_NAME_CHAR_FONT_FAMILY_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, + { UNO_NAME_CHAR_FONT_CHAR_SET_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, + { UNO_NAME_CHAR_FONT_PITCH_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, + }; + m_aMapEntriesArr[nPropertyId] = aCellStyleMap; + } + break; + case PROPERTY_MAP_LINEBREAK: + { + m_aMapEntriesArr[nPropertyId] = GetLineBreakPropertyMap(); + } + break; + case PROPERTY_MAP_CONTENTCONTROL: + { + m_aMapEntriesArr[nPropertyId] = GetContentControlPropertyMap(); + } + break; + + default: + OSL_FAIL( "unexpected property map ID" ); + } + } + return m_aMapEntriesArr[nPropertyId]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx new file mode 100644 index 0000000000..ee4422a22e --- /dev/null +++ b/sw/source/core/unocore/unomap1.cxx @@ -0,0 +1,1737 @@ +/* -*- 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 <hintids.hxx> + +#include <svx/unomid.hxx> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/drawing/ColorMode.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/Hatch.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/RectanglePoint.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/style/DropCapFormat.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/PageStyleLayout.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/table/BorderLine.hpp> +#include <com/sun/star/table/ShadowFormat.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <com/sun/star/table/TableBorder2.hpp> +#include <com/sun/star/table/TableBorderDistances.hpp> +#include <com/sun/star/table/XCell.hpp> +#include <com/sun/star/text/GraphicCrop.hpp> +#include <com/sun/star/text/SectionFileLink.hpp> +#include <com/sun/star/text/TableColumnSeparator.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/XDocumentIndex.hpp> +#include <com/sun/star/text/XDocumentIndexMark.hpp> +#include <com/sun/star/text/XFootnote.hpp> +#include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/XComplexColor.hpp> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unomid.h> +#include <cmdid.h> +#include <editeng/memberids.h> +#include <editeng/unoprnms.hxx> +#include <svl/itemprop.hxx> +#include <svx/xdef.hxx> +#include "unomapproperties.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +SwUnoPropertyMapProvider aSwMapProvider; + +SwUnoPropertyMapProvider::SwUnoPropertyMapProvider() +{ + for( sal_uInt16 i = 0; i < PROPERTY_MAP_END; i++ ) + { + m_aPropertySetArr[i] = nullptr; + } +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetTextCursorPropertyMap() +{ + static SfxItemPropertyMapEntry const aCharAndParaMap_Impl[] = + { + COMPLETE_TEXT_CURSOR_MAP + }; + + return aCharAndParaMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetAccessibilityTextAttrPropertyMap() +{ + static SfxItemPropertyMapEntry const aAccessibilityTextAttrMap_Impl[] = + { + COMMON_ACCESSIBILITY_TEXT_ATTRIBUTE + }; + + return aAccessibilityTextAttrMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetParagraphPropertyMap() +{ + static SfxItemPropertyMapEntry const aParagraphMap_Impl[] = + { + COMMON_CRSR_PARA_PROPERTIES_2 + TABSTOPS_MAP_ENTRY + COMMON_TEXT_CONTENT_PROPERTIES + { UNO_NAME_CHAR_STYLE_NAME, RES_TXTATR_CHARFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_CHAR_STYLE_NAMES, FN_UNO_CHARFMT_SEQUENCE, cppu::UnoType< cppu::UnoSequenceType<OUString> >::get(), PropertyAttribute::MAYBEVOID, 0}, + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + // Added for paragraph backgrounds, this is for paragraph itself + FILL_PROPERTIES_SW + }; + + return aParagraphMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetAutoParaStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aAutoParaStyleMap [] = + { + { UNO_NAME_PARA_STYLE_NAME, RES_FRMATR_STYLE_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_PAGE_STYLE_NAME, FN_UNO_PAGE_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_NUMBERING_IS_NUMBER, FN_UNO_IS_NUMBER, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_NUMBERING_LEVEL, FN_UNO_NUM_LEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_NUMBERING_START_VALUE, FN_UNO_NUM_START_VALUE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, + { UNO_NAME_DOCUMENT_INDEX, FN_UNO_DOCUMENT_INDEX, cppu::UnoType<css::text::XDocumentIndex>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_TEXT_TABLE, FN_UNO_TEXT_TABLE, cppu::UnoType<css::text::XTextTable>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_CELL, FN_UNO_CELL, cppu::UnoType<css::table::XCell>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_TEXT_FRAME, FN_UNO_TEXT_FRAME, cppu::UnoType<css::text::XTextFrame>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_TEXT_SECTION, FN_UNO_TEXT_SECTION, cppu::UnoType<css::text::XTextSection>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_PARA_CHAPTER_NUMBERING_LEVEL, FN_UNO_PARA_CHAPTER_NUMBERING_LEVEL,cppu::UnoType<sal_Int8>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_PARA_IS_NUMBERING_RESTART, FN_NUMBER_NEWSTART, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, + // TODO add RES_PARATR_LIST_AUTOFMT? + { UNO_NAME_OUTLINE_LEVEL, RES_PARATR_OUTLINELEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_OUTLINE_CONTENT_VISIBLE, RES_PARATR_GRABBAG, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN + TABSTOPS_MAP_ENTRY + COMMON_TEXT_CONTENT_PROPERTIES + { UNO_NAME_PARA_AUTO_STYLE_NAME, RES_AUTO_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + // Added for paragraph backgrounds, this is for Paragraph AutoStyles + FILL_PROPERTIES_SW + }; + + return aAutoParaStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetCharStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aCharStyleMap [] = + { + { UNO_NAME_CHAR_AUTO_KERNING, RES_CHRATR_AUTOKERN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_BACK_TRANSPARENT, RES_CHRATR_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_CHAR_BACKGROUND_COMPLEX_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE ,MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR }, + { UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE }, + { UNO_NAME_CHAR_COMPLEX_COLOR, RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_COMPLEX_COLOR }, + { UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA}, + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT}, + { UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ESC }, + { UNO_NAME_CHAR_ESCAPEMENT_HEIGHT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int8>::get() , PROPERTY_NONE, MID_ESC_HEIGHT}, + { UNO_NAME_CHAR_FLASH, RES_CHRATR_BLINK , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_HIDDEN, RES_CHRATR_HIDDEN, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + STANDARD_FONT_PROPERTIES + CJK_FONT_PROPERTIES + CTL_FONT_PROPERTIES + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE}, + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR}, + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_TL_COMPLEX_COLOR }, + { UNO_NAME_CHAR_UNDERLINE_HAS_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR}, + { UNO_NAME_CHAR_OVERLINE, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE}, + { UNO_NAME_CHAR_OVERLINE_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR}, + { UNO_NAME_CHAR_OVERLINE_COMPLEX_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_TL_COMPLEX_COLOR }, + { UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR}, + { UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_WORD_MODE, RES_CHRATR_WORDLINEMODE,cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_HIDDEN, FN_UNO_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_STYLE_INTEROP_GRAB_BAG, FN_UNO_STYLE_INTEROP_GRAB_BAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_CHAR_COMBINE_IS_ON, RES_CHRATR_TWO_LINES, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TWOLINES}, + { UNO_NAME_CHAR_COMBINE_PREFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_START_BRACKET}, + { UNO_NAME_CHAR_COMBINE_SUFFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_END_BRACKET}, + { UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_EMPHASIS}, + PROP_DIFF_FONTHEIGHT + { UNO_NAME_CHAR_ROTATION, RES_CHRATR_ROTATE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ROTATE }, + { UNO_NAME_CHAR_ROTATION_IS_FIT_TO_LINE, RES_CHRATR_ROTATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FITTOLINE }, + { UNO_NAME_CHAR_SCALE_WIDTH, RES_CHRATR_SCALEW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHAR_RELIEF, RES_CHRATR_RELIEF, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_RELIEF }, + { UNO_NAME_CHAR_LEFT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_RIGHT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_TOP_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BOTTOM_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, BOTTOM_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_LEFT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_RIGHT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_TOP_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BOTTOM_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_CHAR_BORDER_LEFT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_CHAR_BORDER_RIGHT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, + { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, + { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_LINK_STYLE, FN_UNO_LINK_STYLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + + return aCharStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetAutoCharStylePropertyMap() +{ + // same as PROPERTY_MAP_TEXTPORTION_EXTENSIONS + static SfxItemPropertyMapEntry const aAutoCharStyleMap [] = + { + { UNO_NAME_CHAR_AUTO_KERNING, RES_CHRATR_AUTOKERN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_BACK_TRANSPARENT, RES_CHRATR_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_CHAR_BACKGROUND_COMPLEX_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR }, + { UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE }, + { UNO_NAME_CHAR_COMPLEX_COLOR, RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_COMPLEX_COLOR }, + { UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA}, + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT}, + { UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ESC }, + { UNO_NAME_CHAR_ESCAPEMENT_HEIGHT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int8>::get() , PROPERTY_NONE, MID_ESC_HEIGHT}, + { UNO_NAME_CHAR_FLASH, RES_CHRATR_BLINK , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_HIDDEN, RES_CHRATR_HIDDEN, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + STANDARD_FONT_PROPERTIES + CJK_FONT_PROPERTIES + CTL_FONT_PROPERTIES + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE}, + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR}, + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_TL_COMPLEX_COLOR }, + { UNO_NAME_CHAR_UNDERLINE_HAS_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR}, + { UNO_NAME_CHAR_OVERLINE, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE}, + { UNO_NAME_CHAR_OVERLINE_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR}, + { UNO_NAME_CHAR_OVERLINE_COMPLEX_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_TL_COMPLEX_COLOR }, + { UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR}, + { UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_WORD_MODE, RES_CHRATR_WORDLINEMODE,cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_TEXT_USER_DEFINED_ATTRIBUTES, RES_TXTATR_UNKNOWN_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_CHAR_COMBINE_IS_ON, RES_CHRATR_TWO_LINES, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TWOLINES}, + { UNO_NAME_CHAR_COMBINE_PREFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_START_BRACKET}, + { UNO_NAME_CHAR_COMBINE_SUFFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_END_BRACKET}, + { UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_EMPHASIS}, + { UNO_NAME_CHAR_ROTATION, RES_CHRATR_ROTATE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ROTATE }, + { UNO_NAME_CHAR_ROTATION_IS_FIT_TO_LINE, RES_CHRATR_ROTATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FITTOLINE }, + { UNO_NAME_CHAR_SCALE_WIDTH, RES_CHRATR_SCALEW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHAR_RELIEF, RES_CHRATR_RELIEF, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_RELIEF }, + { UNO_NAME_CHAR_AUTO_STYLE_NAME, RES_TXTATR_AUTOFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_CHAR_SHADING_VALUE, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_SHADING_VALUE }, + { UNO_NAME_CHAR_LEFT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_RIGHT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_TOP_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BOTTOM_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, BOTTOM_BORDER |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_LEFT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_RIGHT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_TOP_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_CHAR_BOTTOM_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_CHAR_BORDER_LEFT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_CHAR_BORDER_RIGHT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, + { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, + { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + }; + + return aAutoCharStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetParaStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aParaStyleMap [] = + { + COMMON_PARA_STYLE_PROPERTIES + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + // Added for paragraph backgrounds, this is for Paragraph Styles + FILL_PROPERTIES_SW + }; + + return aParaStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetConditionalParaStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aParaStyleMap [] = + { + COMMON_PARA_STYLE_PROPERTIES + { UNO_NAME_PARA_STYLE_CONDITIONS, FN_UNO_PARA_STYLE_CONDITIONS, cppu::UnoType< cppu::UnoSequenceType<css::beans::NamedValue> >::get(), PropertyAttribute::MAYBEVOID, 0}, + + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + // Added for paragraph backgrounds, this is for Paragraph Styles + FILL_PROPERTIES_SW + }; + + return aParaStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetFrameStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aFrameStyleMap [] = + { + { UNO_NAME_ANCHOR_PAGE_NO, RES_ANCHOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ANCHOR_PAGENUM }, + { UNO_NAME_ANCHOR_TYPE, RES_ANCHOR, cppu::UnoType<css::text::TextContentAnchorType>::get(), PROPERTY_NONE, MID_ANCHOR_ANCHORTYPE}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE ,MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_COLOR_R_G_B, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR_R_G_B}, + { UNO_NAME_BACK_COLOR_TRANSPARENCY, RES_BACKGROUND, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE ,MID_BACK_COLOR_TRANSPARENCY}, + { UNO_NAME_FRAME_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + // { UNO_NAME_CHAIN_NEXT_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_CHAIN_NEXTNAME}, + // { UNO_NAME_CHAIN_PREV_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_CHAIN_PREVNAME}, + /*not impl*/ { UNO_NAME_CLIENT_MAP, RES_URL, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_URL_CLIENTMAP }, + { UNO_NAME_CONTENT_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_CONTENT }, + { UNO_NAME_EDIT_IN_READONLY, RES_EDIT_IN_READONLY, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + // #i50322# - add missing map entry for transparency of graphic background + { UNO_NAME_BACK_GRAPHIC_TRANSPARENCY, RES_BACKGROUND, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENCY}, + { UNO_NAME_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_HORI_ORIENT, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_HORIORIENT_ORIENT }, + { UNO_NAME_HORI_ORIENT_POSITION, RES_HORI_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_HORIORIENT_POSITION|CONVERT_TWIPS }, + { UNO_NAME_HORI_ORIENT_RELATION, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_HORIORIENT_RELATION }, + { UNO_NAME_HYPER_LINK_U_R_L, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_URL}, + { UNO_NAME_HYPER_LINK_TARGET, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_TARGET}, + { UNO_NAME_HYPER_LINK_NAME, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_HYPERLINKNAME }, + { UNO_NAME_OPAQUE, RES_OPAQUE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PAGE_TOGGLE, RES_HORI_ORIENT, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_HORIORIENT_PAGETOGGLE }, + { UNO_NAME_POSITION_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_POSITION}, + { UNO_NAME_PRINT, RES_PRINT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH|CONVERT_TWIPS }, + { UNO_NAME_HEIGHT, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_FRMSIZE_HEIGHT|CONVERT_TWIPS }, + { UNO_NAME_RELATIVE_HEIGHT, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT }, + { UNO_NAME_RELATIVE_HEIGHT_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT_RELATION }, + { UNO_NAME_RELATIVE_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH }, + { UNO_NAME_RELATIVE_WIDTH_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH_RELATION }, + { UNO_NAME_SIZE_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_SIZE_TYPE }, + { UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH_TYPE }, + { UNO_NAME_SIZE, RES_FRM_SIZE, cppu::UnoType<css::awt::Size>::get(), PROPERTY_NONE, MID_FRMSIZE_SIZE|CONVERT_TWIPS}, + { UNO_NAME_IS_SYNC_WIDTH_TO_HEIGHT, RES_FRM_SIZE, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT }, + { UNO_NAME_IS_SYNC_HEIGHT_TO_WIDTH, RES_FRM_SIZE, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH }, + // { UNO_NAME_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH }, + { UNO_NAME_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_SHADOW_TRANSPARENCE, RES_SHADOW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_SHADOW_TRANSPARENCE}, + { UNO_NAME_SERVER_MAP, RES_URL, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_URL_SERVERMAP }, + { UNO_NAME_SIZE_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_SIZE }, + // We keep Surround, as we delivered it with 5.1, although it's identical to text::WrapTextMode + { UNO_NAME_SURROUND, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE, MID_SURROUND_SURROUNDTYPE }, + { UNO_NAME_TEXT_WRAP, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE, MID_SURROUND_SURROUNDTYPE }, + { UNO_NAME_SURROUND_ANCHORONLY, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_ANCHORONLY }, + { UNO_NAME_SURROUND_CONTOUR, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUR }, + { UNO_NAME_CONTOUR_OUTSIDE, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUROUTSIDE }, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_ORIENT }, + { UNO_NAME_VERT_ORIENT_POSITION, RES_VERT_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_VERTORIENT_POSITION|CONVERT_TWIPS }, + { UNO_NAME_VERT_ORIENT_RELATION, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_RELATION }, + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_TOP_COLOR }, + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_BOTTOM_COLOR }, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_IS_AUTO_UPDATE, FN_UNO_IS_AUTO_UPDATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + // #i18732# + { UNO_NAME_IS_FOLLOWING_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FOLLOW_TEXT_FLOW}, + // #i28701# + { UNO_NAME_WRAP_INFLUENCE_ON_POSITION, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, MID_WRAP_INFLUENCE}, + { UNO_NAME_ALLOW_OVERLAP, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_ALLOW_OVERLAP}, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_HIDDEN, FN_UNO_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { u"Decorative"_ustr, RES_DECORATIVE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TEXT_VERT_ADJUST, RES_TEXT_VERT_ADJUST, cppu::UnoType<css::drawing::TextVerticalAdjust>::get(), PROPERTY_NONE ,0}, + + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + FILL_PROPERTIES_SW + }; + + return aFrameStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetPageStylePropertyMap() +{ + static SfxItemPropertyMapEntry const aPageStyleMap [] = + { + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_GUTTER_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_GUTTER_MARGIN | CONVERT_TWIPS}, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_LEFT_COLOR }, + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_RIGHT_COLOR }, + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_TOP_COLOR }, + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_BOTTOM_COLOR }, + { UNO_NAME_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_SHADOW_TRANSPARENCE, RES_SHADOW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_SHADOW_TRANSPARENCE}, + + //UUU use real WhichIDs for Header, no longer use extra-defined WhichIDs which make handling harder as needed. + // The implementation will decide if these are part of Header/Footer or PageStyle depending on the SlotName, + // more precisely on the first characters. Thus it is necessary that these are 'Header' for the Header slots + { UNO_NAME_HEADER_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_HEADER_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_HEADER_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_HEADER_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_HEADER_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_HEADER_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_HEADER_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_HEADER_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_HEADER_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_HEADER_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_HEADER_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_HEADER_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_HEADER_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_HEADER_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_HEADER_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_HEADER_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_HEADER_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_HEADER_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_HEADER_BODY_DISTANCE, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_LO_MARGIN|CONVERT_TWIPS }, + { UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT, SID_ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_HEADER_IS_SHARED, SID_ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_HEADER_HEIGHT, SID_ATTR_PAGE_SIZE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_SIZE_HEIGHT|CONVERT_TWIPS }, + { UNO_NAME_HEADER_IS_ON, SID_ATTR_PAGE_ON, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_HEADER_DYNAMIC_SPACING, RES_HEADER_FOOTER_EAT_SPACING, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID ,0 }, + + + { UNO_NAME_FIRST_IS_SHARED, SID_ATTR_PAGE_SHARED_FIRST, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + + //UUU use real WhichIDs for Footer, see Header (above) for more infos + { UNO_NAME_FOOTER_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_FOOTER_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_FOOTER_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_FOOTER_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_FOOTER_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_FOOTER_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_FOOTER_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_FOOTER_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_FOOTER_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, + { UNO_NAME_FOOTER_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_FOOTER_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, + { UNO_NAME_FOOTER_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, + { UNO_NAME_FOOTER_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_FOOTER_BODY_DISTANCE, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_UP_MARGIN|CONVERT_TWIPS }, + { UNO_NAME_FOOTER_IS_DYNAMIC_HEIGHT, SID_ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_FOOTER_IS_SHARED, SID_ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_FOOTER_HEIGHT, SID_ATTR_PAGE_SIZE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_SIZE_HEIGHT|CONVERT_TWIPS }, + { UNO_NAME_FOOTER_IS_ON, SID_ATTR_PAGE_ON, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 }, + { UNO_NAME_FOOTER_DYNAMIC_SPACING, RES_HEADER_FOOTER_EAT_SPACING, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID ,0 }, + + { UNO_NAME_IS_LANDSCAPE, SID_ATTR_PAGE, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_PAGE_ORIENTATION }, + { UNO_NAME_NUMBERING_TYPE, SID_ATTR_PAGE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_PAGE_NUMTYPE }, + { UNO_NAME_PAGE_STYLE_LAYOUT, SID_ATTR_PAGE, cppu::UnoType<css::style::PageStyleLayout>::get(), PROPERTY_NONE ,MID_PAGE_LAYOUT }, + { UNO_NAME_PRINTER_PAPER_TRAY, RES_PAPER_BIN, cppu::UnoType<OUString>::get(), PROPERTY_NONE , 0 }, +// { UNO_NAME_REGISTER_MODE_ACTIVE, SID_SWREGISTER_MODE, cppu::UnoType<bool>::get(), PROPERTY_NONE , 0 }, + { UNO_NAME_REGISTER_PARAGRAPH_STYLE, SID_SWREGISTER_COLLECTION, cppu::UnoType<OUString>::get(), PROPERTY_NONE , 0 }, + { UNO_NAME_SIZE, SID_ATTR_PAGE_SIZE, cppu::UnoType<css::awt::Size>::get(), PROPERTY_NONE, MID_SIZE_SIZE|CONVERT_TWIPS}, + { UNO_NAME_WIDTH, SID_ATTR_PAGE_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_SIZE_WIDTH|CONVERT_TWIPS}, + { UNO_NAME_HEIGHT, SID_ATTR_PAGE_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_SIZE_HEIGHT|CONVERT_TWIPS }, + { UNO_NAME_TEXT_VERT_ADJUST, RES_TEXT_VERT_ADJUST, cppu::UnoType<css::drawing::TextVerticalAdjust>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_HEADER_TEXT, FN_UNO_HEADER, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_HEADER_TEXT_LEFT, FN_UNO_HEADER_LEFT, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_HEADER_TEXT_RIGHT, FN_UNO_HEADER_RIGHT, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_HEADER_TEXT_FIRST, FN_UNO_HEADER_FIRST, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOOTER_TEXT, FN_UNO_FOOTER, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOOTER_TEXT_LEFT, FN_UNO_FOOTER_LEFT, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOOTER_TEXT_RIGHT, FN_UNO_FOOTER_RIGHT, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOOTER_TEXT_FIRST, FN_UNO_FOOTER_FIRST, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOLLOW_STYLE, FN_UNO_FOLLOW_STYLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_FOOTNOTE_HEIGHT, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_FTN_HEIGHT|CONVERT_TWIPS}, + { UNO_NAME_FOOTNOTE_LINE_WEIGHT, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_LINE_WEIGHT|CONVERT_TWIPS}, + { UNO_NAME_FOOTNOTE_LINE_COLOR, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_LINE_COLOR}, + { UNO_NAME_FOOTNOTE_LINE_STYLE, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE , MID_FTN_LINE_STYLE}, + { UNO_NAME_FOOTNOTE_LINE_RELATIVE_WIDTH, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE , MID_LINE_RELWIDTH }, + { UNO_NAME_FOOTNOTE_LINE_ADJUST, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_LINE_ADJUST }, + { UNO_NAME_FOOTNOTE_LINE_TEXT_DISTANCE, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_LINE_TEXT_DIST |CONVERT_TWIPS }, + { UNO_NAME_FOOTNOTE_LINE_DISTANCE, FN_PARAM_FTN_INFO, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_LINE_FOOTNOTE_DIST|CONVERT_TWIPS}, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + // writing grid + { UNO_NAME_GRID_COLOR, RES_TEXTGRID, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_GRID_COLOR}, + { UNO_NAME_GRID_LINES, RES_TEXTGRID, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_GRID_LINES}, + { UNO_NAME_GRID_BASE_HEIGHT, RES_TEXTGRID, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_GRID_BASEHEIGHT|CONVERT_TWIPS}, + { UNO_NAME_GRID_RUBY_HEIGHT, RES_TEXTGRID, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_GRID_RUBYHEIGHT|CONVERT_TWIPS}, + { UNO_NAME_GRID_MODE, RES_TEXTGRID, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_GRID_TYPE}, + { UNO_NAME_GRID_RUBY_BELOW, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_RUBY_BELOW}, + { UNO_NAME_GRID_PRINT, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_PRINT}, + { UNO_NAME_GRID_DISPLAY, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_DISPLAY}, + { UNO_NAME_GRID_BASE_WIDTH, RES_TEXTGRID, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_GRID_BASEWIDTH|CONVERT_TWIPS}, + { UNO_NAME_GRID_SNAP_TO_CHARS, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_SNAPTOCHARS}, + { UNO_NAME_GRID_STANDARD_PAGE_MODE, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_STANDARD_MODE}, + { UNO_NAME_HIDDEN, FN_UNO_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to style import/export + FILL_PROPERTIES_SW + { u"BackgroundFullSize"_ustr, RES_BACKGROUND_FULL_SIZE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { u"RtlGutter"_ustr, RES_RTL_GUTTER, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + + // Added DrawingLayer FillStyle Properties for Header. These need an own unique name, + // but reuse the same WhichIDs as the regular fill. The implementation will decide to which + // group of fill properties it belongs based on the start of the name (was already done in + // the implementation partially), thus all SlotNames *have* to start with 'Header' + { UNO_NAME_HEADER_FILLBMP_LOGICAL_SIZE, XATTR_FILLBMP_SIZELOG, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_OFFSET_X, XATTR_FILLBMP_TILEOFFSETX, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_OFFSET_Y, XATTR_FILLBMP_TILEOFFSETY, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_POSITION_OFFSET_X, XATTR_FILLBMP_POSOFFSETX, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_POSITION_OFFSET_Y, XATTR_FILLBMP_POSOFFSETY, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_RECTANGLE_POINT, XATTR_FILLBMP_POS, cppu::UnoType<css::drawing::RectanglePoint>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_SIZE_X, XATTR_FILLBMP_SIZEX, cppu::UnoType<sal_Int32>::get() , 0, 0, PropertyMoreFlags::METRIC_ITEM}, + { UNO_NAME_HEADER_FILLBMP_SIZE_Y, XATTR_FILLBMP_SIZEY, cppu::UnoType<sal_Int32>::get() , 0, 0, PropertyMoreFlags::METRIC_ITEM}, + { UNO_NAME_HEADER_FILLBMP_STRETCH, XATTR_FILLBMP_STRETCH, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_TILE, XATTR_FILLBMP_TILE, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_HEADER_FILLBMP_MODE, OWN_ATTR_FILLBMP_MODE, cppu::UnoType<css::drawing::BitmapMode>::get(), 0, 0}, + { UNO_NAME_HEADER_FILLCOLOR, XATTR_FILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, + { UNO_NAME_HEADER_FILLBACKGROUND, XATTR_FILLBACKGROUND, cppu::UnoType<bool>::get(), 0, 0}, + { UNO_NAME_HEADER_FILLBITMAP, XATTR_FILLBITMAP, cppu::UnoType<css::awt::XBitmap>::get(), 0, MID_BITMAP}, + { UNO_NAME_HEADER_FILLBITMAPNAME, XATTR_FILLBITMAP, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_HEADER_FILLGRADIENTSTEPCOUNT, XATTR_GRADIENTSTEPCOUNT, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_HEADER_FILLGRADIENT, XATTR_FILLGRADIENT, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, + { UNO_NAME_HEADER_FILLGRADIENTNAME, XATTR_FILLGRADIENT, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_HEADER_FILLHATCH, XATTR_FILLHATCH, cppu::UnoType<css::drawing::Hatch>::get(), 0, MID_FILLHATCH}, + { UNO_NAME_HEADER_FILLHATCHNAME, XATTR_FILLHATCH, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_HEADER_FILLSTYLE, XATTR_FILLSTYLE, cppu::UnoType<css::drawing::FillStyle>::get(), 0, 0}, + { UNO_NAME_HEADER_FILL_TRANSPARENCE, XATTR_FILLTRANSPARENCE, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_HEADER_FILLTRANSPARENCEGRADIENT, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, + { UNO_NAME_HEADER_FILLTRANSPARENCEGRADIENTNAME, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_HEADER_FILLCOLOR_2, XATTR_SECONDARYFILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, + + // Added DrawingLayer FillStyle Properties for Footer, similar as for Header (see there) + { UNO_NAME_FOOTER_FILLBMP_LOGICAL_SIZE, XATTR_FILLBMP_SIZELOG, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_OFFSET_X, XATTR_FILLBMP_TILEOFFSETX, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_OFFSET_Y, XATTR_FILLBMP_TILEOFFSETY, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_POSITION_OFFSET_X, XATTR_FILLBMP_POSOFFSETX, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_POSITION_OFFSET_Y, XATTR_FILLBMP_POSOFFSETY, cppu::UnoType<sal_Int32>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_RECTANGLE_POINT, XATTR_FILLBMP_POS, cppu::UnoType<css::drawing::RectanglePoint>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_SIZE_X, XATTR_FILLBMP_SIZEX, cppu::UnoType<sal_Int32>::get() , 0, 0, PropertyMoreFlags::METRIC_ITEM}, + { UNO_NAME_FOOTER_FILLBMP_SIZE_Y, XATTR_FILLBMP_SIZEY, cppu::UnoType<sal_Int32>::get() , 0, 0, PropertyMoreFlags::METRIC_ITEM}, + { UNO_NAME_FOOTER_FILLBMP_STRETCH, XATTR_FILLBMP_STRETCH, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_TILE, XATTR_FILLBMP_TILE, cppu::UnoType<bool>::get() , 0, 0}, + { UNO_NAME_FOOTER_FILLBMP_MODE, OWN_ATTR_FILLBMP_MODE, cppu::UnoType<css::drawing::BitmapMode>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILLCOLOR, XATTR_FILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILLBACKGROUND, XATTR_FILLBACKGROUND, cppu::UnoType<bool>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILLBITMAP, XATTR_FILLBITMAP, cppu::UnoType<css::awt::XBitmap>::get(), 0, MID_BITMAP}, + { UNO_NAME_FOOTER_FILLBITMAPNAME, XATTR_FILLBITMAP, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_FOOTER_FILLGRADIENTSTEPCOUNT, XATTR_GRADIENTSTEPCOUNT, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILLGRADIENT, XATTR_FILLGRADIENT, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, + { UNO_NAME_FOOTER_FILLGRADIENTNAME, XATTR_FILLGRADIENT, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_FOOTER_FILLHATCH, XATTR_FILLHATCH, cppu::UnoType<css::drawing::Hatch>::get(), 0, MID_FILLHATCH}, + { UNO_NAME_FOOTER_FILLHATCHNAME, XATTR_FILLHATCH, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_FOOTER_FILLSTYLE, XATTR_FILLSTYLE, cppu::UnoType<css::drawing::FillStyle>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILL_TRANSPARENCE, XATTR_FILLTRANSPARENCE, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_FOOTER_FILLTRANSPARENCEGRADIENT, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, + { UNO_NAME_FOOTER_FILLTRANSPARENCEGRADIENTNAME, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<OUString>::get(), 0, MID_NAME }, + { UNO_NAME_FOOTER_FILLCOLOR_2, XATTR_SECONDARYFILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, + + }; + + return aPageStyleMap; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetTablePropertyMap() +{ + static SfxItemPropertyMapEntry const aTablePropertyMap_Impl[] = + { + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR}, + { UNO_NAME_BREAK_TYPE, RES_BREAK, cppu::UnoType<css::style::BreakType>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_HORI_ORIENT, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_HORIORIENT_ORIENT }, + { UNO_NAME_KEEP_TOGETHER, RES_KEEP, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SPLIT, RES_LAYOUT_SPLIT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_PAGE_NUMBER_OFFSET, RES_PAGEDESC, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PAGEDESC_PAGENUMOFFSET}, + { UNO_NAME_PAGE_DESC_NAME, RES_PAGEDESC, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0xbf}, + { UNO_NAME_RELATIVE_WIDTH, FN_TABLE_RELATIVE_WIDTH,cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0xbf }, + { UNO_NAME_REPEAT_HEADLINE, FN_TABLE_HEADLINE_REPEAT,cppu::UnoType<bool>::get(), PROPERTY_NONE, 0xbf}, + { UNO_NAME_HEADER_ROW_COUNT, FN_TABLE_HEADLINE_COUNT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0xbf}, + { UNO_NAME_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SHADOW_TRANSPARENCE, RES_SHADOW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_SHADOW_TRANSPARENCE}, + { UNO_NAME_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_WIDTH, FN_TABLE_WIDTH, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, 0xbf}, + { UNO_NAME_IS_WIDTH_RELATIVE, FN_TABLE_IS_RELATIVE_WIDTH, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0xbf}, + { UNO_NAME_CHART_ROW_AS_LABEL, FN_UNO_RANGE_ROW_LABEL, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHART_COLUMN_AS_LABEL, FN_UNO_RANGE_COL_LABEL, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TABLE_BORDER, FN_UNO_TABLE_BORDER, cppu::UnoType<css::table::TableBorder>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, + { UNO_NAME_TABLE_BORDER2, FN_UNO_TABLE_BORDER2, cppu::UnoType<css::table::TableBorder2>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, + { UNO_NAME_TABLE_BORDER_DISTANCES, FN_UNO_TABLE_BORDER_DISTANCES, cppu::UnoType<css::table::TableBorderDistances>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, + { UNO_NAME_TABLE_COLUMN_SEPARATORS, FN_UNO_TABLE_COLUMN_SEPARATORS, cppu::UnoType< cppu::UnoSequenceType<css::text::TableColumnSeparator> >::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_TABLE_COLUMN_RELATIVE_SUM, FN_UNO_TABLE_COLUMN_RELATIVE_SUM, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::READONLY, 0 }, + COMMON_TEXT_CONTENT_PROPERTIES + { UNO_LINK_DISPLAY_NAME, FN_PARAM_LINK_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0xbf}, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_TEXT_SECTION, FN_UNO_TEXT_SECTION, cppu::UnoType<css::text::XTextSection>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TABLE_NAME, FN_UNO_TABLE_NAME, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_PAGE_STYLE_NAME, RES_PAGEDESC, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TABLE_TEMPLATE_NAME, FN_UNO_TABLE_TEMPLATE_NAME, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + // #i29550# + { UNO_NAME_COLLAPSING_BORDERS, RES_COLLAPSING_BORDERS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + REDLINE_NODE_PROPERTIES + { UNO_NAME_TABLE_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, + }; + + return aTablePropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetRangePropertyMap() +{ + static SfxItemPropertyMapEntry const aRangePropertyMap_Impl[] = + { + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 + TABSTOPS_MAP_ENTRY + { UNO_NAME_BACK_COLOR, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_TRANSPARENT, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_NUMBER_FORMAT, RES_BOXATR_FORMAT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID ,0 }, + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_ORIENT }, + { UNO_NAME_CHART_ROW_AS_LABEL, FN_UNO_RANGE_ROW_LABEL, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_CHART_COLUMN_AS_LABEL, FN_UNO_RANGE_COL_LABEL, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + }; + + return aRangePropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetSectionPropertyMap() +{ + static SfxItemPropertyMapEntry const aSectionPropertyMap_Impl[] = + { + { UNO_NAME_CONDITION, WID_SECT_CONDITION, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_DDE_COMMAND_FILE, WID_SECT_DDE_TYPE, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_DDE_COMMAND_TYPE, WID_SECT_DDE_FILE, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_DDE_COMMAND_ELEMENT, WID_SECT_DDE_ELEMENT, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_IS_AUTOMATIC_UPDATE, WID_SECT_DDE_AUTOUPDATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_FILE_LINK, WID_SECT_LINK , cppu::UnoType<css::text::SectionFileLink>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_VISIBLE, WID_SECT_VISIBLE , cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_PROTECTED, WID_SECT_PROTECTED, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_EDIT_IN_READONLY, WID_SECT_EDIT_IN_READONLY, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_LINK_REGION, WID_SECT_REGION , cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, + { UNO_LINK_DISPLAY_NAME, FN_PARAM_LINK_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0xbf}, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_FOOTNOTE_IS_COLLECT_AT_TEXT_END, RES_FTN_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_COLLECT }, + { UNO_NAME_FOOTNOTE_IS_RESTART_NUMBERING, RES_FTN_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_RESTART_NUM }, + { UNO_NAME_FOOTNOTE_RESTART_NUMBERING_AT, RES_FTN_AT_TXTEND, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_NUM_START_AT}, + { UNO_NAME_FOOTNOTE_IS_OWN_NUMBERING, RES_FTN_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_OWN_NUM }, + { UNO_NAME_FOOTNOTE_NUMBERING_TYPE, RES_FTN_AT_TXTEND, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_NUM_TYPE }, + { UNO_NAME_FOOTNOTE_NUMBERING_PREFIX, RES_FTN_AT_TXTEND, cppu::UnoType<OUString>::get() , PROPERTY_NONE, MID_PREFIX }, + { UNO_NAME_FOOTNOTE_NUMBERING_SUFFIX, RES_FTN_AT_TXTEND, cppu::UnoType<OUString>::get() , PROPERTY_NONE, MID_SUFFIX }, + { UNO_NAME_ENDNOTE_IS_COLLECT_AT_TEXT_END, RES_END_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_COLLECT }, + { UNO_NAME_ENDNOTE_IS_RESTART_NUMBERING, RES_END_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_RESTART_NUM }, + { UNO_NAME_ENDNOTE_RESTART_NUMBERING_AT, RES_END_AT_TXTEND, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_NUM_START_AT }, + { UNO_NAME_ENDNOTE_IS_OWN_NUMBERING, RES_END_AT_TXTEND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_OWN_NUM }, + { UNO_NAME_ENDNOTE_NUMBERING_TYPE, RES_END_AT_TXTEND, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_NUM_TYPE }, + { UNO_NAME_ENDNOTE_NUMBERING_PREFIX, RES_END_AT_TXTEND, cppu::UnoType<OUString>::get() , PROPERTY_NONE, MID_PREFIX }, + { UNO_NAME_ENDNOTE_NUMBERING_SUFFIX, RES_END_AT_TXTEND, cppu::UnoType<OUString>::get() , PROPERTY_NONE, MID_SUFFIX }, + { UNO_NAME_DOCUMENT_INDEX, WID_SECT_DOCUMENT_INDEX, cppu::UnoType<css::text::XDocumentIndex>::get(), PropertyAttribute::READONLY | PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_GLOBAL_DOCUMENT_SECTION, WID_SECT_IS_GLOBAL_DOC_SECTION, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0 }, + { UNO_NAME_PROTECTION_KEY, WID_SECT_PASSWORD, cppu::UnoType< cppu::UnoSequenceType<sal_Int8> >::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DONT_BALANCE_TEXT_COLUMNS, RES_COLUMNBALANCE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + COMMON_TEXT_CONTENT_PROPERTIES + REDLINE_NODE_PROPERTIES + { UNO_NAME_IS_CURRENTLY_VISIBLE, WID_SECT_CURRENTLY_VISIBLE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_SECT_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_L_MARGIN|CONVERT_TWIPS}, + { UNO_NAME_SECT_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_R_MARGIN|CONVERT_TWIPS}, + }; + + return aSectionPropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetFramePropertyMap() +{ + static SfxItemPropertyMapEntry const aFramePropertyMap_Impl[] = + { // + // TODO: We should consider completely removing SvxBrushItem() stuff + // add support for XATTR_FILL_FIRST, XATTR_FILL_LAST + // COMMON_FRAME_PROPERTIES currently hosts the RES_BACKGROUND entries from SvxBrushItem + COMMON_FRAME_PROPERTIES + REDLINE_NODE_PROPERTIES + { UNO_NAME_CHAIN_NEXT_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_NEXTNAME}, + { UNO_NAME_CHAIN_PREV_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_PREVNAME}, + /*not impl*/ { UNO_NAME_CLIENT_MAP, RES_URL, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_URL_CLIENTMAP }, + { UNO_NAME_EDIT_IN_READONLY, RES_EDIT_IN_READONLY, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_COLUMNS, RES_COL, cppu::UnoType<css::text::XTextColumns>::get(), PROPERTY_NONE, MID_COLUMNS}, + //next elements are part of the service description + { UNO_NAME_FRAME_HEIGHT_ABSOLUTE, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FRMSIZE_HEIGHT|CONVERT_TWIPS }, + { UNO_NAME_FRAME_HEIGHT_PERCENT, RES_FRM_SIZE, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT }, + { UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT, RES_FRM_SIZE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FRMSIZE_IS_AUTO_HEIGHT }, + { UNO_NAME_FRAME_WIDTH_ABSOLUTE, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FRMSIZE_WIDTH|CONVERT_TWIPS }, + { UNO_NAME_FRAME_WIDTH_PERCENT, RES_FRM_SIZE, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH }, + { UNO_NAME_SIZE_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_SIZE_TYPE }, + { UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH_TYPE }, + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_IS_SPLIT_ALLOWED, RES_FLY_SPLIT, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_WRAP_TEXT_AT_FLY_START, RES_WRAP_TEXT_AT_FLY_START, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, + + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to FlyFrame import/export + FILL_PROPERTIES_SW + }; + + return aFramePropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetGraphicPropertyMap() +{ + static SfxItemPropertyMapEntry const aGraphicPropertyMap_Impl[] = + { + // TODO: We should consider completely removing SvxBrushItem() stuff + // add support for XATTR_FILL_FIRST, XATTR_FILL_LAST + // COMMON_FRAME_PROPERTIES currently hosts the RES_BACKGROUND entries from SvxBrushItem + COMMON_FRAME_PROPERTIES + { UNO_NAME_SURROUND_CONTOUR, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUR }, + { UNO_NAME_CONTOUR_OUTSIDE, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUROUTSIDE }, + { UNO_NAME_GRAPHIC_CROP, RES_GRFATR_CROPGRF, cppu::UnoType<css::text::GraphicCrop>::get(), PROPERTY_NONE, CONVERT_TWIPS }, + { UNO_NAME_HORI_MIRRORED_ON_EVEN_PAGES, RES_GRFATR_MIRRORGRF, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_MIRROR_HORZ_EVEN_PAGES }, + { UNO_NAME_HORI_MIRRORED_ON_ODD_PAGES, RES_GRFATR_MIRRORGRF, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_MIRROR_HORZ_ODD_PAGES }, + { UNO_NAME_VERT_MIRRORED, RES_GRFATR_MIRRORGRF, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_MIRROR_VERT }, + { UNO_NAME_REPLACEMENT_GRAPHIC, FN_UNO_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 }, + { UNO_NAME_GRAPHIC_FILTER, FN_UNO_GRAPHIC_FILTER, cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_NAME_GRAPHIC, FN_UNO_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 }, + { UNO_NAME_GRAPHIC_URL, FN_UNO_GRAPHIC_URL, cppu::UnoType<css::uno::Any>::get(), 0, 0 }, + { UNO_NAME_TRANSFORMED_GRAPHIC, FN_UNO_TRANSFORMED_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 }, + { UNO_NAME_GRAPHIC_PREVIEW, FN_UNO_GRAPHIC_PREVIEW, cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 }, + { UNO_NAME_ACTUAL_SIZE, FN_UNO_ACTUAL_SIZE, cppu::UnoType<css::awt::Size>::get(), PropertyAttribute::READONLY, CONVERT_TWIPS}, + { UNO_NAME_CONTOUR_POLY_POLYGON, FN_PARAM_CONTOUR_PP, cppu::UnoType<css::drawing::PointSequenceSequence>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PIXEL_CONTOUR, FN_UNO_IS_PIXEL_CONTOUR, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_IS_AUTOMATIC_CONTOUR, FN_UNO_IS_AUTOMATIC_CONTOUR , cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_GRAPHIC_ROTATION, RES_GRFATR_ROTATION, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_ADJUST_LUMINANCE, RES_GRFATR_LUMINANCE, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_ADJUST_CONTRAST, RES_GRFATR_CONTRAST, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_ADJUST_RED, RES_GRFATR_CHANNELR, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_ADJUST_GREEN, RES_GRFATR_CHANNELG, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_ADJUST_BLUE, RES_GRFATR_CHANNELB, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_GAMMA, RES_GRFATR_GAMMA, cppu::UnoType<double>::get(), 0, 0}, + { UNO_NAME_GRAPHIC_IS_INVERTED, RES_GRFATR_INVERT, cppu::UnoType<bool>::get(), 0, 0}, + { UNO_NAME_TRANSPARENCY, RES_GRFATR_TRANSPARENCY, cppu::UnoType<sal_Int16>::get(), 0, 0}, + { UNO_NAME_GRAPHIC_COLOR_MODE, RES_GRFATR_DRAWMODE, cppu::UnoType<css::drawing::ColorMode>::get(), 0, 0}, + + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to Writer GraphicObject import/export + FILL_PROPERTIES_SW + }; + + return aGraphicPropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetEmbeddedPropertyMap() +{ + static SfxItemPropertyMapEntry const aEmbeddedPropertyMap_Impl[] = + { // + // TODO: We should consider completely removing SvxBrushItem() stuff + // add support for XATTR_FILL_FIRST, XATTR_FILL_LAST + // COMMON_FRAME_PROPERTIES currently hosts the RES_BACKGROUND entries from SvxBrushItem + COMMON_FRAME_PROPERTIES + { UNO_NAME_SURROUND_CONTOUR, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUR }, + { UNO_NAME_CONTOUR_OUTSIDE, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_CONTOUROUTSIDE}, + { UNO_NAME_CONTOUR_POLY_POLYGON, FN_PARAM_CONTOUR_PP, cppu::UnoType<css::drawing::PointSequenceSequence>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_IS_PIXEL_CONTOUR, FN_UNO_IS_PIXEL_CONTOUR, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_IS_AUTOMATIC_CONTOUR, FN_UNO_IS_AUTOMATIC_CONTOUR , cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CLSID, FN_UNO_CLSID, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_STREAM_NAME, FN_UNO_STREAM_NAME, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_MODEL, FN_UNO_MODEL, cppu::UnoType<css::frame::XModel>::get(), PropertyAttribute::READONLY|PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_GRAPHIC_URL, FN_UNO_REPLACEMENT_GRAPHIC_URL, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_GRAPHIC, FN_UNO_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_COMPONENT,FN_UNO_COMPONENT, cppu::UnoType<css::lang::XComponent>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_EMBEDDED_OBJECT,FN_EMBEDDED_OBJECT, cppu::UnoType<css::embed::XEmbeddedObject>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DRAW_ASPECT,FN_UNO_DRAW_ASPECT, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_VISIBLE_AREA_WIDTH,FN_UNO_VISIBLE_AREA_WIDTH, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_VISIBLE_AREA_HEIGHT,FN_UNO_VISIBLE_AREA_HEIGHT, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + // added FillProperties for SW, same as FILL_PROPERTIES in svx + // but need own defines in Writer due to later association of strings + // and uno types (see loop at end of this method and definition of SW_PROP_NMID) + // This entry is for adding that properties to OLE/EmbeddedObject import/export + FILL_PROPERTIES_SW + }; + + return aEmbeddedPropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetIndexMarkPropertyMap() +{ + static SfxItemPropertyMapEntry const aIdxMarkMap_Impl[] = + { + { UNO_NAME_ALTERNATIVE_TEXT, WID_ALT_TEXT, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_PRIMARY_KEY, WID_PRIMARY_KEY, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SECONDARY_KEY, WID_SECONDARY_KEY, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_TEXT_READING, WID_TEXT_READING, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PRIMARY_KEY_READING, WID_PRIMARY_KEY_READING, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SECONDARY_KEY_READING, WID_SECONDARY_KEY_READING, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_MAIN_ENTRY, WID_MAIN_ENTRY, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + COMMON_TEXT_CONTENT_PROPERTIES + }; + + return aIdxMarkMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetContentMarkPropertyMap() +{ + static SfxItemPropertyMapEntry const aContentMarkMap_Impl[] = + { + { UNO_NAME_ALTERNATIVE_TEXT, WID_ALT_TEXT, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL, WID_LEVEL , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + COMMON_TEXT_CONTENT_PROPERTIES + }; + + return aContentMarkMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetUserMarkPropertyMap() +{ + static SfxItemPropertyMapEntry const aUserMarkMap_Impl[] = + { + { UNO_NAME_ALTERNATIVE_TEXT, WID_ALT_TEXT, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_LEVEL, WID_LEVEL , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_USER_INDEX_NAME, WID_USER_IDX_NAME, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0}, + COMMON_TEXT_CONTENT_PROPERTIES + }; + + return aUserMarkMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetTextTableCursorPropertyMap() +{ + // The PropertySet corresponds to the Range without Chart properties + static SfxItemPropertyMapEntry const aTableCursorPropertyMap_Impl [] = + { + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 + TABSTOPS_MAP_ENTRY + + // attributes from PROPERTY_MAP_TABLE_CELL: + { UNO_NAME_BACK_COLOR, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE , MID_BACK_COLOR }, + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE , MID_BACKGROUND_COMPLEX_COLOR }, + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, + { UNO_NAME_BACK_GRAPHIC_LOCATION, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, + { UNO_NAME_NUMBER_FORMAT, RES_BOXATR_FORMAT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID ,0 }, + { UNO_NAME_BACK_TRANSPARENT, FN_UNO_TABLE_CELL_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE , MID_GRAPHIC_TRANSPARENT }, + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, + { UNO_NAME_TEXT_SECTION, FN_UNO_TEXT_SECTION, cppu::UnoType<css::text::XTextSection>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + { UNO_NAME_IS_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), 0, MID_PROTECT_CONTENT}, + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_ORIENT }, + }; + + return aTableCursorPropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetBookmarkPropertyMap() +{ + static SfxItemPropertyMapEntry const aBookmarkPropertyMap_Impl [] = + { + { UNO_LINK_DISPLAY_NAME, FN_PARAM_LINK_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0xbf}, + COMMON_TEXT_CONTENT_PROPERTIES + { UNO_NAME_BOOKMARK_HIDDEN, FN_BOOKMARK_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_BOOKMARK_CONDITION, FN_BOOKMARK_CONDITION, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + }; + + return aBookmarkPropertyMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetParagraphExtensionsPropertyMap() +{ + static SfxItemPropertyMapEntry const aParagraphExtensionsMap_Impl[] = + { + COMMON_TEXT_CONTENT_PROPERTIES + }; + + return aParagraphExtensionsMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetTextPortionExtensionPropertyMap() +{ + static SfxItemPropertyMapEntry const aTextPortionExtensionMap_Impl[] = + { + COMPLETE_TEXT_CURSOR_MAP + {UNO_NAME_BOOKMARK, FN_UNO_BOOKMARK, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + {UNO_NAME_CONTROL_CHARACTER, FN_UNO_CONTROL_CHARACTER, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, MID_HYPHEN_MIN_LEAD }, + {UNO_NAME_IS_COLLAPSED, FN_UNO_IS_COLLAPSED, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + {UNO_NAME_IS_START, FN_UNO_IS_START, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + //REDLINE_PROPERTIES + {UNO_NAME_TEXT_PORTION_TYPE, FN_UNO_TEXT_PORTION_TYPE, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_META, FN_UNO_META, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + {UNO_NAME_LINEBREAK, FN_UNO_LINEBREAK, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + {UNO_NAME_CONTENT_CONTROL, FN_UNO_CONTENT_CONTROL, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + }; + + return aTextPortionExtensionMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetFootnotePropertyMap() +{ + static SfxItemPropertyMapEntry const aFootnoteMap_Impl[] = + { + {UNO_NAME_REFERENCE_ID, 0, cppu::UnoType<sal_Int16>::get(),PropertyAttribute::READONLY|PropertyAttribute::MAYBEVOID, 0}, + COMMON_TEXT_CONTENT_PROPERTIES + REDLINE_NODE_PROPERTIES + }; + + return aFootnoteMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetLineBreakPropertyMap() +{ + static SfxItemPropertyMapEntry const aLineBreakMap_Impl[] = + { + { UNO_NAME_CLEAR, 0, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, + COMMON_TEXT_CONTENT_PROPERTIES + }; + + return aLineBreakMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetContentControlPropertyMap() +{ + static SfxItemPropertyMapEntry const aContentControlMap_Impl[] = + { + { UNO_NAME_SHOWING_PLACE_HOLDER, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHECKBOX, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHECKED, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CHECKED_STATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_UNCHECKED_STATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_LIST_ITEMS, 0, cppu::UnoType<uno::Sequence<uno::Sequence<beans::PropertyValue>>>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_PICTURE, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATE, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATE_FORMAT, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATE_LANGUAGE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_CURRENT_DATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_PLAIN_TEXT, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_COMBO_BOX, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DROP_DOWN, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_PLACEHOLDER_DOC_PART, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATA_BINDING_PREFIX_MAPPINGS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATA_BINDING_XPATH, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATA_BINDING_STORE_ITEM_ID, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_COLOR, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_APPEARANCE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_ALIAS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TAG, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_ID, 0, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_TAB_INDEX, 0, cppu::UnoType<sal_uInt32>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_LOCK, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_MULTILINE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { UNO_NAME_DATE_STRING, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 }, + }; + + return aContentControlMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetRedlinePropertyMap() +{ + static SfxItemPropertyMapEntry const aRedlineMap_Impl[] = + { + REDLINE_PROPERTIES(PropertyAttribute::READONLY) + REDLINE_NODE_PROPERTIES + {UNO_NAME_REDLINE_START, 0, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::READONLY, 0}, + {UNO_NAME_REDLINE_END, 0, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + }; + + return aRedlineMap_Impl; +} + +std::span<SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetTextDefaultPropertyMap() +{ + static SfxItemPropertyMapEntry aTextDefaultMap_Impl[] = + { + { UNO_NAME_TAB_STOP_DISTANCE, RES_PARATR_TABSTOP, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_STD_TAB | CONVERT_TWIPS}, + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN + COMMON_HYPERLINK_PROPERTIES + { UNO_NAME_CHAR_STYLE_NAME, RES_TXTATR_CHARFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + { UNO_NAME_IS_SPLIT_ALLOWED, RES_ROW_SPLIT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + // #i29550# + { UNO_NAME_COLLAPSING_BORDERS, RES_COLLAPSING_BORDERS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + + //text grid enhancement for better CJK support. 2007-04-01 + //just export the default page mode property, other properties are not handled in this version + { UNO_NAME_GRID_STANDARD_PAGE_MODE, RES_TEXTGRID, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_GRID_STANDARD_MODE}, + }; + + return aTextDefaultMap_Impl; +} + +std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetRedlinePortionPropertyMap() +{ + static SfxItemPropertyMapEntry const aRedlinePortionMap_Impl[] = + { + COMPLETE_TEXT_CURSOR_MAP + {UNO_NAME_BOOKMARK, FN_UNO_BOOKMARK, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, + {UNO_NAME_CONTROL_CHARACTER, FN_UNO_CONTROL_CHARACTER, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, MID_HYPHEN_MIN_LEAD }, + {UNO_NAME_IS_COLLAPSED, FN_UNO_IS_COLLAPSED, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + {UNO_NAME_IS_START, FN_UNO_IS_START, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 }, + REDLINE_PROPERTIES(0) + {UNO_NAME_TEXT_PORTION_TYPE, FN_UNO_TEXT_PORTION_TYPE, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + + return aRedlinePortionMap_Impl; +} + +const SfxItemPropertySet* SwUnoPropertyMapProvider::GetPropertySet( sal_uInt16 nPropertyId) +{ + if( !m_aPropertySetArr[nPropertyId] ) + { + std::span<const SfxItemPropertyMapEntry> pEntries = GetPropertyMapEntries(nPropertyId); + switch( nPropertyId ) + { + case PROPERTY_MAP_TEXT_CURSOR: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_CURSOR(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_CURSOR; + } + break; + case PROPERTY_MAP_CHAR_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_CHAR_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CHAR_STYLE; + } + break; + case PROPERTY_MAP_PARA_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_PARA_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_PARA_STYLE; + } + break; + case PROPERTY_MAP_FRAME_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_FRAME_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FRAME_STYLE; + } + break; + case PROPERTY_MAP_PAGE_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_PAGE_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_PAGE_STYLE; + } + break; + case PROPERTY_MAP_NUM_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_NUM_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_NUM_STYLE; + } + break; + case PROPERTY_MAP_SECTION: + { + static SfxItemPropertySet aPROPERTY_MAP_SECTION(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_SECTION; + } + break; + case PROPERTY_MAP_TEXT_TABLE: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_TABLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_TABLE; + } + break; + case PROPERTY_MAP_TABLE_CELL: + { + static SfxItemPropertySet aPROPERTY_MAP_TABLE_CELL(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TABLE_CELL; + } + break; + case PROPERTY_MAP_TABLE_RANGE: + { + static SfxItemPropertySet aPROPERTY_MAP_TABLE_RANGE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TABLE_RANGE; + } + break; + case PROPERTY_MAP_TEXT_SEARCH: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_SEARCH(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_SEARCH; + } + break; + case PROPERTY_MAP_TEXT_FRAME: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_FRAME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_FRAME; + } + break; + case PROPERTY_MAP_TEXT_GRAPHIC: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_GRAPHIC(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_GRAPHIC; + } + break; + case PROPERTY_MAP_TEXT_PAGE: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_PAGE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_PAGE; + } + break; + case PROPERTY_MAP_TEXT_SHAPE: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_SHAPE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_SHAPE; + } + break; + case PROPERTY_MAP_INDEX_USER: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_USER(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_USER; + } + break; + case PROPERTY_MAP_INDEX_CNTNT: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_CNTNT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_CNTNT; + } + break; + case PROPERTY_MAP_INDEX_IDX: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_IDX(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_IDX; + } + break; + case PROPERTY_MAP_USER_MARK: + { + static SfxItemPropertySet aPROPERTY_MAP_USER_MARK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_USER_MARK; + } + break; + case PROPERTY_MAP_CNTIDX_MARK: + { + static SfxItemPropertySet aPROPERTY_MAP_CNTIDX_MARK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CNTIDX_MARK; + } + break; + case PROPERTY_MAP_INDEX_MARK: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_MARK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_MARK; + } + break; + case PROPERTY_MAP_TEXT_TABLE_ROW: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_TABLE_ROW(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_TABLE_ROW; + } + break; + case PROPERTY_MAP_TEXT_SHAPE_DESCRIPTOR: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_SHAPE_DESCRIPTOR(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_SHAPE_DESCRIPTOR; + } + break; + case PROPERTY_MAP_TEXT_TABLE_CURSOR: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_TABLE_CURSOR(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_TABLE_CURSOR; + } + break; + case PROPERTY_MAP_BOOKMARK: + { + static SfxItemPropertySet aPROPERTY_MAP_BOOKMARK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_BOOKMARK; + } + break; + case PROPERTY_MAP_FIELDMARK: + { + static SfxItemPropertySet aPROPERTY_MAP_FIELDMARK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FIELDMARK; + } + break; + case PROPERTY_MAP_PARAGRAPH_EXTENSIONS: + { + static SfxItemPropertySet aPROPERTY_MAP_PARAGRAPH_EXTENSIONS(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_PARAGRAPH_EXTENSIONS; + } + break; + case PROPERTY_MAP_INDEX_ILLUSTRATIONS: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_ILLUSTRATIONS(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_ILLUSTRATIONS; + } + break; + case PROPERTY_MAP_INDEX_OBJECTS: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_OBJECTS(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_OBJECTS; + } + break; + case PROPERTY_MAP_INDEX_TABLES: + { + static SfxItemPropertySet aPROPERTY_MAP_INDEX_TABLES(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_INDEX_TABLES; + } + break; + case PROPERTY_MAP_BIBLIOGRAPHY : + { + static SfxItemPropertySet aPROPERTY_MAP_BIBLIOGRAPHY(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_BIBLIOGRAPHY; + } + break; + case PROPERTY_MAP_TEXT_DOCUMENT: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_DOCUMENT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_DOCUMENT; + } + break; + case PROPERTY_MAP_LINK_TARGET : + { + static SfxItemPropertySet aPROPERTY_MAP_LINK_TARGET(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_LINK_TARGET; + } + break; + case PROPERTY_MAP_AUTO_TEXT_GROUP : + { + static SfxItemPropertySet aPROPERTY_MAP_AUTO_TEXT_GROUP(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_AUTO_TEXT_GROUP; + } + break; + case PROPERTY_MAP_TEXTPORTION_EXTENSIONS : + { + static SfxItemPropertySet aPROPERTY_MAP_TEXTPORTION_EXTENSIONS(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXTPORTION_EXTENSIONS; + } + break; + case PROPERTY_MAP_FOOTNOTE : + { + static SfxItemPropertySet aPROPERTY_MAP_FOOTNOTE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FOOTNOTE; + } + break; + case PROPERTY_MAP_PARAGRAPH : + { + static SfxItemPropertySet aPROPERTY_MAP_PARAGRAPH(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_PARAGRAPH; + } + break; + case PROPERTY_MAP_EMBEDDED_OBJECT : + { + static SfxItemPropertySet aPROPERTY_MAP_EMBEDDED_OBJECT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_EMBEDDED_OBJECT; + } + break; + case PROPERTY_MAP_REDLINE : + { + static SfxItemPropertySet aPROPERTY_MAP_REDLINE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_REDLINE; + } + break; + case PROPERTY_MAP_TEXT_DEFAULT : + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_DEFAULT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_DEFAULT; + } + break; + case PROPERTY_MAP_FLDTYP_DATETIME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATETIME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATETIME; + } + break; + case PROPERTY_MAP_FLDTYP_USER: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_USER(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_USER; + } + break; + case PROPERTY_MAP_FLDTYP_SET_EXP: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_SET_EXP(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_SET_EXP; + } + break; + case PROPERTY_MAP_FLDTYP_GET_EXP: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_GET_EXP(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_GET_EXP; + } + break; + case PROPERTY_MAP_FLDTYP_FILE_NAME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_FILE_NAME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_FILE_NAME; + } + break; + case PROPERTY_MAP_FLDTYP_PAGE_NUM: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_PAGE_NUM(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_PAGE_NUM; + } + break; + case PROPERTY_MAP_FLDTYP_AUTHOR: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_AUTHOR(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_AUTHOR; + } + break; + case PROPERTY_MAP_FLDTYP_CHAPTER: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_CHAPTER(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_CHAPTER; + } + break; + case PROPERTY_MAP_FLDTYP_GET_REFERENCE: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_GET_REFERENCE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_GET_REFERENCE; + } + break; + case PROPERTY_MAP_FLDTYP_CONDITIONED_TEXT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_CONDITIONED_TEXT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_CONDITIONED_TEXT; + } + break; + case PROPERTY_MAP_FLDTYP_HIDDEN_TEXT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_HIDDEN_TEXT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_HIDDEN_TEXT; + } + break; + case PROPERTY_MAP_FLDTYP_ANNOTATION : + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_ANNOTATION(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_ANNOTATION; + } + break; + case PROPERTY_MAP_FLDTYP_INPUT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_INPUT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_INPUT; + } + break; + case PROPERTY_MAP_FLDTYP_MACRO: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_MACRO(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_MACRO; + } + break; + case PROPERTY_MAP_FLDTYP_DDE: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DDE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DDE; + } + break; + case PROPERTY_MAP_FLDTYP_HIDDEN_PARA: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_HIDDEN_PARA(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_HIDDEN_PARA; + } + break; + case PROPERTY_MAP_FLDTYP_DOC_INFO : + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOC_INFO(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOC_INFO; + } + break; + case PROPERTY_MAP_FLDTYP_TEMPLATE_NAME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_TEMPLATE_NAME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_TEMPLATE_NAME; + } + break; + case PROPERTY_MAP_FLDTYP_USER_EXT : + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_USER_EXT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_USER_EXT; + } + break; + case PROPERTY_MAP_FLDTYP_REF_PAGE_SET: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_REF_PAGE_SET(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_REF_PAGE_SET; + } + break; + case PROPERTY_MAP_FLDTYP_REF_PAGE_GET: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_REF_PAGE_GET(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_REF_PAGE_GET; + } + break; + case PROPERTY_MAP_FLDTYP_JUMP_EDIT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_JUMP_EDIT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_JUMP_EDIT; + } + break; + case PROPERTY_MAP_FLDTYP_SCRIPT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_SCRIPT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_SCRIPT; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATABASE_NEXT_SET; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NUM_SET: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATABASE_NUM_SET(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATABASE_NUM_SET; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_SET_NUM: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATABASE_SET_NUM(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATABASE_SET_NUM; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATABASE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATABASE; + } + break; + case PROPERTY_MAP_FLDTYP_DATABASE_NAME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DATABASE_NAME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DATABASE_NAME; + } + break; + case PROPERTY_MAP_FLDTYP_DOCSTAT: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCSTAT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCSTAT; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_AUTHOR; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_DATE_TIME; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_DATE_TIME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_DATE_TIME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_CHANGE_DATE_TIME; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_CREATE_DATE_TIME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_CREATE_DATE_TIME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_CREATE_DATE_TIME; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_EDIT_TIME; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_MISC : + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_MISC(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_MISC; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_REVISION: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_REVISION(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_REVISION; + } + break; + case PROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_COMBINED_CHARACTERS; + } + break; + case PROPERTY_MAP_FLDTYP_DUMMY_0: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DUMMY_0(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DUMMY_0; + } + break; + case PROPERTY_MAP_FLDTYP_TABLE_FORMULA: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_TABLE_FORMULA(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_TABLE_FORMULA; + } + break; + case PROPERTY_MAP_FLDMSTR_USER: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_USER(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_USER; + } + break; + case PROPERTY_MAP_FLDMSTR_DDE: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_DDE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_DDE; + } + break; + case PROPERTY_MAP_FLDMSTR_SET_EXP: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_SET_EXP(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_SET_EXP; + } + break; + case PROPERTY_MAP_FLDMSTR_DATABASE: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_DATABASE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_DATABASE; + } + break; + case PROPERTY_MAP_FLDMSTR_DUMMY0: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_DUMMY0(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_DUMMY0; + } + break; + case PROPERTY_MAP_FLDTYP_BIBLIOGRAPHY: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_BIBLIOGRAPHY(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_BIBLIOGRAPHY; + } + break; + case PROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDMSTR_BIBLIOGRAPHY; + } + break; + case PROPERTY_MAP_TEXT: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT; + } + break; + case PROPERTY_MAP_REDLINE_PORTION: + { + static SfxItemPropertySet aPROPERTY_MAP_REDLINE_PORTION(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_REDLINE_PORTION; + } + break; + case PROPERTY_MAP_MAILMERGE: + { + static SfxItemPropertySet aPROPERTY_MAP_MAILMERGE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_MAILMERGE; + } + break; + case PROPERTY_MAP_FLDTYP_DROPDOWN: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DROPDOWN(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DROPDOWN; + } + break; + case PROPERTY_MAP_CHART2_DATA_SEQUENCE: + { + static SfxItemPropertySet aPROPERTY_MAP_CHART2_DATA_SEQUENCE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CHART2_DATA_SEQUENCE; + } + break; + case PROPERTY_MAP_TEXT_VIEW: + { + static SfxItemPropertySet aPROPERTY_MAP_TEXT_VIEW(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_VIEW; + } + break; + case PROPERTY_MAP_CONDITIONAL_PARA_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_CONDITIONAL_PARA_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CONDITIONAL_PARA_STYLE; + } + break; + case PROPERTY_MAP_CHAR_AUTO_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_CHAR_AUTO_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CHAR_AUTO_STYLE; + } + break; + case PROPERTY_MAP_RUBY_AUTO_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_RUBY_AUTO_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_RUBY_AUTO_STYLE; + } + break; + case PROPERTY_MAP_PARA_AUTO_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_PARA_AUTO_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_PARA_AUTO_STYLE; + } + break; + case PROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM: + { + static SfxItemPropertySet aPROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FLDTYP_DOCINFO_CUSTOM; + } + break; + case PROPERTY_MAP_METAFIELD: + { + static SfxItemPropertySet aPROPERTY_MAP_METAFIELD(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_METAFIELD; + } + break; + case PROPERTY_MAP_TABLE_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_TABLE_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TABLE_STYLE; + } + break; + case PROPERTY_MAP_CELL_STYLE: + { + static SfxItemPropertySet aPROPERTY_MAP_CELL_STYLE(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CELL_STYLE; + } + break; + case PROPERTY_MAP_LINEBREAK: + { + static SfxItemPropertySet aPROPERTY_MAP_LINEBREAK(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_LINEBREAK; + } + break; + case PROPERTY_MAP_CONTENTCONTROL: + { + static SfxItemPropertySet aPROPERTY_MAP_CONTENTCONTROL(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CONTENTCONTROL; + } + break; + } + } + return m_aPropertySetArr[nPropertyId]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unomapproperties.hxx b/sw/source/core/unocore/unomapproperties.hxx new file mode 100644 index 0000000000..2330ba8608 --- /dev/null +++ b/sw/source/core/unocore/unomapproperties.hxx @@ -0,0 +1,584 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_SW_INC_UNOMAPPROPERTIES_HXX +#define INCLUDED_SW_INC_UNOMAPPROPERTIES_HXX + +// These are the unomap common properties used by unomap?.cxx + +#ifndef MID_TXT_LMARGIN +#define MID_TXT_LMARGIN 11 +#endif + +#define STANDARD_FONT_PROPERTIES \ + { UNO_NAME_CHAR_HEIGHT, RES_CHRATR_FONTSIZE , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS}, \ + { UNO_NAME_CHAR_WEIGHT, RES_CHRATR_WEIGHT , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT}, \ + { UNO_NAME_CHAR_FONT_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, \ + { UNO_NAME_CHAR_FONT_STYLE_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, \ + { UNO_NAME_CHAR_FONT_FAMILY, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, \ + { UNO_NAME_CHAR_FONT_CHAR_SET, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, \ + { UNO_NAME_CHAR_FONT_PITCH, RES_CHRATR_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, \ + { UNO_NAME_CHAR_POSTURE, RES_CHRATR_POSTURE , cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE}, \ + { UNO_NAME_RSID, RES_CHRATR_RSID, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_LOCALE, RES_CHRATR_LANGUAGE, cppu::UnoType<css::lang::Locale>::get(), PropertyAttribute::MAYBEVOID, MID_LANG_LOCALE }, \ + { UNO_NAME_CHAR_INTEROP_GRAB_BAG, RES_CHRATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, \ + +#define CJK_FONT_PROPERTIES \ + { UNO_NAME_CHAR_HEIGHT_ASIAN, RES_CHRATR_CJK_FONTSIZE , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS}, \ + { UNO_NAME_CHAR_WEIGHT_ASIAN, RES_CHRATR_CJK_WEIGHT , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT}, \ + { UNO_NAME_CHAR_FONT_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, \ + { UNO_NAME_CHAR_FONT_STYLE_NAME_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, \ + { UNO_NAME_CHAR_FONT_FAMILY_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, \ + { UNO_NAME_CHAR_FONT_CHAR_SET_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, \ + { UNO_NAME_CHAR_FONT_PITCH_ASIAN, RES_CHRATR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, \ + { UNO_NAME_CHAR_POSTURE_ASIAN, RES_CHRATR_CJK_POSTURE , cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE}, \ + { UNO_NAME_CHAR_LOCALE_ASIAN, RES_CHRATR_CJK_LANGUAGE , cppu::UnoType<css::lang::Locale>::get() , PropertyAttribute::MAYBEVOID, MID_LANG_LOCALE }, + +#define CTL_FONT_PROPERTIES \ + { UNO_NAME_CHAR_HEIGHT_COMPLEX, RES_CHRATR_CTL_FONTSIZE , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS},\ + { UNO_NAME_CHAR_WEIGHT_COMPLEX, RES_CHRATR_CTL_WEIGHT , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT}, \ + { UNO_NAME_CHAR_FONT_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, \ + { UNO_NAME_CHAR_FONT_STYLE_NAME_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_STYLE_NAME }, \ + { UNO_NAME_CHAR_FONT_FAMILY_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY }, \ + { UNO_NAME_CHAR_FONT_CHAR_SET_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, \ + { UNO_NAME_CHAR_FONT_PITCH_COMPLEX, RES_CHRATR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, \ + { UNO_NAME_CHAR_POSTURE_COMPLEX, RES_CHRATR_CTL_POSTURE , cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE}, \ + { UNO_NAME_CHAR_LOCALE_COMPLEX, RES_CHRATR_CTL_LANGUAGE , cppu::UnoType<css::lang::Locale>::get() , PropertyAttribute::MAYBEVOID, MID_LANG_LOCALE }, + +#define REDLINE_NODE_PROPERTIES \ + { UNO_NAME_START_REDLINE, FN_UNO_REDLINE_NODE_START , cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0xbf }, \ + { UNO_NAME_END_REDLINE, FN_UNO_REDLINE_NODE_END , cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0xbf }, + +#define REDLINE_PROPERTIES(readonly) \ + { UNO_NAME_REDLINE_AUTHOR, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_REDLINE_DATE_TIME, 0, cppu::UnoType<css::util::DateTime>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_REDLINE_COMMENT, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|readonly, 0},\ + { UNO_NAME_REDLINE_DESCRIPTION, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID | PropertyAttribute::READONLY, 0}, \ + { UNO_NAME_REDLINE_TYPE, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_REDLINE_SUCCESSOR_DATA, 0, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_REDLINE_IDENTIFIER, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_IS_IN_HEADER_FOOTER, 0, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_REDLINE_TEXT, 0, cppu::UnoType<css::text::XText>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + { UNO_NAME_MERGE_LAST_PARA, 0, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, + +#define COMMON_CRSR_PARA_PROPERTIES_FN_ONLY \ + { UNO_NAME_PARA_STYLE_NAME, FN_UNO_PARA_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_PAGE_STYLE_NAME, FN_UNO_PAGE_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0}, \ + { UNO_NAME_NUMBERING_IS_NUMBER, FN_UNO_IS_NUMBER, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_NUMBERING_LEVEL, FN_UNO_NUM_LEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_NUMBERING_RULES, FN_UNO_NUM_RULES, cppu::UnoType<css::container::XIndexReplace>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ + { UNO_NAME_NUMBERING_START_VALUE, FN_UNO_NUM_START_VALUE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ + { UNO_NAME_DOCUMENT_INDEX, FN_UNO_DOCUMENT_INDEX, cppu::UnoType<css::text::XDocumentIndex>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_TEXT_TABLE, FN_UNO_TEXT_TABLE, cppu::UnoType<css::text::XTextTable>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_CELL, FN_UNO_CELL, cppu::UnoType<css::table::XCell>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_TEXT_FRAME, FN_UNO_TEXT_FRAME, cppu::UnoType<css::text::XTextFrame>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_TEXT_SECTION, FN_UNO_TEXT_SECTION, cppu::UnoType<css::text::XTextSection>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_TEXT_PARAGRAPH, FN_UNO_TEXT_PARAGRAPH, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_SORTED_TEXT_ID, FN_UNO_SORTED_TEXT_ID, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 }, \ + { UNO_NAME_PARA_CHAPTER_NUMBERING_LEVEL, FN_UNO_PARA_CHAPTER_NUMBERING_LEVEL,cppu::UnoType<sal_Int8>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, FN_UNO_PARA_CONDITIONAL_STYLE_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, \ + { UNO_NAME_LIST_ID, FN_UNO_LIST_ID, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_PARA_IS_NUMBERING_RESTART, FN_NUMBER_NEWSTART, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE, FN_UNO_PARA_CONT_PREV_SUBTREE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0 }, \ + { UNO_NAME_PARA_LIST_LABEL_STRING, FN_UNO_PARA_NUM_STRING, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 }, \ + { UNO_NAME_PARA_LIST_AUTO_FORMAT, FN_UNO_PARA_NUM_AUTO_FORMAT, cppu::UnoType<cppu::UnoSequenceType<css::beans::NamedValue>>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_OUTLINE_LEVEL, RES_PARATR_OUTLINELEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_OUTLINE_CONTENT_VISIBLE, RES_PARATR_GRABBAG, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, + +#define COMMON_HYPERLINK_PROPERTIES \ + { UNO_NAME_HYPER_LINK_U_R_L, RES_TXTATR_INETFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_URL_URL}, \ + { UNO_NAME_HYPER_LINK_TARGET, RES_TXTATR_INETFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_URL_TARGET}, \ + { UNO_NAME_HYPER_LINK_NAME, RES_TXTATR_INETFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_URL_HYPERLINKNAME }, \ + { UNO_NAME_UNVISITED_CHAR_STYLE_NAME, RES_TXTATR_INETFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_URL_UNVISITED_FMT }, \ + { UNO_NAME_VISITED_CHAR_STYLE_NAME, RES_TXTATR_INETFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_URL_VISITED_FMT }, + +// same as COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN but without +// UNO_NAME_BREAK_TYPE and UNO_NAME_PAGE_DESC_NAME which can not be used +// by the SwXTextTableCursor +#define COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 \ + { UNO_NAME_PARRSID, RES_PARATR_RSID, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_IS_HYPHENATION, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_IS_HYPHEN }, \ + { UNO_NAME_PARA_HYPHENATION_NO_CAPS, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_NO_CAPS }, \ + { UNO_NAME_PARA_HYPHENATION_NO_LAST_WORD, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_NO_LAST_WORD }, \ + { UNO_NAME_PARA_HYPHENATION_MAX_LEADING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_LEAD }, \ + { UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_TRAIL }, \ + { UNO_NAME_PARA_HYPHENATION_MAX_HYPHENS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MAX_HYPHENS }, \ + { UNO_NAME_PARA_HYPHENATION_MIN_WORD_LENGTH, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_WORD_LENGTH }, \ + { UNO_NAME_PARA_HYPHENATION_ZONE, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_ZONE}, \ + { UNO_NAME_CHAR_AUTO_KERNING, RES_CHRATR_AUTOKERN, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \ + { UNO_NAME_CHAR_BACKGROUND_COMPLEX_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR },\ + { UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \ + { UNO_NAME_PARA_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \ + { UNO_NAME_PARA_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE , MID_BACKGROUND_COMPLEX_COLOR },\ + { UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_THEME_INDEX }, \ + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_TINT_OR_SHADE }, \ + { UNO_NAME_CHAR_COMPLEX_COLOR , RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_ALPHA }, \ + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT }, \ + { UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_CROSSED_OUT }, \ + { UNO_NAME_CHAR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_ESC }, \ + { UNO_NAME_CHAR_ESCAPEMENT_HEIGHT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int8>::get(), PropertyAttribute::MAYBEVOID, MID_ESC_HEIGHT }, \ + { UNO_NAME_CHAR_AUTO_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_AUTO_ESC }, \ + { UNO_NAME_CHAR_FLASH, RES_CHRATR_BLINK, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_HIDDEN, RES_CHRATR_HIDDEN, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_TL_STYLE }, \ + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COLOR }, \ + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_UNDERLINE_HAS_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_TL_HASCOLOR }, \ + { UNO_NAME_CHAR_OVERLINE, RES_CHRATR_OVERLINE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_TL_STYLE }, \ + { UNO_NAME_CHAR_OVERLINE_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COLOR }, \ + { UNO_NAME_CHAR_OVERLINE_COMPLEX_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_TL_HASCOLOR }, \ + { UNO_NAME_PARA_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_URL }, \ + { UNO_NAME_PARA_GRAPHIC, RES_BACKGROUND, cppu::UnoType<css::graphic::XGraphic>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC }, \ + { UNO_NAME_PARA_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_FILTER }, \ + { UNO_NAME_PARA_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_POSITION }, \ + { UNO_NAME_PARA_LEFT_MARGIN, RES_MARGIN_TEXTLEFT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TXT_LMARGIN | CONVERT_TWIPS }, \ + { UNO_NAME_PARA_RIGHT_MARGIN, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_R_MARGIN | CONVERT_TWIPS }, \ + { UNO_NAME_PARA_IS_AUTO_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_AUTO }, \ + { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_INDENT | CONVERT_TWIPS }, \ + STANDARD_FONT_PROPERTIES \ + CJK_FONT_PROPERTIES \ + CTL_FONT_PROPERTIES \ + { UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_DROP_CAP_FORMAT, RES_PARATR_DROP, cppu::UnoType<css::style::DropCapFormat>::get(), PropertyAttribute::MAYBEVOID, MID_DROPCAP_FORMAT | CONVERT_TWIPS }, \ + { UNO_NAME_DROP_CAP_WHOLE_WORD, RES_PARATR_DROP, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_DROPCAP_WHOLE_WORD }, \ + { UNO_NAME_DROP_CAP_CHAR_STYLE_NAME, RES_PARATR_DROP, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_DROPCAP_CHAR_STYLE_NAME }, \ + { UNO_NAME_PARA_KEEP_TOGETHER, RES_KEEP, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_SPLIT, RES_PARATR_SPLIT, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_WIDOWS, RES_PARATR_WIDOWS, cppu::UnoType<sal_Int8>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_ORPHANS, RES_PARATR_ORPHANS, cppu::UnoType<sal_Int8>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PAGE_NUMBER_OFFSET, RES_PAGEDESC, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PAGEDESC_PAGENUMOFFSET }, \ + { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST }, \ + { UNO_NAME_PARA_EXPAND_SINGLE_WORD, RES_PARATR_ADJUST, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_EXPAND_SINGLE }, \ + { UNO_NAME_PARA_LAST_LINE_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_LAST_LINE_ADJUST }, \ + { UNO_NAME_PARA_LINE_NUMBER_COUNT, RES_LINENUMBER, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_LINENUMBER_COUNT }, \ + { UNO_NAME_PARA_LINE_NUMBER_START_VALUE, RES_LINENUMBER, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_LINENUMBER_STARTVALUE }, \ + { UNO_NAME_PARA_LINE_SPACING, RES_PARATR_LINESPACING, cppu::UnoType<css::style::LineSpacing>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, \ + { UNO_NAME_PARA_REGISTER_MODE_ACTIVE, RES_PARATR_REGISTER, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_UP_MARGIN | CONVERT_TWIPS }, \ + { UNO_NAME_PARA_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_LO_MARGIN | CONVERT_TWIPS }, \ + { UNO_NAME_PARA_CONTEXT_MARGIN, RES_UL_SPACE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_CTX_MARGIN }, \ + { UNO_NAME_CHAR_BACK_TRANSPARENT, RES_CHRATR_BACKGROUND, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_TRANSPARENT }, \ + { UNO_NAME_PARA_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_GRAPHIC_TRANSPARENT }, \ + { UNO_NAME_NUMBERING_STYLE_NAME, RES_PARATR_NUMRULE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_WORD_MODE, RES_CHRATR_WORDLINEMODE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_LEFT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, LEFT_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_RIGHT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, RIGHT_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_TOP_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, TOP_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_BOTTOM_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, BOTTOM_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_LEFT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, LEFT_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_RIGHT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_TOP_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, TOP_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_BOTTOM_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_BORDER_LEFT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_LEFT_COLOR }, \ + { UNO_NAME_CHAR_BORDER_RIGHT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_RIGHT_COLOR }, \ + { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, \ + { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, \ + { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS }, \ + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, LEFT_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, RIGHT_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, TOP_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), PropertyAttribute::MAYBEVOID, BOTTOM_BORDER | CONVERT_TWIPS }, \ + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, LEFT_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, TOP_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS }, \ + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_LEFT_COLOR }, \ + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_RIGHT_COLOR }, \ + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, \ + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, \ + { UNO_NAME_PARA_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_TEXT_USER_DEFINED_ATTRIBUTES, RES_TXTATR_UNKNOWN_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS }, \ + { UNO_NAME_CHAR_COMBINE_IS_ON, RES_CHRATR_TWO_LINES, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_TWOLINES }, \ + { UNO_NAME_CHAR_COMBINE_PREFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_START_BRACKET }, \ + { UNO_NAME_CHAR_COMBINE_SUFFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_END_BRACKET }, \ + { UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_EMPHASIS }, \ + { UNO_NAME_PARA_IS_HANGING_PUNCTUATION, RES_PARATR_HANGINGPUNCTUATION, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_IS_CHARACTER_DISTANCE, RES_PARATR_SCRIPTSPACE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_IS_FORBIDDEN_RULES, RES_PARATR_FORBIDDEN_RULES, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_VERT_ALIGNMENT, RES_PARATR_VERTALIGN, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_CHAR_ROTATION, RES_CHRATR_ROTATE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_ROTATE }, \ + { UNO_NAME_CHAR_ROTATION_IS_FIT_TO_LINE, RES_CHRATR_ROTATE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_FITTOLINE }, \ + { UNO_NAME_CHAR_SCALE_WIDTH, RES_CHRATR_SCALEW, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_RUBY_TEXT, RES_TXTATR_CJK_RUBY, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_TEXT }, \ + { UNO_NAME_RUBY_ADJUST, RES_TXTATR_CJK_RUBY, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_ADJUST }, \ + { UNO_NAME_RUBY_CHAR_STYLE_NAME, RES_TXTATR_CJK_RUBY, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_CHARSTYLE }, \ + { UNO_NAME_RUBY_POSITION, RES_TXTATR_CJK_RUBY, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_POSITION}, \ + { UNO_NAME_RUBY_IS_ABOVE, RES_TXTATR_CJK_RUBY, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_RUBY_ABOVE }, \ + { UNO_NAME_CHAR_RELIEF, RES_CHRATR_RELIEF, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_RELIEF }, \ + { UNO_NAME_SNAP_TO_GRID, RES_PARATR_SNAPTOGRID, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_PARA_IS_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 }, \ + { UNO_NAME_CHAR_SHADING_VALUE, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_SHADING_VALUE }, \ + { UNO_NAME_PARA_INTEROP_GRAB_BAG, RES_PARATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, \ + +#define COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN \ + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 \ + { UNO_NAME_BREAK_TYPE, RES_BREAK, cppu::UnoType<css::style::BreakType>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_PAGE_DESC_NAME, RES_PAGEDESC, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_PAGEDESC_PAGEDESCNAME }, + +#define TABSTOPS_MAP_ENTRY { UNO_NAME_TABSTOPS, RES_PARATR_TABSTOP, cppu::UnoType< cppu::UnoSequenceType<css::style::TabStop> >::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, + +#define COMMON_CRSR_PARA_PROPERTIES \ + COMMON_CRSR_PARA_PROPERTIES_FN_ONLY \ + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN \ + COMMON_HYPERLINK_PROPERTIES \ + { UNO_NAME_CHAR_STYLE_NAME, RES_TXTATR_CHARFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_CHAR_STYLE_NAMES, FN_UNO_CHARFMT_SEQUENCE, cppu::UnoType< cppu::UnoSequenceType<OUString> >::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_CHAR_AUTO_STYLE_NAME, RES_TXTATR_AUTOFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_PARA_AUTO_STYLE_NAME, RES_AUTO_STYLE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0}, + +#define COMMON_CRSR_PARA_PROPERTIES_2 \ + COMMON_CRSR_PARA_PROPERTIES_FN_ONLY \ + COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN + +#define COMPLETE_TEXT_CURSOR_MAP\ + COMMON_CRSR_PARA_PROPERTIES\ + { UNO_NAME_DOCUMENT_INDEX_MARK, FN_UNO_DOCUMENT_INDEX_MARK, cppu::UnoType<css::text::XDocumentIndexMark>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 },\ + { UNO_NAME_TEXT_FIELD, FN_UNO_TEXT_FIELD, cppu::UnoType<css::text::XTextField>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 },\ + { UNO_NAME_REFERENCE_MARK, FN_UNO_REFERENCE_MARK, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 },\ + { UNO_NAME_FOOTNOTE, FN_UNO_FOOTNOTE, cppu::UnoType<css::text::XFootnote>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 },\ + { UNO_NAME_ENDNOTE, FN_UNO_ENDNOTE, cppu::UnoType<css::text::XFootnote>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY ,0 },\ + { UNO_NAME_HYPER_LINK_EVENTS, RES_TXTATR_INETFMT, cppu::UnoType<css::container::XNameReplace>::get(), PropertyAttribute::MAYBEVOID, MID_URL_HYPERLINKEVENTS},\ + { UNO_NAME_NESTED_TEXT_CONTENT, FN_UNO_NESTED_TEXT_CONTENT, cppu::UnoType<css::text::XTextContent>::get(), PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0 },\ + TABSTOPS_MAP_ENTRY + +#define BASE_INDEX_PROPERTIES_\ + { UNO_NAME_TITLE, WID_IDX_TITLE, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_NAME, WID_IDX_NAME, cppu::UnoType<OUString>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CONTENT_SECTION, WID_IDX_CONTENT_SECTION, cppu::UnoType<css::text::XTextSection>::get() , PropertyAttribute::READONLY, 0},\ + { UNO_NAME_HEADER_SECTION, WID_IDX_HEADER_SECTION, cppu::UnoType<css::text::XTextSection>::get() , PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, 0},\ + +#define ANCHOR_TYPES_PROPERTY { UNO_NAME_ANCHOR_TYPES, FN_UNO_ANCHOR_TYPES, cppu::UnoType< cppu::UnoSequenceType<css::text::TextContentAnchorType> >::get(),PropertyAttribute::READONLY, 0xbf}, + +// #i18732# #i28701# #i73249# +// all users of COMMON_FRAME_PROPERTIES add the new XATTR_FILL_FIRST, XATTR_FILL_LAST FillStyle, +// thus it may be possible to remove the RES_BACKGROUND entries from SvxBrushItem completely (this includes +// all using UNO_NAME_BACK_* slots) in the future +#define COMMON_FRAME_PROPERTIES \ + { UNO_NAME_ANCHOR_PAGE_NO, RES_ANCHOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ANCHOR_PAGENUM }, \ + { UNO_NAME_ANCHOR_TYPE, RES_ANCHOR, cppu::UnoType<css::text::TextContentAnchorType>::get(), PROPERTY_NONE, MID_ANCHOR_ANCHORTYPE}, \ + { UNO_NAME_ANCHOR_FRAME, RES_ANCHOR, cppu::UnoType<css::text::XTextFrame>::get(), PropertyAttribute::MAYBEVOID, MID_ANCHOR_ANCHORFRAME}, \ + ANCHOR_TYPES_PROPERTY\ + { UNO_NAME_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, \ + { UNO_NAME_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE ,MID_BACKGROUND_COMPLEX_COLOR }, \ + { UNO_NAME_BACK_COLOR_R_G_B, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR_R_G_B}, \ + { UNO_NAME_BACK_COLOR_TRANSPARENCY, RES_BACKGROUND, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE ,MID_BACK_COLOR_TRANSPARENCY}, \ + { UNO_NAME_FRAME_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_CONTENT_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_CONTENT }, \ + { UNO_NAME_FRAME_STYLE_NAME, FN_UNO_FRAME_STYLE_NAME,cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_BACK_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL }, \ + { UNO_NAME_BACK_GRAPHIC, RES_BACKGROUND, cppu::UnoType<css::graphic::XGraphic>::get(), PROPERTY_NONE, MID_GRAPHIC }, \ + { UNO_NAME_BACK_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER }, \ + { UNO_NAME_BACK_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, \ + { UNO_NAME_BACK_GRAPHIC_TRANSPARENCY, RES_BACKGROUND, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENCY}, \ + { UNO_NAME_LEFT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_L_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_RIGHT_MARGIN, RES_LR_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH|CONVERT_TWIPS},\ + { UNO_NAME_HEIGHT, RES_FRM_SIZE, cppu::UnoType<sal_Int32>::get() , PROPERTY_NONE, MID_FRMSIZE_HEIGHT|CONVERT_TWIPS},\ + { UNO_NAME_HORI_ORIENT, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_HORIORIENT_ORIENT }, \ + { UNO_NAME_HORI_ORIENT_POSITION, RES_HORI_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_HORIORIENT_POSITION|CONVERT_TWIPS }, \ + { UNO_NAME_HORI_ORIENT_RELATION, RES_HORI_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_HORIORIENT_RELATION }, \ + { UNO_NAME_HYPER_LINK_U_R_L, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_URL}, \ + { UNO_NAME_HYPER_LINK_TARGET, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_TARGET}, \ + { UNO_NAME_HYPER_LINK_NAME, RES_URL, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_URL_HYPERLINKNAME }, \ + { UNO_NAME_OPAQUE, RES_OPAQUE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_PAGE_TOGGLE, RES_HORI_ORIENT, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_HORIORIENT_PAGETOGGLE }, \ + { UNO_NAME_POSITION_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_POSITION}, \ + { UNO_NAME_PRINT, RES_PRINT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_RELATIVE_HEIGHT, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT }, \ + { UNO_NAME_RELATIVE_HEIGHT_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT_RELATION }, \ + { UNO_NAME_RELATIVE_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH }, \ + { UNO_NAME_RELATIVE_WIDTH_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH_RELATION }, \ + { UNO_NAME_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, \ + { UNO_NAME_SHADOW_TRANSPARENCE, RES_SHADOW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_SHADOW_TRANSPARENCE}, \ + { UNO_NAME_IMAGE_MAP, RES_URL, cppu::UnoType<css::container::XIndexContainer>::get(), PROPERTY_NONE, MID_URL_CLIENTMAP}, \ + { UNO_NAME_SERVER_MAP, RES_URL, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_URL_SERVERMAP }, \ + { UNO_NAME_SIZE, RES_FRM_SIZE, cppu::UnoType<css::awt::Size>::get(), PROPERTY_NONE, MID_FRMSIZE_SIZE|CONVERT_TWIPS}, \ + { UNO_NAME_SIZE_PROTECTED, RES_PROTECT, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_PROTECT_SIZE }, \ + { UNO_NAME_IS_SYNC_WIDTH_TO_HEIGHT, RES_FRM_SIZE, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT }, \ + { UNO_NAME_IS_SYNC_HEIGHT_TO_WIDTH, RES_FRM_SIZE, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH }, \ + { UNO_NAME_TEXT_WRAP, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE, MID_SURROUND_SURROUNDTYPE }, \ + { UNO_NAME_SURROUND, RES_SURROUND, cppu::UnoType<css::text::WrapTextMode>::get(), PROPERTY_NONE, MID_SURROUND_SURROUNDTYPE }, \ + { UNO_NAME_SURROUND_ANCHORONLY, RES_SURROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_SURROUND_ANCHORONLY }, \ + { UNO_NAME_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT }, \ + { UNO_NAME_VERT_ORIENT, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_ORIENT }, \ + { UNO_NAME_VERT_ORIENT_POSITION, RES_VERT_ORIENT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_VERTORIENT_POSITION|CONVERT_TWIPS }, \ + { UNO_NAME_VERT_ORIENT_RELATION, RES_VERT_ORIENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE ,MID_VERTORIENT_RELATION }, \ + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS }, \ + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS }, \ + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS }, \ + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS }, \ + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE|CONVERT_TWIPS }, \ + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS }, \ + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS }, \ + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS }, \ + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS }, \ + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_LEFT_COLOR }, \ + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_RIGHT_COLOR }, \ + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_TOP_COLOR }, \ + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_BOTTOM_COLOR }, \ + { UNO_LINK_DISPLAY_NAME, FN_PARAM_LINK_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0xbf}, \ + { UNO_NAME_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 },\ + { UNO_NAME_Z_ORDER, FN_UNO_Z_ORDER, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_IS_FOLLOWING_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FOLLOW_TEXT_FLOW}, \ + { UNO_NAME_PARENT_TEXT, FN_UNO_PARENT_TEXT, cppu::UnoType<text::XText>::get(), PropertyAttribute::MAYBEVOID | PropertyAttribute::READONLY, 0 }, \ + { UNO_NAME_WRAP_INFLUENCE_ON_POSITION, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<sal_Int8>::get(), PROPERTY_NONE, MID_WRAP_INFLUENCE}, \ + { UNO_NAME_ALLOW_OVERLAP, RES_WRAP_INFLUENCE_ON_OBJPOS, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_ALLOW_OVERLAP}, \ + { UNO_NAME_TITLE, FN_UNO_TITLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_TOOLTIP, FN_UNO_TOOLTIP, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_DESCRIPTION, FN_UNO_DESCRIPTION, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_LAYOUT_SIZE, WID_LAYOUT_SIZE, cppu::UnoType<css::awt::Size>::get(), PropertyAttribute::MAYBEVOID | PropertyAttribute::READONLY, 0 }, \ + { UNO_NAME_LINE_STYLE, RES_BOX, cppu::UnoType<css::drawing::LineStyle>::get(), 0, LINE_STYLE }, \ + { UNO_NAME_LINE_WIDTH, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LINE_WIDTH |CONVERT_TWIPS }, \ + { u"Decorative"_ustr, RES_DECORATIVE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, \ + { UNO_NAME_TEXT_VERT_ADJUST, RES_TEXT_VERT_ADJUST, cppu::UnoType<css::drawing::TextVerticalAdjust>::get(), PROPERTY_NONE ,0}, + +#define COMMON_TEXT_CONTENT_PROPERTIES \ + { UNO_NAME_ANCHOR_TYPE, FN_UNO_ANCHOR_TYPE, cppu::UnoType<css::text::TextContentAnchorType>::get(), PropertyAttribute::READONLY, MID_ANCHOR_ANCHORTYPE},\ + ANCHOR_TYPES_PROPERTY\ + { UNO_NAME_TEXT_WRAP, FN_UNO_TEXT_WRAP, cppu::UnoType<css::text::WrapTextMode>::get(), PropertyAttribute::READONLY, MID_SURROUND_SURROUNDTYPE }, + +#define PROP_DIFF_FONTHEIGHT \ + { UNO_NAME_CHAR_PROP_HEIGHT, RES_CHRATR_FONTSIZE , cppu::UnoType<float>::get(), PROPERTY_NONE , MID_FONTHEIGHT_PROP},\ + { UNO_NAME_CHAR_DIFF_HEIGHT, RES_CHRATR_FONTSIZE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_FONTHEIGHT_DIFF|CONVERT_TWIPS},\ + { UNO_NAME_CHAR_PROP_HEIGHT_ASIAN, RES_CHRATR_CJK_FONTSIZE , cppu::UnoType<float>::get(), PROPERTY_NONE , MID_FONTHEIGHT_PROP},\ + { UNO_NAME_CHAR_DIFF_HEIGHT_ASIAN, RES_CHRATR_CJK_FONTSIZE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_FONTHEIGHT_DIFF|CONVERT_TWIPS},\ + { UNO_NAME_CHAR_PROP_HEIGHT_COMPLEX, RES_CHRATR_CTL_FONTSIZE , cppu::UnoType<float>::get(), PROPERTY_NONE , MID_FONTHEIGHT_PROP},\ + { UNO_NAME_CHAR_DIFF_HEIGHT_COMPLEX, RES_CHRATR_CTL_FONTSIZE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , MID_FONTHEIGHT_DIFF|CONVERT_TWIPS}, + +#define COMMON_PARA_STYLE_PROPERTIES \ + { UNO_NAME_BREAK_TYPE, RES_BREAK, cppu::UnoType<css::style::BreakType>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_PAGE_DESC_NAME, RES_PAGEDESC, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_PAGEDESC_PAGEDESCNAME },\ + { UNO_NAME_PAGE_NUMBER_OFFSET, RES_PAGEDESC, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PAGEDESC_PAGENUMOFFSET},\ + { UNO_NAME_CHAR_AUTO_KERNING, RES_CHRATR_AUTOKERN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_BACK_TRANSPARENT, RES_CHRATR_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT },\ + { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR },\ + { UNO_NAME_CHAR_BACKGROUND_COMPLEX_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR },\ + { UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR },\ + { UNO_NAME_PARA_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR },\ + { UNO_NAME_PARA_BACKGROUND_COMPLEX_COLOR, RES_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE , MID_BACKGROUND_COMPLEX_COLOR },\ + { UNO_NAME_PARA_BACK_TRANSPARENT, RES_BACKGROUND, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_GRAPHIC_TRANSPARENT },\ + { UNO_NAME_PARA_GRAPHIC_URL, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_URL },\ + { UNO_NAME_PARA_GRAPHIC, RES_BACKGROUND, cppu::UnoType<css::graphic::XGraphic>::get(), PROPERTY_NONE ,MID_GRAPHIC },\ + { UNO_NAME_PARA_GRAPHIC_FILTER, RES_BACKGROUND, cppu::UnoType<OUString>::get(), PROPERTY_NONE ,MID_GRAPHIC_FILTER },\ + { UNO_NAME_PARA_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, \ + { UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, \ + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE }, \ + { UNO_NAME_CHAR_COMPLEX_COLOR, RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA},\ + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT},\ + { UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ESC },\ + { UNO_NAME_CHAR_ESCAPEMENT_HEIGHT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int8>::get() , PROPERTY_NONE, MID_ESC_HEIGHT},\ + { UNO_NAME_CHAR_FLASH, RES_CHRATR_BLINK , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_HIDDEN, RES_CHRATR_HIDDEN, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + STANDARD_FONT_PROPERTIES\ + CJK_FONT_PROPERTIES\ + CTL_FONT_PROPERTIES\ + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE},\ + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR},\ + { UNO_NAME_CHAR_UNDERLINE_HAS_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR},\ + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_OVERLINE, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_TL_STYLE},\ + { UNO_NAME_CHAR_OVERLINE_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TL_COLOR},\ + { UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE , cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR},\ + { UNO_NAME_CHAR_OVERLINE_COMPLEX_COLOR, RES_CHRATR_OVERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR }, \ + { UNO_NAME_PARA_LEFT_MARGIN, RES_MARGIN_TEXTLEFT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_TXT_LMARGIN|CONVERT_TWIPS},\ + { UNO_NAME_PARA_RIGHT_MARGIN, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_R_MARGIN|CONVERT_TWIPS},\ + { UNO_NAME_PARA_LEFT_MARGIN_RELATIVE, RES_MARGIN_TEXTLEFT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_L_REL_MARGIN},\ + { UNO_NAME_PARA_RIGHT_MARGIN_RELATIVE, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_R_REL_MARGIN},\ + { UNO_NAME_PARA_IS_AUTO_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FIRST_AUTO},\ + { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FIRST_LINE_INDENT|CONVERT_TWIPS},\ + { UNO_NAME_PARA_FIRST_LINE_INDENT_RELATIVE, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FIRST_LINE_REL_INDENT|CONVERT_TWIPS},\ + { UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS},\ + { UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_DROP_CAP_FORMAT, RES_PARATR_DROP, cppu::UnoType<css::style::DropCapFormat>::get() , PROPERTY_NONE, MID_DROPCAP_FORMAT|CONVERT_TWIPS },\ + { UNO_NAME_DROP_CAP_WHOLE_WORD, RES_PARATR_DROP, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_DROPCAP_WHOLE_WORD },\ + { UNO_NAME_DROP_CAP_CHAR_STYLE_NAME, RES_PARATR_DROP, cppu::UnoType<OUString>::get() , PropertyAttribute::MAYBEVOID, MID_DROPCAP_CHAR_STYLE_NAME },\ + { UNO_NAME_PARA_KEEP_TOGETHER, RES_KEEP, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_PARA_SPLIT, RES_PARATR_SPLIT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_PARA_WIDOWS, RES_PARATR_WIDOWS, cppu::UnoType<sal_Int8>::get(),PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_PARA_ORPHANS, RES_PARATR_ORPHANS, cppu::UnoType<sal_Int8>::get(),PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_PARA_EXPAND_SINGLE_WORD, RES_PARATR_ADJUST, cppu::UnoType<bool>::get() , PROPERTY_NONE, MID_EXPAND_SINGLE },\ + { UNO_NAME_PARA_LAST_LINE_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_LAST_LINE_ADJUST},\ + { UNO_NAME_PARA_LINE_NUMBER_COUNT, RES_LINENUMBER, cppu::UnoType<bool>::get(), PROPERTY_NONE ,MID_LINENUMBER_COUNT },\ + { UNO_NAME_PARA_LINE_NUMBER_START_VALUE, RES_LINENUMBER, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_LINENUMBER_STARTVALUE},\ + { UNO_NAME_PARA_LINE_SPACING, RES_PARATR_LINESPACING, cppu::UnoType<css::style::LineSpacing>::get(),PROPERTY_NONE, CONVERT_TWIPS},\ + { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_PARA_ADJUST},\ + { UNO_NAME_PARA_REGISTER_MODE_ACTIVE, RES_PARATR_REGISTER, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_PARA_TOP_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_UP_MARGIN|CONVERT_TWIPS},\ + { UNO_NAME_PARA_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_LO_MARGIN|CONVERT_TWIPS},\ + { UNO_NAME_PARA_CONTEXT_MARGIN, RES_UL_SPACE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_CTX_MARGIN},\ + { UNO_NAME_PARA_TOP_MARGIN_RELATIVE, RES_UL_SPACE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_UP_REL_MARGIN},\ + { UNO_NAME_PARA_BOTTOM_MARGIN_RELATIVE, RES_UL_SPACE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_LO_REL_MARGIN},\ + TABSTOPS_MAP_ENTRY\ + { UNO_NAME_CHAR_WORD_MODE, RES_CHRATR_WORDLINEMODE,cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ + { UNO_NAME_CHAR_SHADING_VALUE, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_SHADING_VALUE }, \ + { UNO_NAME_CHAR_LEFT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, LEFT_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_RIGHT_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, RIGHT_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_TOP_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, TOP_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_BOTTOM_BORDER, RES_CHRATR_BOX, cppu::UnoType<css::table::BorderLine>::get(), PROPERTY_NONE, BOTTOM_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_LEFT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, LEFT_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_RIGHT_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_TOP_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, TOP_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_CHAR_BOTTOM_BORDER_DISTANCE, RES_CHRATR_BOX, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS },\ + { UNO_NAME_CHAR_BORDER_LEFT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_LEFT_COLOR }, \ + { UNO_NAME_CHAR_BORDER_RIGHT_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_RIGHT_COLOR }, \ + { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, \ + { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, \ + { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS},\ + { UNO_NAME_LEFT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, LEFT_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_RIGHT_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, RIGHT_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_TOP_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, TOP_BORDER |CONVERT_TWIPS },\ + { UNO_NAME_BOTTOM_BORDER, RES_BOX, cppu::UnoType<css::table::BorderLine>::get(), 0, BOTTOM_BORDER|CONVERT_TWIPS },\ + { UNO_NAME_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE|CONVERT_TWIPS },\ + { UNO_NAME_LEFT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_RIGHT_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_TOP_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE |CONVERT_TWIPS },\ + { UNO_NAME_BOTTOM_BORDER_DISTANCE, RES_BOX, cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE|CONVERT_TWIPS },\ + { UNO_NAME_BORDER_LEFT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_LEFT_COLOR }, \ + { UNO_NAME_BORDER_RIGHT_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_RIGHT_COLOR }, \ + { UNO_NAME_BORDER_TOP_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_TOP_COLOR }, \ + { UNO_NAME_BORDER_BOTTOM_COMPLEX_COLOR, RES_BOX, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_BORDER_BOTTOM_COLOR }, \ + { UNO_NAME_PARA_IS_HYPHENATION, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_IS_HYPHEN },\ + { UNO_NAME_PARA_HYPHENATION_NO_CAPS, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_NO_CAPS },\ + { UNO_NAME_PARA_HYPHENATION_NO_LAST_WORD, RES_PARATR_HYPHENZONE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_NO_LAST_WORD },\ + { UNO_NAME_PARA_HYPHENATION_MAX_LEADING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_LEAD },\ + { UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_TRAIL },\ + { UNO_NAME_PARA_HYPHENATION_MAX_HYPHENS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MAX_HYPHENS},\ + { UNO_NAME_PARA_HYPHENATION_MIN_WORD_LENGTH, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_WORD_LENGTH},\ + { UNO_NAME_PARA_HYPHENATION_ZONE, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_ZONE},\ + { UNO_NAME_NUMBERING_STYLE_NAME, RES_PARATR_NUMRULE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_NUMBERING_LEVEL, RES_PARATR_LIST_LEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_PARA_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 },\ + { UNO_NAME_PARA_SHADOW_FORMAT, RES_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS},\ + { UNO_NAME_CHAR_COMBINE_IS_ON, RES_CHRATR_TWO_LINES, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TWOLINES},\ + { UNO_NAME_CHAR_COMBINE_PREFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_START_BRACKET},\ + { UNO_NAME_CHAR_COMBINE_SUFFIX, RES_CHRATR_TWO_LINES, cppu::UnoType<OUString>::get(), PROPERTY_NONE, MID_END_BRACKET},\ + { UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_EMPHASIS},\ + { UNO_NAME_PARA_IS_HANGING_PUNCTUATION, RES_PARATR_HANGINGPUNCTUATION, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 },\ + { UNO_NAME_PARA_IS_CHARACTER_DISTANCE, RES_PARATR_SCRIPTSPACE, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 },\ + { UNO_NAME_PARA_IS_FORBIDDEN_RULES, RES_PARATR_FORBIDDEN_RULES, cppu::UnoType<bool>::get(), PROPERTY_NONE ,0 },\ + { UNO_NAME_PARA_VERT_ALIGNMENT, RES_PARATR_VERTALIGN, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , 0 },\ + { UNO_NAME_CHAR_ROTATION, RES_CHRATR_ROTATE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ROTATE },\ + { UNO_NAME_CHAR_ROTATION_IS_FIT_TO_LINE, RES_CHRATR_ROTATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FITTOLINE },\ + { UNO_NAME_CHAR_SCALE_WIDTH, RES_CHRATR_SCALEW, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 },\ + { UNO_NAME_CHAR_RELIEF, RES_CHRATR_RELIEF, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_RELIEF },\ + PROP_DIFF_FONTHEIGHT\ + { UNO_NAME_FOLLOW_STYLE, FN_UNO_FOLLOW_STYLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_LINK_STYLE, FN_UNO_LINK_STYLE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_IS_PHYSICAL, FN_UNO_IS_PHYSICAL, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY, 0},\ + { UNO_NAME_IS_AUTO_UPDATE, FN_UNO_IS_AUTO_UPDATE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},\ + { UNO_NAME_DISPLAY_NAME, FN_UNO_DISPLAY_NAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0},\ + { UNO_NAME_CATEGORY, FN_UNO_CATEGORY, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE , 0 },\ + { UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 },\ + { UNO_NAME_PARA_IS_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0},\ + { UNO_NAME_SNAP_TO_GRID, RES_PARATR_SNAPTOGRID, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \ + { UNO_NAME_OUTLINE_LEVEL, RES_PARATR_OUTLINELEVEL,cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_HIDDEN, FN_UNO_HIDDEN, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_STYLE_INTEROP_GRAB_BAG, FN_UNO_STYLE_INTEROP_GRAB_BAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_PARA_INTEROP_GRAB_BAG, RES_PARATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, + +#define COMMON_ACCESSIBILITY_TEXT_ATTRIBUTE \ + { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, \ + { UNO_NAME_CHAR_BACKGROUND_COMPLEX_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<css::util::XComplexColor>::get(), PROPERTY_NONE, MID_BACKGROUND_COMPLEX_COLOR },\ + { UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, \ + { UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, \ + { UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE }, \ + { UNO_NAME_CHAR_COMPLEX_COLOR, RES_CHRATR_COLOR, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_COMPLEX_COLOR }, \ + { UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA }, \ + { UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, \ + { UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_EMPHASIS}, \ + { UNO_NAME_CHAR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_ESC }, \ + { UNO_NAME_CHAR_FONT_NAME, RES_CHRATR_FONT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, MID_FONT_FAMILY_NAME }, \ + { UNO_NAME_CHAR_HEIGHT, RES_CHRATR_FONTSIZE , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_FONTHEIGHT|CONVERT_TWIPS}, \ + { UNO_NAME_CHAR_POSTURE, RES_CHRATR_POSTURE , cppu::UnoType<css::awt::FontSlant>::get(), PropertyAttribute::MAYBEVOID, MID_POSTURE}, \ + { UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, \ + { UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT}, \ + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COLOR}, \ + { UNO_NAME_CHAR_UNDERLINE_COLOR, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COLOR}, \ + { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR}, \ + { UNO_NAME_CHAR_WEIGHT, RES_CHRATR_WEIGHT , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT}, \ + { UNO_NAME_NUMBERING_LEVEL, RES_PARATR_LIST_LEVEL,cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_NUMBERING, RES_PARATR_LIST_ISCOUNTED, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_TL_STYLE}, \ + { UNO_NAME_NUMBERING_RULES, RES_PARATR_NUMRULE,cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ + { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST}, \ + { UNO_NAME_PARA_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_LO_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_INDENT|CONVERT_TWIPS}, \ + { UNO_NAME_PARA_LEFT_MARGIN, RES_MARGIN_TEXTLEFT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TXT_LMARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_PARA_LINE_SPACING, RES_PARATR_LINESPACING, cppu::UnoType<css::style::LineSpacing>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ + { UNO_NAME_PARA_RIGHT_MARGIN, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_R_MARGIN|CONVERT_TWIPS}, \ + { UNO_NAME_TABSTOPS, RES_PARATR_TABSTOP, cppu::UnoType< cppu::UnoSequenceType<css::style::TabStop> >::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ + +#define FILL_PROPERTIES_SW_BMP \ + { UNO_NAME_FILLBMP_LOGICAL_SIZE, XATTR_FILLBMP_SIZELOG, cppu::UnoType<bool>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_OFFSET_X, XATTR_FILLBMP_TILEOFFSETX, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_OFFSET_Y, XATTR_FILLBMP_TILEOFFSETY, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_POSITION_OFFSET_X, XATTR_FILLBMP_POSOFFSETX, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_POSITION_OFFSET_Y, XATTR_FILLBMP_POSOFFSETY, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_RECTANGLE_POINT, XATTR_FILLBMP_POS, cppu::UnoType<css::drawing::RectanglePoint>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_SIZE_X, XATTR_FILLBMP_SIZEX, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM}, \ + { UNO_NAME_FILLBMP_SIZE_Y, XATTR_FILLBMP_SIZEY, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM}, \ + { UNO_NAME_FILLBMP_STRETCH, XATTR_FILLBMP_STRETCH, cppu::UnoType<bool>::get(), 0, 0}, \ + { UNO_NAME_FILLBMP_TILE, XATTR_FILLBMP_TILE, cppu::UnoType<bool>::get(), 0, 0},\ + { UNO_NAME_FILLBMP_MODE, OWN_ATTR_FILLBMP_MODE, cppu::UnoType<drawing::BitmapMode>::get(), 0, 0}, \ + +#define FILL_PROPERTIES_SW_DEFAULTS \ + { UNO_NAME_FILLCOLOR, XATTR_FILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + +#define FILL_PROPERTIES_SW \ + FILL_PROPERTIES_SW_BMP \ + FILL_PROPERTIES_SW_DEFAULTS \ + { UNO_NAME_FILLBACKGROUND, XATTR_FILLBACKGROUND, cppu::UnoType<bool>::get(), 0, 0}, \ + { UNO_NAME_FILLBITMAP, XATTR_FILLBITMAP, cppu::UnoType<css::awt::XBitmap>::get(), 0, MID_BITMAP}, \ + { UNO_NAME_FILLBITMAPURL, XATTR_FILLBITMAP, cppu::UnoType<OUString>::get(), 0, MID_BITMAP }, \ + { UNO_NAME_FILLBITMAPNAME, XATTR_FILLBITMAP, cppu::UnoType<OUString>::get(), 0, MID_NAME }, \ + { UNO_NAME_FILLGRADIENTSTEPCOUNT, XATTR_GRADIENTSTEPCOUNT, cppu::UnoType<sal_Int16>::get(), 0, 0}, \ + { UNO_NAME_FILLGRADIENT, XATTR_FILLGRADIENT, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, \ + { UNO_NAME_FILLGRADIENTNAME, XATTR_FILLGRADIENT, cppu::UnoType<OUString>::get(), 0, MID_NAME }, \ + { UNO_NAME_FILLHATCH, XATTR_FILLHATCH, cppu::UnoType<css::drawing::Hatch>::get(), 0, MID_FILLHATCH}, \ + { UNO_NAME_FILLHATCHNAME, XATTR_FILLHATCH, cppu::UnoType<OUString>::get(), 0, MID_NAME }, \ + { UNO_NAME_FILLSTYLE, XATTR_FILLSTYLE, cppu::UnoType<css::drawing::FillStyle>::get(), 0, 0}, \ + { UNO_NAME_FILL_TRANSPARENCE, XATTR_FILLTRANSPARENCE, cppu::UnoType<sal_Int16>::get(), 0, 0}, \ + { UNO_NAME_FILLTRANSPARENCEGRADIENT, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<css::awt::Gradient>::get(), 0, MID_FILLGRADIENT}, \ + { UNO_NAME_FILLTRANSPARENCEGRADIENTNAME, XATTR_FILLFLOATTRANSPARENCE, cppu::UnoType<OUString>::get(), 0, MID_NAME }, \ + { UNO_NAME_FILLCOLOR_2, XATTR_SECONDARYFILLCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0}, \ + { UNO_NAME_FILL_COMPLEX_COLOR, XATTR_FILLCOLOR, cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_COMPLEX_COLOR}, \ + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx new file mode 100644 index 0000000000..b2f83fee30 --- /dev/null +++ b/sw/source/core/unocore/unoobj.cxx @@ -0,0 +1,3123 @@ +/* -*- 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 <com/sun/star/table/TableSortField.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svl/itemprop.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <osl/endian.h> +#include <unotools/collatorwrapper.hxx> + +#include <autostyle_helper.hxx> +#include <swtypes.hxx> +#include <hintids.hxx> +#include <cmdid.h> +#include <unomid.h> +#include <hints.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <istyleaccess.hxx> +#include <ndtxt.hxx> +#include <unocrsr.hxx> +#include <unocrsrhelper.hxx> +#include <unoport.hxx> +#include <swundo.hxx> +#include <rootfrm.hxx> +#include <paratr.hxx> +#include <pam.hxx> +#include <shellio.hxx> +#include <unotbl.hxx> +#include <fmtruby.hxx> +#include <docsh.hxx> +#include <docstyle.hxx> +#include <fmtpdsc.hxx> +#include <pagedesc.hxx> +#include <edimp.hxx> +#include <fchrfmt.hxx> +#include <fmtautofmt.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unometa.hxx> +#include <unocontentcontrol.hxx> +#include <unotext.hxx> +#include <com/sun/star/text/TextMarkupType.hpp> +#include <utility> +#include <vcl/svapp.hxx> +#include <unotools/syslocale.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <SwStyleNameMapper.hxx> +#include <sortopt.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <memory> +#include <unoparaframeenum.hxx> +#include <unoparagraph.hxx> +#include <iodetect.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/profilezone.hxx> +#include <comphelper/flagguard.hxx> +#include <swmodule.hxx> + +using namespace ::com::sun::star; + +// Helper classes +SwUnoInternalPaM::SwUnoInternalPaM(SwDoc& rDoc) : + SwPaM(rDoc.GetNodes()) +{ +} + +SwUnoInternalPaM::~SwUnoInternalPaM() +{ + while( GetNext() != this) + { + // coverity[deref_arg] - the delete moves a new entry into GetNext() + delete GetNext(); + } +} + +SwUnoInternalPaM& SwUnoInternalPaM::operator=(const SwPaM& rPaM) +{ + const SwPaM* pTmp = &rPaM; + *GetPoint() = *rPaM.GetPoint(); + if(rPaM.HasMark()) + { + SetMark(); + *GetMark() = *rPaM.GetMark(); + } + else + DeleteMark(); + while(&rPaM != (pTmp = pTmp->GetNext())) + { + if(pTmp->HasMark()) + new SwPaM(*pTmp->GetMark(), *pTmp->GetPoint(), this); + else + new SwPaM(*pTmp->GetPoint(), this); + } + return *this; +} + +void SwUnoCursorHelper::SelectPam(SwPaM & rPam, const bool bExpand) +{ + if (bExpand) + { + if (!rPam.HasMark()) + { + rPam.SetMark(); + } + } + else if (rPam.HasMark()) + { + rPam.DeleteMark(); + } +} + +void SwUnoCursorHelper::GetTextFromPam(SwPaM & rPam, OUString & rBuffer, + SwRootFrame const*const pLayout) +{ + if (!rPam.HasMark()) + { + return; + } + SvMemoryStream aStream; +#ifdef OSL_BIGENDIAN + aStream.SetEndian( SvStreamEndian::BIG ); +#else + aStream.SetEndian( SvStreamEndian::LITTLE ); +#endif + WriterRef xWrt; + // TODO/MBA: looks like a BaseURL doesn't make sense here + SwReaderWriter::GetWriter( FILTER_TEXT_DLG, OUString(), xWrt ); + if( !xWrt.is() ) + return; + + SwWriter aWriter( aStream, rPam ); + xWrt->m_bASCII_NoLastLineEnd = true; + xWrt->m_bExportParagraphNumbering = false; + SwAsciiOptions aOpt = xWrt->GetAsciiOptions(); + aOpt.SetCharSet( RTL_TEXTENCODING_UNICODE ); + xWrt->SetAsciiOptions( aOpt ); + xWrt->m_bUCS2_WithStartChar = false; + // #i68522# + const bool bOldShowProgress = xWrt->m_bShowProgress; + xWrt->m_bShowProgress = false; + xWrt->m_bHideDeleteRedlines = pLayout && pLayout->IsHideRedlines(); + // tdf#155951 SwWriter::Write calls EndAllAction, and that + // called SelectShell(), triggering selection change event, which + // resulted infinite recursion, if selectionChanged() calls + // XTextRange::getString() e.g. on the selected range. + ::comphelper::FlagRestorationGuard g(g_bNoInterrupt, true); + + if( ! aWriter.Write( xWrt ).IsError() ) + { + const sal_uInt64 lUniLen = aStream.GetSize()/sizeof( sal_Unicode ); + if (lUniLen < o3tl::make_unsigned(SAL_MAX_INT32-1)) + { + aStream.WriteUInt16( '\0' ); + + aStream.Seek( 0 ); + aStream.ResetError(); + + rtl_uString *pStr = rtl_uString_alloc(lUniLen); + aStream.ReadBytes(pStr->buffer, lUniLen * sizeof(sal_Unicode)); + rBuffer = OUString(pStr, SAL_NO_ACQUIRE); + } + } + xWrt->m_bShowProgress = bOldShowProgress; + +} + +/// @throws lang::IllegalArgumentException +/// @throws uno::RuntimeException +static void +lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet) +{ + SwDocShell *const pDocSh = rDoc.GetDocShell(); + if(!pDocSh) + return; + + OUString uStyle; + if (!(rValue >>= uStyle)) + { + throw lang::IllegalArgumentException(); + } + OUString sStyle; + SwStyleNameMapper::FillUIName(uStyle, sStyle, + SwGetPoolIdFromName::ChrFmt); + SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>( + pDocSh->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char)); + if (!pStyle) + { + throw lang::IllegalArgumentException(); + } + const SwFormatCharFormat aFormat(pStyle->GetCharFormat()); + rSet.Put(aFormat); +}; + +/// @throws lang::IllegalArgumentException +static void +lcl_setAutoStyle(IStyleAccess & rStyleAccess, const uno::Any & rValue, + SfxItemSet & rSet, const bool bPara) +{ + OUString uStyle; + if (!(rValue >>= uStyle)) + { + throw lang::IllegalArgumentException(); + } + std::shared_ptr<SfxItemSet> pStyle = bPara ? + rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_PARA ): + rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_CHAR ); + if(!pStyle) + { + throw lang::IllegalArgumentException(); + } + + SwFormatAutoFormat aFormat( bPara + ? sal::static_int_cast< sal_uInt16 >(RES_AUTO_STYLE) + : sal::static_int_cast< sal_uInt16 >(RES_TXTATR_AUTOFMT) ); + aFormat.SetStyleHandle( pStyle ); + rSet.Put(aFormat); +}; + +void +SwUnoCursorHelper::SetTextFormatColl(const uno::Any & rAny, SwPaM & rPaM) +{ + SwDoc& rDoc = rPaM.GetDoc(); + SwDocShell *const pDocSh = rDoc.GetDocShell(); + if(!pDocSh) + return; + OUString uStyle; + rAny >>= uStyle; + OUString sStyle; + SwStyleNameMapper::FillUIName(uStyle, sStyle, + SwGetPoolIdFromName::TxtColl ); + SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>( + pDocSh->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Para)); + if (!pStyle) + { + throw lang::IllegalArgumentException(); + } + + SwTextFormatColl *const pLocal = pStyle->GetCollection(); + UnoActionContext aAction(&rDoc); + rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + SwPaM *pTmpCursor = &rPaM; + do { + rDoc.SetTextFormatColl(*pTmpCursor, pLocal); + pTmpCursor = pTmpCursor->GetNext(); + } while ( pTmpCursor != &rPaM ); + rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); +} + +bool +SwUnoCursorHelper::SetPageDesc( + const uno::Any& rValue, SwDoc & rDoc, SfxItemSet & rSet) +{ + OUString uDescName; + if (!(rValue >>= uDescName)) + { + return false; + } + std::unique_ptr<SwFormatPageDesc> pNewDesc; + if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet( RES_PAGEDESC )) + { + pNewDesc.reset(new SwFormatPageDesc(*pItem)); + } + if (!pNewDesc) + { + pNewDesc.reset(new SwFormatPageDesc()); + } + OUString sDescName; + SwStyleNameMapper::FillUIName(uDescName, sDescName, + SwGetPoolIdFromName::PageDesc); + if (!pNewDesc->GetPageDesc() || + (pNewDesc->GetPageDesc()->GetName() != sDescName)) + { + bool bPut = false; + if (!sDescName.isEmpty()) + { + SwPageDesc *const pPageDesc = SwPageDesc::GetByName(rDoc, sDescName); + if (!pPageDesc) + { + throw lang::IllegalArgumentException(); + } + pNewDesc->RegisterToPageDesc(*pPageDesc); + bPut = true; + } + if(!bPut) + { + rSet.ClearItem(RES_BREAK); + rSet.Put(SwFormatPageDesc()); + } + else + { + rSet.Put(std::move(pNewDesc)); + } + } + return true; +} + +static void +lcl_SetNodeNumStart(SwPaM & rCursor, uno::Any const& rValue) +{ + sal_Int16 nTmp = 1; + rValue >>= nTmp; + sal_uInt16 nStt = (nTmp < 0 ? USHRT_MAX : o3tl::narrowing<sal_uInt16>(nTmp)); + SwDoc& rDoc = rCursor.GetDoc(); + UnoActionContext aAction(&rDoc); + + if( rCursor.GetNext() != &rCursor ) // MultiSelection? + { + rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + SwPamRanges aRangeArr( rCursor ); + SwPaM aPam( *rCursor.GetPoint() ); + for( size_t n = 0; n < aRangeArr.Count(); ++n ) + { + rDoc.SetNumRuleStart(*aRangeArr.SetPam( n, aPam ).GetPoint()); + rDoc.SetNodeNumStart(*aRangeArr.SetPam( n, aPam ).GetPoint(), + nStt ); + } + rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } + else + { + rDoc.SetNumRuleStart( *rCursor.GetPoint()); + rDoc.SetNodeNumStart( *rCursor.GetPoint(), nStt ); + } +} + +static bool +lcl_setCharFormatSequence(SwPaM & rPam, uno::Any const& rValue) +{ + uno::Sequence<OUString> aCharStyles; + if (!(rValue >>= aCharStyles)) + { + return false; + } + + for (sal_Int32 nStyle = 0; nStyle < aCharStyles.getLength(); nStyle++) + { + uno::Any aStyle; + rPam.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr); + aStyle <<= aCharStyles.getConstArray()[nStyle]; + // create a local set and apply each format directly + SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> aSet(rPam.GetDoc().GetAttrPool()); + lcl_setCharStyle(rPam.GetDoc(), aStyle, aSet); + // the first style should replace the current attributes, + // all other have to be added + SwUnoCursorHelper::SetCursorAttr(rPam, aSet, nStyle + ? SetAttrMode::DONTREPLACE + : SetAttrMode::DEFAULT); + rPam.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START, nullptr); + } + return true; +} + +static void +lcl_setDropcapCharStyle(SwPaM const & rPam, SfxItemSet & rItemSet, + uno::Any const& rValue) +{ + OUString uStyle; + if (!(rValue >>= uStyle)) + { + throw lang::IllegalArgumentException(); + } + OUString sStyle; + SwStyleNameMapper::FillUIName(uStyle, sStyle, + SwGetPoolIdFromName::ChrFmt); + SwDoc& rDoc = rPam.GetDoc(); + //default character style must not be set as default format + SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>( + rDoc.GetDocShell() + ->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char)); + if (!pStyle || pStyle->GetCharFormat() == rDoc.GetDfltCharFormat()) + { + throw lang::IllegalArgumentException(); + } + std::unique_ptr<SwFormatDrop> pDrop; + if (const SwFormatDrop* pItem = rItemSet.GetItemIfSet(RES_PARATR_DROP)) + { + pDrop.reset(new SwFormatDrop(*pItem)); + } + if (!pDrop) + { + pDrop.reset(new SwFormatDrop); + } + const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*pStyle)); + pDrop->SetCharFormat(xStyle->GetCharFormat()); + rItemSet.Put(std::move(pDrop)); +} + +static void +lcl_setRubyCharstyle(SfxItemSet & rItemSet, uno::Any const& rValue) +{ + OUString sTmp; + if (!(rValue >>= sTmp)) + { + throw lang::IllegalArgumentException(); + } + + std::unique_ptr<SwFormatRuby> pRuby; + if (const SwFormatRuby* pItem = rItemSet.GetItemIfSet(RES_TXTATR_CJK_RUBY)) + { + pRuby.reset(new SwFormatRuby(*pItem)); + } + if (!pRuby) + { + pRuby.reset(new SwFormatRuby(OUString())); + } + OUString sStyle; + SwStyleNameMapper::FillUIName(sTmp, sStyle, + SwGetPoolIdFromName::ChrFmt); + pRuby->SetCharFormatName(sStyle); + pRuby->SetCharFormatId(0); + if (!sStyle.isEmpty()) + { + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( + sStyle, SwGetPoolIdFromName::ChrFmt); + pRuby->SetCharFormatId(nId); + } + rItemSet.Put(std::move(pRuby)); +} + +bool +SwUnoCursorHelper::SetCursorPropertyValue( + SfxItemPropertyMapEntry const& rEntry, const uno::Any& rValue, + SwPaM & rPam, SfxItemSet & rItemSet) +{ + if (!(rEntry.nFlags & beans::PropertyAttribute::MAYBEVOID) && + (rValue.getValueType() == cppu::UnoType<void>::get())) + { + return false; + } + bool bRet = true; + switch (rEntry.nWID) + { + case RES_TXTATR_CHARFMT: + lcl_setCharStyle(rPam.GetDoc(), rValue, rItemSet); + break; + case RES_TXTATR_AUTOFMT: + lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(), + rValue, rItemSet, false); + break; + case FN_UNO_CHARFMT_SEQUENCE: + lcl_setCharFormatSequence(rPam, rValue); + break; + case FN_UNO_PARA_STYLE : + SwUnoCursorHelper::SetTextFormatColl(rValue, rPam); + break; + case RES_AUTO_STYLE: + lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(), + rValue, rItemSet, true); + break; + case FN_UNO_PAGE_STYLE: + //FIXME nothing here? + break; + case FN_UNO_NUM_START_VALUE: + lcl_SetNodeNumStart( rPam, rValue ); + break; + case FN_UNO_NUM_LEVEL: + // #i91601# + case FN_UNO_LIST_ID: + case FN_UNO_IS_NUMBER: + case FN_UNO_PARA_NUM_AUTO_FORMAT: + { + // multi selection is not considered + SwTextNode *const pTextNd = rPam.GetPointNode().GetTextNode(); + if (!pTextNd) + { + throw lang::IllegalArgumentException(); + } + if (FN_UNO_NUM_LEVEL == rEntry.nWID) + { + sal_Int16 nLevel = 0; + if (rValue >>= nLevel) + { + if (nLevel < 0 || MAXLEVEL <= nLevel) + { + throw lang::IllegalArgumentException( + "invalid NumberingLevel", nullptr, 0); + } + pTextNd->SetAttrListLevel(nLevel); + } + } + // #i91601# + else if (FN_UNO_LIST_ID == rEntry.nWID) + { + OUString sListId; + if (rValue >>= sListId) + { + pTextNd->SetListId( sListId ); + } + } + else if (FN_UNO_IS_NUMBER == rEntry.nWID) + { + bool bIsNumber(false); + if ((rValue >>= bIsNumber) && !bIsNumber) + { + pTextNd->SetCountedInList( false ); + } + } + else if (FN_UNO_PARA_NUM_AUTO_FORMAT == rEntry.nWID) + { + std::shared_ptr<SfxItemSet> pAutoStyle; + if (uno::Sequence<beans::NamedValue> props; rValue >>= props) + { + // TODO create own map for this, it contains UNO_NAME_DISPLAY_NAME? or make property readable so ODF export can map it to a automatic style? + SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + SfxItemSetFixed + <RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1> + items( rPam.GetDoc().GetAttrPool() ); + + for (beans::NamedValue const & prop : std::as_const(props)) + { + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName(prop.Name); + if (!pEntry) + { + if (prop.Name == "CharStyleName") + { + lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); + continue; + } + throw beans::UnknownPropertyException( + "Unknown property: " + prop.Name); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException( + "Property is read-only: " + prop.Name); + } + rPropSet.setPropertyValue(*pEntry, prop.Value, items); + } + + IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); + // Add it to the autostyle pool, needed by the ODT export. + pAutoStyle = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR); + } + else if (OUString styleName; rValue >>= styleName) + { + IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); + pAutoStyle = rStyleAccess.getByName(styleName, IStyleAccess::AUTO_STYLE_CHAR); + } + if (pAutoStyle) + { + SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT); + // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add() + item.SetStyleHandle(pAutoStyle); + pTextNd->SetAttr(item); + } + } + //PROPERTY_MAYBEVOID! + } + break; + case FN_NUMBER_NEWSTART: + { + bool bVal = false; + if (!(rValue >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + rPam.GetDoc().SetNumRuleStart(*rPam.GetPoint(), bVal); + } + break; + case FN_UNO_NUM_RULES: + SwUnoCursorHelper::setNumberingProperty(rValue, rPam); + break; + case RES_PARATR_DROP: + { + if (MID_DROPCAP_CHAR_STYLE_NAME == rEntry.nMemberId) + { + lcl_setDropcapCharStyle(rPam, rItemSet, rValue); + } + else + { + bRet = false; + } + } + break; + case RES_TXTATR_CJK_RUBY: + { + if (MID_RUBY_CHARSTYLE == rEntry.nMemberId) + { + lcl_setRubyCharstyle(rItemSet, rValue); + } + else + { + bRet = false; + } + } + break; + case RES_PAGEDESC: + { + if (MID_PAGEDESC_PAGEDESCNAME == rEntry.nMemberId) + { + SwUnoCursorHelper::SetPageDesc( + rValue, rPam.GetDoc(), rItemSet); + } + else + { + bRet = false; + } + } + break; + default: + bRet = false; + } + return bRet; +} + +SwFormatColl * +SwUnoCursorHelper::GetCurTextFormatColl(SwPaM & rPaM, const bool bConditional) +{ + static const sal_uLong nMaxLookup = 1000; + SwFormatColl *pFormat = nullptr; + bool bError = false; + SwPaM *pTmpCursor = &rPaM; + do + { + const SwNodeOffset nSttNd = pTmpCursor->Start()->GetNodeIndex(); + const SwNodeOffset nEndNd = pTmpCursor->End()->GetNodeIndex(); + + if( nEndNd - nSttNd >= SwNodeOffset(nMaxLookup) ) + { + pFormat = nullptr; + break; + } + + const SwNodes& rNds = rPaM.GetDoc().GetNodes(); + for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n ) + { + SwTextNode const*const pNd = rNds[ n ]->GetTextNode(); + if( pNd ) + { + SwFormatColl *const pNdFormat = bConditional + ? pNd->GetFormatColl() : &pNd->GetAnyFormatColl(); + if( !pFormat ) + { + pFormat = pNdFormat; + } + else if( pFormat != pNdFormat ) + { + bError = true; + break; + } + } + } + + pTmpCursor = pTmpCursor->GetNext(); + } while ( pTmpCursor != &rPaM ); + return bError ? nullptr : pFormat; +} + +SwUnoCursor& SwXTextCursor::GetCursor() + { return *m_pUnoCursor; } + +SwPaM const* SwXTextCursor::GetPaM() const + { return m_pUnoCursor.get(); } + +SwPaM* SwXTextCursor::GetPaM() + { return m_pUnoCursor.get(); } + +SwDoc const* SwXTextCursor::GetDoc() const + { return m_pUnoCursor ? &m_pUnoCursor->GetDoc() : nullptr; } + +SwDoc* SwXTextCursor::GetDoc() + { return m_pUnoCursor ? &m_pUnoCursor->GetDoc() : nullptr; } + +SwXTextCursor::SwXTextCursor( + SwDoc & rDoc, + uno::Reference< text::XText > xParent, + const CursorType eType, + const SwPosition& rPos, + SwPosition const*const pMark) + : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR)) + , m_eType(eType) + , m_xParentText(std::move(xParent)) + , m_pUnoCursor(rDoc.CreateUnoCursor(rPos)) +{ + if (pMark) + { + m_pUnoCursor->SetMark(); + *m_pUnoCursor->GetMark() = *pMark; + } +} + +SwXTextCursor::SwXTextCursor(uno::Reference< text::XText > xParent, + SwPaM const& rSourceCursor, const CursorType eType) + : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR)) + , m_eType(eType) + , m_xParentText(std::move(xParent)) + , m_pUnoCursor(rSourceCursor.GetDoc().CreateUnoCursor(*rSourceCursor.GetPoint())) +{ + if (rSourceCursor.HasMark()) + { + m_pUnoCursor->SetMark(); + *m_pUnoCursor->GetMark() = *rSourceCursor.GetMark(); + } +} + +SwXTextCursor::~SwXTextCursor() +{ + SolarMutexGuard g; // #i105557#: call dtor with locked solar mutex + m_pUnoCursor.reset(nullptr); // need to delete this with SolarMutex held +} + +void SwXTextCursor::DeleteAndInsert(std::u16string_view aText, + ::sw::DeleteAndInsertMode const eMode) +{ + auto pUnoCursor = static_cast<SwCursor*>(m_pUnoCursor.get()); + if (!pUnoCursor) + return; + + // Start/EndAction + SwDoc& rDoc = pUnoCursor->GetDoc(); + UnoActionContext aAction(&rDoc); + const sal_Int32 nTextLen = aText.size(); + rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + auto pCurrent = pUnoCursor; + do + { + if (pCurrent->HasMark()) + { + rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent, + // is it "delete" or "replace"? + (nTextLen != 0 || eMode & ::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default); + } + if(nTextLen) + { + const bool bSuccess( + SwUnoCursorHelper::DocInsertStringSplitCR( + rDoc, *pCurrent, aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints))); + OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." ); + + SwUnoCursorHelper::SelectPam(*pUnoCursor, true); + pCurrent->Left(aText.size()); + } + pCurrent = pCurrent->GetNext(); + } while (pCurrent != pUnoCursor); + rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); +} + +namespace { + +enum ForceIntoMetaMode { META_CHECK_BOTH, META_INIT_START, META_INIT_END }; + +enum ForceIntoContentControlMode +{ + CONTENT_CONTROL_CHECK_BOTH, + CONTENT_CONTROL_INIT_START, + CONTENT_CONTROL_INIT_END +}; +} + +static bool +lcl_ForceIntoMeta(SwPaM & rCursor, + uno::Reference<text::XText> const & xParentText, + const enum ForceIntoMetaMode eMode) +{ + bool bRet( true ); // means not forced in META_CHECK_BOTH + SwXMeta const * const pXMeta( dynamic_cast<SwXMeta*>(xParentText.get()) ); + OSL_ENSURE(pXMeta, "no parent?"); + if (!pXMeta) + throw uno::RuntimeException(); + SwTextNode * pTextNode; + sal_Int32 nStart; + sal_Int32 nEnd; + const bool bSuccess( pXMeta->SetContentRange(pTextNode, nStart, nEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + throw uno::RuntimeException(); + // force the cursor back into the meta if it has moved outside + SwPosition start(*pTextNode, nStart); + SwPosition end(*pTextNode, nEnd); + switch (eMode) + { + case META_INIT_START: + *rCursor.GetPoint() = start; + break; + case META_INIT_END: + *rCursor.GetPoint() = end; + break; + case META_CHECK_BOTH: + if (*rCursor.Start() < start) + { + *rCursor.Start() = start; + bRet = false; + } + if (*rCursor.End() > end) + { + *rCursor.End() = end; + bRet = false; + } + break; + } + return bRet; +} + +namespace +{ +bool lcl_ForceIntoContentControl(SwPaM& rCursor, const uno::Reference<text::XText>& xParentText, + ForceIntoContentControlMode eMode) +{ + bool bRet = true; // means not forced in CONTENT_CONTROL_CHECK_BOTH + auto pXContentControl = dynamic_cast<SwXContentControl*>(xParentText.get()); + if (!pXContentControl) + { + SAL_WARN("sw.core", "lcl_ForceIntoContentControl: no parent text"); + throw uno::RuntimeException(); + } + + SwTextNode* pTextNode; + sal_Int32 nStart; + sal_Int32 nEnd; + bool bSuccess = pXContentControl->SetContentRange(pTextNode, nStart, nEnd); + if (!bSuccess) + { + SAL_WARN("sw.core", "lcl_ForceIntoContentControl: SetContentRange() failed"); + throw uno::RuntimeException(); + } + + // Force the cursor back into the content control if it has moved outside. + SwPosition aStart(*pTextNode, nStart); + SwPosition aEnd(*pTextNode, nEnd); + switch (eMode) + { + case CONTENT_CONTROL_INIT_START: + *rCursor.GetPoint() = aStart; + break; + + case CONTENT_CONTROL_INIT_END: + *rCursor.GetPoint() = aEnd; + break; + + case CONTENT_CONTROL_CHECK_BOTH: + if (*rCursor.Start() < aStart) + { + *rCursor.Start() = aStart; + bRet = false; + } + + if (*rCursor.End() > aEnd) + { + *rCursor.End() = aEnd; + bRet = false; + } + break; + } + + return bRet; +} +} + +bool SwXTextCursor::IsAtEndOfMeta() const +{ + if (CursorType::Meta == m_eType) + { + auto pCursor( m_pUnoCursor ); + SwXMeta const*const pXMeta( + dynamic_cast<SwXMeta*>(m_xParentText.get()) ); + OSL_ENSURE(pXMeta, "no meta?"); + if (pCursor && pXMeta) + { + SwTextNode * pTextNode; + sal_Int32 nStart; + sal_Int32 nEnd; + const bool bSuccess( + pXMeta->SetContentRange(pTextNode, nStart, nEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (bSuccess) + { + const SwPosition end(*pTextNode, nEnd); + if ( (*pCursor->GetPoint() == end) + || (*pCursor->GetMark() == end)) + { + return true; + } + } + } + } + return false; +} + +bool SwXTextCursor::IsAtEndOfContentControl() const +{ + if (CursorType::ContentControl == m_eType) + { + auto pCursor( m_pUnoCursor ); + auto pXContentControl( + dynamic_cast<SwXContentControl*>(m_xParentText.get()) ); + if (!pXContentControl) + { + SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no content control"); + } + if (pCursor && pXContentControl) + { + SwTextNode * pTextNode; + sal_Int32 nStart; + sal_Int32 nEnd; + const bool bSuccess( + pXContentControl->SetContentRange(pTextNode, nStart, nEnd) ); + if (!bSuccess) + { + SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no pam"); + } + else + { + const SwPosition end(*pTextNode, nEnd); + if ( (*pCursor->GetPoint() == end) + || (*pCursor->GetMark() == end)) + { + return true; + } + } + } + } + return false; +} + +OUString SwXTextCursor::getImplementationName() +{ + return "SwXTextCursor"; +} + +sal_Bool SAL_CALL SwXTextCursor::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXTextCursor::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextCursor", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex", + "com.sun.star.text.TextSortable" + }; +} + +void SAL_CALL SwXTextCursor::collapseToStart() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (rUnoCursor.HasMark()) + { + if (*rUnoCursor.GetPoint() > *rUnoCursor.GetMark()) + { + rUnoCursor.Exchange(); + } + rUnoCursor.DeleteMark(); + } +} + +void SAL_CALL SwXTextCursor::collapseToEnd() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (rUnoCursor.HasMark()) + { + if (*rUnoCursor.GetPoint() < *rUnoCursor.GetMark()) + { + rUnoCursor.Exchange(); + } + rUnoCursor.DeleteMark(); + } +} + +sal_Bool SAL_CALL SwXTextCursor::isCollapsed() +{ + SolarMutexGuard aGuard; + + bool bRet = true; + auto pUnoCursor(m_pUnoCursor); + if(pUnoCursor && pUnoCursor->GetMark()) + { + bRet = (*pUnoCursor->GetPoint() == *pUnoCursor->GetMark()); + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::goLeft(sal_Int16 nCount, sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = rUnoCursor.Left( nCount); + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::goRight(sal_Int16 nCount, sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = rUnoCursor.Right(nCount); + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +void SAL_CALL +SwXTextCursor::gotoStart(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + comphelper::ProfileZone aZone("gotoStart"); + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + if (CursorType::Body == m_eType) + { + rUnoCursor.Move( fnMoveBackward, GoInDoc ); + //check, that the cursor is not in a table + SwTableNode * pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + while (pTableNode) + { + rUnoCursor.GetPoint()->Assign( *pTableNode->EndOfSectionNode() ); + SwContentNode* pCNode = GetDoc()->GetNodes().GoNext(rUnoCursor.GetPoint()); + pTableNode = pCNode ? pCNode->FindTableNode() : nullptr; + } + SwStartNode const*const pTmp = + rUnoCursor.GetPointNode().StartOfSectionNode(); + if (pTmp->IsSectionNode()) + { + SwSectionNode const*const pSectionStartNode = + static_cast<SwSectionNode const*>(pTmp); + if (pSectionStartNode->GetSection().IsHiddenFlag()) + { + GetDoc()->GetNodes().GoNextSection( + rUnoCursor.GetPoint(), true, false); + } + } + } + else if ( (CursorType::Frame == m_eType) + || (CursorType::TableText == m_eType) + || (CursorType::Header == m_eType) + || (CursorType::Footer == m_eType) + || (CursorType::Footnote== m_eType) + || (CursorType::Redline == m_eType)) + { + rUnoCursor.MoveSection(GoCurrSection, fnSectionStart); + } + else if (CursorType::Meta == m_eType) + { + lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_START); + } + else if (m_eType == CursorType::ContentControl) + { + lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_START); + } +} + +void SAL_CALL +SwXTextCursor::gotoEnd(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + comphelper::ProfileZone aZone("gotoEnd"); + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + if (CursorType::Body == m_eType) + { + rUnoCursor.Move( fnMoveForward, GoInDoc ); + } + else if ( (CursorType::Frame == m_eType) + || (CursorType::TableText == m_eType) + || (CursorType::Header == m_eType) + || (CursorType::Footer == m_eType) + || (CursorType::Footnote== m_eType) + || (CursorType::Redline == m_eType)) + { + rUnoCursor.MoveSection( GoCurrSection, fnSectionEnd); + } + else if (CursorType::Meta == m_eType) + { + lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_END); + } + else if (m_eType == CursorType::ContentControl) + { + lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_END); + } +} + +void SAL_CALL +SwXTextCursor::gotoRange( + const uno::Reference< text::XTextRange > & xRange, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + + if (!xRange.is()) + { + throw uno::RuntimeException(); + } + + SwUnoCursor & rOwnCursor( GetCursorOrThrow() ); + + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xRange.get()); + + if (!pRange && !pCursor) + { + throw uno::RuntimeException(); + } + + SwPaM aPam(GetDoc()->GetNodes()); + const SwPaM * pPam(nullptr); + if (pCursor) + { + pPam = pCursor->GetPaM(); + } + else if (pRange) + { + if (pRange->GetPositions(aPam)) + { + pPam = & aPam; + } + } + + if (!pPam) + { + throw uno::RuntimeException(); + } + + { + SwStartNodeType eSearchNodeType = SwNormalStartNode; + switch (m_eType) + { + case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break; + case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break; + case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break; + case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break; + case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break; + //case CURSOR_INVALID: + //case CursorType::Body: + default: + ; + } + + const SwStartNode* pOwnStartNode = rOwnCursor.GetPointNode().FindSttNodeByType(eSearchNodeType); + while ( pOwnStartNode != nullptr + && pOwnStartNode->IsSectionNode()) + { + pOwnStartNode = pOwnStartNode->StartOfSectionNode(); + } + + const SwStartNode* pTmp = + pPam->GetPointNode().FindSttNodeByType(eSearchNodeType); + while ( pTmp != nullptr + && pTmp->IsSectionNode() ) + { + pTmp = pTmp->StartOfSectionNode(); + } + + if ( eSearchNodeType == SwTableBoxStartNode ) + { + if (!pOwnStartNode || !pTmp) + { + throw uno::RuntimeException(); + } + + if ( pOwnStartNode->FindTableNode() != pTmp->FindTableNode() ) + { + throw uno::RuntimeException(); + } + } + else + { + if ( pOwnStartNode != pTmp ) + { + throw uno::RuntimeException(); + } + } + } + + if (CursorType::Meta == m_eType) + { + SwPaM CopyPam(*pPam->GetMark(), *pPam->GetPoint()); + const bool bNotForced( lcl_ForceIntoMeta( + CopyPam, m_xParentText, META_CHECK_BOTH) ); + if (!bNotForced) + { + throw uno::RuntimeException( + "gotoRange: parameter range not contained in nesting" + " text content for which this cursor was created", + static_cast<text::XWordCursor*>(this)); + } + } + else if (m_eType == CursorType::ContentControl) + { + SwPaM aPaM(*pPam->GetMark(), *pPam->GetPoint()); + if (!lcl_ForceIntoContentControl(aPaM, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)) + { + throw uno::RuntimeException("gotoRange: xRange is out of bounds of the content control", + static_cast<text::XWordCursor*>(this)); + } + } + + // selection has to be expanded here + if(bExpand) + { + // cursor should include its previous range plus the given range + const SwPosition aOwnLeft(*rOwnCursor.Start()); + const SwPosition aOwnRight(*rOwnCursor.End()); + SwPosition const& rParamLeft = *pPam->Start(); + SwPosition const& rParamRight = *pPam->End(); + + // now there are four SwPositions, + // two of them are going to be used, but which ones? + if (aOwnRight > rParamRight) + *rOwnCursor.GetPoint() = aOwnRight; + else + *rOwnCursor.GetPoint() = rParamRight; + rOwnCursor.SetMark(); + if (aOwnLeft < rParamLeft) + *rOwnCursor.GetMark() = aOwnLeft; + else + *rOwnCursor.GetMark() = rParamLeft; + } + else + { + // cursor should be the given range + *rOwnCursor.GetPoint() = *pPam->GetPoint(); + if (pPam->HasMark()) + { + rOwnCursor.SetMark(); + *rOwnCursor.GetMark() = *pPam->GetMark(); + } + else + { + rOwnCursor.DeleteMark(); + } + } +} + +sal_Bool SAL_CALL SwXTextCursor::isStartOfWord() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const bool bRet = + rUnoCursor.IsStartWordWT( i18n::WordType::DICTIONARY_WORD ); + return bRet; +} + +sal_Bool SAL_CALL SwXTextCursor::isEndOfWord() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const bool bRet = + rUnoCursor.IsEndWordWT( i18n::WordType::DICTIONARY_WORD ); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoNextWord(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + // problems arise when a paragraph starts with something other than a word + bool bRet = false; + // remember old position to check if cursor has moved + // since the called functions are sometimes a bit unreliable + // in specific cases... + SwPosition *const pPoint = rUnoCursor.GetPoint(); + SwNode *const pOldNode = &pPoint->GetNode(); + sal_Int32 const nOldIndex = pPoint->GetContentIndex(); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + // end of paragraph + if (rUnoCursor.GetPointContentNode() && + (pPoint->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len())) + { + rUnoCursor.Right(1); + } + else + { + const bool bTmp = + rUnoCursor.GoNextWordWT( i18n::WordType::DICTIONARY_WORD ); + // if there is no next word within the current paragraph + // try to go to the start of the next paragraph + if (!bTmp) + { + rUnoCursor.MovePara(GoNextPara, fnParaStart); + } + } + + // return true if cursor has moved + bRet = (&pPoint->GetNode() != pOldNode) || + (pPoint->GetContentIndex() != nOldIndex); + if (bRet && (CursorType::Meta == m_eType)) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH); + } + else if (bRet && m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH); + } + + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoPreviousWord(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + // white spaces create problems on the paragraph start + bool bRet = false; + SwPosition *const pPoint = rUnoCursor.GetPoint(); + SwNode *const pOldNode = &pPoint->GetNode(); + sal_Int32 const nOldIndex = pPoint->GetContentIndex(); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + // start of paragraph? + if (pPoint->GetContentIndex() == 0) + { + rUnoCursor.Left(1); + } + else + { + rUnoCursor.GoPrevWordWT( i18n::WordType::DICTIONARY_WORD ); + if (pPoint->GetContentIndex() == 0) + { + rUnoCursor.Left(1); + } + } + + // return true if cursor has moved + bRet = (&pPoint->GetNode() != pOldNode) || + (pPoint->GetContentIndex() != nOldIndex); + if (bRet && (CursorType::Meta == m_eType)) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH); + } + else if (bRet && m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH); + } + + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoEndOfWord(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + bool bRet = false; + SwPosition *const pPoint = rUnoCursor.GetPoint(); + SwNode & rOldNode = pPoint->GetNode(); + sal_Int32 const nOldIndex = pPoint->GetContentIndex(); + + const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD; + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + if (!rUnoCursor.IsEndWordWT( nWordType )) + { + rUnoCursor.GoEndWordWT( nWordType ); + } + + // restore old cursor if we are not at the end of a word by now + // otherwise use current one + bRet = rUnoCursor.IsEndWordWT( nWordType ); + if (!bRet) + { + pPoint->Assign(rOldNode, nOldIndex); + } + else if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH); + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH); + } + + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoStartOfWord(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + bool bRet = false; + SwPosition *const pPoint = rUnoCursor.GetPoint(); + SwNode & rOldNode = pPoint->GetNode(); + sal_Int32 const nOldIndex = pPoint->GetContentIndex(); + + const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD; + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + if (!rUnoCursor.IsStartWordWT( nWordType )) + { + rUnoCursor.GoStartWordWT( nWordType ); + } + + // restore old cursor if we are not at the start of a word by now + // otherwise use current one + bRet = rUnoCursor.IsStartWordWT( nWordType ); + if (!bRet) + { + pPoint->Assign(rOldNode, nOldIndex); + } + else if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH); + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH); + } + + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::isStartOfSentence() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + // start of paragraph? + bool bRet = rUnoCursor.GetPoint()->GetContentIndex() == 0; + // with mark ->no sentence start + // (check if cursor is no selection, i.e. it does not have + // a mark or else point and mark are identical) + if (!bRet && (!rUnoCursor.HasMark() || + *rUnoCursor.GetPoint() == *rUnoCursor.GetMark())) + { + SwCursor aCursor(*rUnoCursor.GetPoint(),nullptr); + SwPosition aOrigPos = *aCursor.GetPoint(); + aCursor.GoSentence(SwCursor::START_SENT ); + bRet = aOrigPos == *aCursor.GetPoint(); + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::isEndOfSentence() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + // end of paragraph? + bool bRet = rUnoCursor.GetPointContentNode() && + (rUnoCursor.GetPoint()->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len()); + // with mark->no sentence end + // (check if cursor is no selection, i.e. it does not have + // a mark or else point and mark are identical) + if (!bRet && (!rUnoCursor.HasMark() || + *rUnoCursor.GetPoint() == *rUnoCursor.GetMark())) + { + SwCursor aCursor(*rUnoCursor.GetPoint(), nullptr); + SwPosition aOrigPos = *aCursor.GetPoint(); + aCursor.GoSentence(SwCursor::END_SENT); + bRet = aOrigPos == *aCursor.GetPoint(); + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoNextSentence(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const bool bWasEOS = isEndOfSentence(); + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = rUnoCursor.GoSentence(SwCursor::NEXT_SENT); + if (!bRet) + { + bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart); + } + + // if at the end of the sentence (i.e. at the space after the '.') + // advance to next word in order for GoSentence to work properly + // next time and have isStartOfSentence return true after this call + if (!rUnoCursor.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES)) + { + const bool bNextWord = rUnoCursor.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES); + if (bWasEOS && !bNextWord) + { + bRet = false; + } + } + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoPreviousSentence(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = rUnoCursor.GoSentence(SwCursor::PREV_SENT); + if (!bRet) + { + bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart); + if (bRet) + { + rUnoCursor.MovePara(GoCurrPara, fnParaEnd); + // at the end of a paragraph move to the sentence end again + rUnoCursor.GoSentence(SwCursor::PREV_SENT); + } + } + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoStartOfSentence(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + // if we're at the para start then we won't move + // but bRet is also true if GoSentence failed but + // the start of the sentence is reached + bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor) + || rUnoCursor.GoSentence(SwCursor::START_SENT) + || SwUnoCursorHelper::IsStartOfPara(rUnoCursor); + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoEndOfSentence(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + // bRet is true if GoSentence() succeeded or if the + // MovePara() succeeded while the end of the para is + // not reached already + bool bAlreadyParaEnd = SwUnoCursorHelper::IsEndOfPara(rUnoCursor); + bool bRet = !bAlreadyParaEnd + && (rUnoCursor.GoSentence(SwCursor::END_SENT) + || rUnoCursor.MovePara(GoCurrPara, fnParaEnd)); + if (CursorType::Meta == m_eType) + { + bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText, + META_CHECK_BOTH) + && bRet; + } + else if (m_eType == CursorType::ContentControl) + { + bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH) + && bRet; + } + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::isStartOfParagraph() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::isEndOfParagraph() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoStartOfParagraph(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (CursorType::Meta == m_eType) + { + return false; + } + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor); + if (!bRet) + { + bRet = rUnoCursor.MovePara(GoCurrPara, fnParaStart); + } + + // since MovePara(GoCurrPara, fnParaStart) only returns false + // if we were already at the start of the paragraph this function + // should always complete successfully. + OSL_ENSURE( bRet, "gotoStartOfParagraph failed" ); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoEndOfParagraph(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (CursorType::Meta == m_eType) + { + return false; + } + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor); + if (!bRet) + { + bRet = rUnoCursor.MovePara(GoCurrPara, fnParaEnd); + } + + // since MovePara(GoCurrPara, fnParaEnd) only returns false + // if we were already at the end of the paragraph this function + // should always complete successfully. + OSL_ENSURE( bRet, "gotoEndOfParagraph failed" ); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoNextParagraph(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (CursorType::Meta == m_eType) + { + return false; + } + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + const bool bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart); + return bRet; +} + +sal_Bool SAL_CALL +SwXTextCursor::gotoPreviousParagraph(sal_Bool Expand) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (CursorType::Meta == m_eType) + { + return false; + } + SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); + const bool bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart); + return bRet; +} + +uno::Reference< text::XText > SAL_CALL +SwXTextCursor::getText() +{ + SolarMutexGuard g; + + return m_xParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextCursor::getStart() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + uno::Reference< text::XTextRange > xRet; + SwPaM aPam(*rUnoCursor.Start()); + const uno::Reference< text::XText > xParent = getText(); + if (CursorType::Meta == m_eType) + { + // return cursor to prevent modifying SwXTextRange for META + rtl::Reference<SwXTextCursor> pXCursor( + new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta, + *rUnoCursor.GetPoint()) ); + pXCursor->gotoStart(false); + xRet = static_cast<text::XWordCursor*>(pXCursor.get()); + } + else + { + xRet = new SwXTextRange(aPam, xParent); + } + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextCursor::getEnd() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + uno::Reference< text::XTextRange > xRet; + SwPaM aPam(*rUnoCursor.End()); + const uno::Reference< text::XText > xParent = getText(); + if (CursorType::Meta == m_eType) + { + // return cursor to prevent modifying SwXTextRange for META + rtl::Reference<SwXTextCursor> pXCursor( + new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta, + *rUnoCursor.GetPoint()) ); + pXCursor->gotoEnd(false); + xRet = static_cast<text::XWordCursor*>(pXCursor.get()); + } + else + { + xRet = new SwXTextRange(aPam, xParent); + } + return xRet; +} + +OUString SAL_CALL SwXTextCursor::getString() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + OUString aText; + SwUnoCursorHelper::GetTextFromPam(rUnoCursor, aText); + return aText; +} + +void SAL_CALL +SwXTextCursor::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + + GetCursorOrThrow(); // just to check if valid + + const bool bForceExpandHints( (CursorType::Meta == m_eType) + && dynamic_cast<SwXMeta&>(*m_xParentText) + .CheckForOwnMemberMeta(*GetPaM(), true) ); + DeleteAndInsert(aString, bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default); +} + +uno::Any SwUnoCursorHelper::GetPropertyValue( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + std::u16string_view rPropertyName) +{ + uno::Any aAny; + SfxItemPropertyMapEntry const*const pEntry = + rPropSet.getPropertyMap().getByName(rPropertyName); + + if (!pEntry) + { + throw beans::UnknownPropertyException( + OUString::Concat("Unknown property: ") + rPropertyName); + } + + beans::PropertyState eTemp; + const bool bDone = SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, rPaM, &aAny, eTemp ); + + if (!bDone) + { + SfxItemSetFixed< + RES_CHRATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER> + aSet(rPaM.GetDoc().GetAttrPool()); + + SwUnoCursorHelper::GetCursorAttr(rPaM, aSet); + + rPropSet.getPropertyValue(*pEntry, aSet, aAny); + } + + return aAny; +} + +void SwUnoCursorHelper::SetPropertyValue( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + const OUString& rPropertyName, + const uno::Any& rValue, + const SetAttrMode nAttrMode) +{ + beans::PropertyValue aVal { comphelper::makePropertyValue(rPropertyName, rValue) }; + SetPropertyValues(rPaM, rPropSet, std::span<beans::PropertyValue>(&aVal, 1), nAttrMode); +} + +// FN_UNO_PARA_STYLE is known to set attributes for nodes, inside +// SwUnoCursorHelper::SetTextFormatColl, instead of extending item set. +// We need to get them from nodes in next call to GetCursorAttr. +// The rest could cause similar problems in theory, so we just list them here. +static bool propertyCausesSideEffectsInNodes(sal_uInt16 nWID) +{ + return nWID == FN_UNO_PARA_STYLE || + nWID == FN_UNO_CHARFMT_SEQUENCE || + nWID == FN_UNO_NUM_START_VALUE || + nWID == FN_UNO_NUM_RULES; +} + +void SwUnoCursorHelper::SetPropertyValues( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + const uno::Sequence< beans::PropertyValue > &rPropertyValues, + const SetAttrMode nAttrMode) +{ + SetPropertyValues(rPaM, rPropSet, + std::span<const beans::PropertyValue>(rPropertyValues.getConstArray(), rPropertyValues.getLength()), + nAttrMode); +} + +void SwUnoCursorHelper::SetPropertyValues( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + std::span< const beans::PropertyValue > aPropertyValues, + const SetAttrMode nAttrMode) +{ + if (aPropertyValues.empty()) + return; + + SwDoc& rDoc = rPaM.GetDoc(); + OUString aUnknownExMsg, aPropertyVetoExMsg; + + // Build set of attributes we want to fetch + WhichRangesContainer aRanges; + std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> aSideEffectsEntries; + std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> aEntries; + aEntries.reserve(aPropertyValues.size()); + for (const auto& rPropVal : aPropertyValues) + { + const OUString &rPropertyName = rPropVal.Name; + + SfxItemPropertyMapEntry const* pEntry = + rPropSet.getPropertyMap().getByName(rPropertyName); + + // Queue up any exceptions until the end ... + if (!pEntry) + { + aUnknownExMsg += "Unknown property: '" + rPropertyName + "' "; + continue; + } + else if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + aPropertyVetoExMsg += "Property is read-only: '" + rPropertyName + "' "; + continue; + } + if (propertyCausesSideEffectsInNodes(pEntry->nWID)) + { + aSideEffectsEntries.emplace_back(pEntry, rPropVal.Value); + } + else + { + aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID); + aEntries.emplace_back(pEntry, rPropVal.Value); + } + } + + // Entries with side effects first, using dedicated one-element SfxItemSet for each + for (const auto& [pEntry, rValue] : aSideEffectsEntries) + { + SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID); + // we need to get up-to-date item set from nodes + SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet); + // this can set some attributes in nodes' mpAttrSet + if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet)) + rPropSet.setPropertyValue(*pEntry, rValue, aItemSet); + SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false /*bTableMode*/); + } + + if (!aEntries.empty()) + { + // Fetch, overwrite, and re-set the attributes from the core + SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aRanges)); + // we need to get up-to-date item set from nodes + SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet); + + for (const auto& [pEntry, rValue] : aEntries) + { + // this can set some attributes in nodes' mpAttrSet + if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet)) + rPropSet.setPropertyValue(*pEntry, rValue, aItemSet); + } + + SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false /*bTableMode*/); + } + + if (!aUnknownExMsg.isEmpty()) + throw beans::UnknownPropertyException(aUnknownExMsg); + if (!aPropertyVetoExMsg.isEmpty()) + throw beans::PropertyVetoException(aPropertyVetoExMsg); +} + +namespace +{ + bool NotInRange(sal_uInt16 nWID, sal_uInt16 nStart, sal_uInt16 nEnd) + { + return nWID < nStart || nWID > nEnd; + } +} + +uno::Sequence< beans::PropertyState > +SwUnoCursorHelper::GetPropertyStates( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + const uno::Sequence< OUString >& rPropertyNames, + const SwGetPropertyStatesCaller eCaller) +{ + const OUString* pNames = rPropertyNames.getConstArray(); + uno::Sequence< beans::PropertyState > aRet(rPropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + const SfxItemPropertyMap &rMap = rPropSet.getPropertyMap(); + std::optional<SfxItemSet> oSet; + std::optional<SfxItemSet> oSetParent; + + for (sal_Int32 i = 0, nEnd = rPropertyNames.getLength(); i < nEnd; i++) + { + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName( pNames[i] ); + if(!pEntry) + { + if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT || + pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT || + pNames[i] == UNO_NAME_NO_FORMAT_ATTR) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + continue; + } + else if (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT == + eCaller) + { + //this values marks the element as unknown property + pStates[i] = beans::PropertyState::PropertyState_MAKE_FIXED_SIZE; + continue; + } + else + { + throw beans::UnknownPropertyException( + "Unknown property: " + pNames[i]); + } + } + if (((SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION == eCaller) || + (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT == eCaller)) && + NotInRange(pEntry->nWID, FN_UNO_RANGE_BEGIN, FN_UNO_RANGE_END) && + NotInRange(pEntry->nWID, RES_CHRATR_BEGIN, RES_TXTATR_END) ) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + else + { + if ( pEntry->nWID >= FN_UNO_RANGE_BEGIN && + pEntry->nWID <= FN_UNO_RANGE_END ) + { + (void)SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, rPaM, nullptr, pStates[i] ); + } + else + { + if (!oSet) + { + switch ( eCaller ) + { + case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT: + case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION: + oSet.emplace( rPaM.GetDoc().GetAttrPool(), + svl::Items<RES_CHRATR_BEGIN, RES_TXTATR_END> ); + break; + case SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY: + oSet.emplace( rPaM.GetDoc().GetAttrPool(), + pEntry->nWID, pEntry->nWID ); + break; + default: + oSet.emplace( + rPaM.GetDoc().GetAttrPool(), + svl::Items< + RES_CHRATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_CONTAINER, + RES_UNKNOWNATR_CONTAINER>); + } + // #i63870# + SwUnoCursorHelper::GetCursorAttr( rPaM, *oSet ); + } + + pStates[i] = ( oSet->Count() ) + ? rPropSet.getPropertyState( *pEntry, *oSet ) + : beans::PropertyState_DEFAULT_VALUE; + + //try again to find out if a value has been inherited + if( beans::PropertyState_DIRECT_VALUE == pStates[i] ) + { + if (!oSetParent) + { + oSetParent.emplace(oSet->CloneAsValue( false )); + // #i63870# + SwUnoCursorHelper::GetCursorAttr( + rPaM, *oSetParent, true, false ); + } + + pStates[i] = ( oSetParent->Count() ) + ? rPropSet.getPropertyState( *pEntry, *oSetParent ) + : beans::PropertyState_DEFAULT_VALUE; + } + } + } + } + return aRet; +} + +beans::PropertyState SwUnoCursorHelper::GetPropertyState( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + const OUString& rPropertyName) +{ + uno::Sequence< OUString > aStrings { rPropertyName }; + uno::Sequence< beans::PropertyState > aSeq = + GetPropertyStates(rPaM, rPropSet, aStrings, + SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY ); + return aSeq[0]; +} + +static void +lcl_SelectParaAndReset( SwPaM &rPaM, SwDoc & rDoc, + o3tl::sorted_vector<sal_uInt16> const &rWhichIds ) +{ + // if we are resetting paragraph attributes, we need to select the full paragraph first + SwPosition aStart = *rPaM.Start(); + SwPosition aEnd = *rPaM.End(); + auto pTemp ( rDoc.CreateUnoCursor(aStart) ); + if(!SwUnoCursorHelper::IsStartOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaStart); + } + pTemp->SetMark(); + *pTemp->GetPoint() = aEnd; + SwUnoCursorHelper::SelectPam(*pTemp, true); + if(!SwUnoCursorHelper::IsEndOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaEnd); + } + rDoc.ResetAttrs(*pTemp, true, rWhichIds); +} + +void SwUnoCursorHelper::SetPropertyToDefault( + SwPaM& rPaM, const SfxItemPropertySet& rPropSet, + std::u16string_view rPropertyName) +{ + SwDoc& rDoc = rPaM.GetDoc(); + SfxItemPropertyMapEntry const*const pEntry = + rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + OUString::Concat("Unknown property: ") + rPropertyName); + } + + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw uno::RuntimeException( + OUString::Concat("setPropertyToDefault: property is read-only: ") + + rPropertyName, nullptr); + } + + if (pEntry->nWID < RES_FRMATR_END) + { + const o3tl::sorted_vector<sal_uInt16> aWhichIds{ pEntry->nWID }; + if (pEntry->nWID < RES_PARATR_BEGIN) + { + rDoc.ResetAttrs(rPaM, true, aWhichIds); + } + else + { + lcl_SelectParaAndReset ( rPaM, rDoc, aWhichIds ); + } + } + else + { + SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, rPaM); + } +} + +uno::Any SwUnoCursorHelper::GetPropertyDefault( + SwPaM const & rPaM, const SfxItemPropertySet& rPropSet, + std::u16string_view rPropertyName) +{ + SfxItemPropertyMapEntry const*const pEntry = + rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + OUString::Concat("Unknown property: ") + rPropertyName); + } + + uno::Any aRet; + if (pEntry->nWID < RES_FRMATR_END) + { + SwDoc& rDoc = rPaM.GetDoc(); + const SfxPoolItem& rDefItem = + rDoc.GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(aRet, pEntry->nMemberId); + } + return aRet; +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXTextCursor::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef = [&]() + { + static SfxItemPropertyMapEntry const aCursorExtMap_Impl[] = + { + { UNO_NAME_IS_SKIP_HIDDEN_TEXT, FN_SKIP_HIDDEN_TEXT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_SKIP_PROTECTED_TEXT, FN_SKIP_PROTECTED_TEXT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_NO_FORMAT_ATTR, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + }; + const uno::Reference< beans::XPropertySetInfo > xInfo = + m_rPropSet.getPropertySetInfo(); + // extend PropertySetInfo! + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + return rtl::Reference<SfxExtItemPropertySetInfo>(new SfxExtItemPropertySetInfo( + aCursorExtMap_Impl, + aPropSeq )); + }(); + return xRef; +} + +void SAL_CALL +SwXTextCursor::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (rPropertyName == UNO_NAME_IS_SKIP_HIDDEN_TEXT) + { + bool bSet(false); + if (!(rValue >>= bSet)) + { + throw lang::IllegalArgumentException(); + } + rUnoCursor.SetSkipOverHiddenSections(bSet); + } + else if (rPropertyName == UNO_NAME_IS_SKIP_PROTECTED_TEXT) + { + bool bSet(false); + if (!(rValue >>= bSet)) + { + throw lang::IllegalArgumentException(); + } + rUnoCursor.SetSkipOverProtectSections(bSet); + } + else if (rPropertyName == UNO_NAME_NO_FORMAT_ATTR) + { + bool bSet(false); + if (!(rValue >>= bSet)) + { + throw lang::IllegalArgumentException(); + } + if (bSet) + { + m_nAttrMode = SetAttrMode::NOFORMATATTR; + } + else + { + m_nAttrMode = SetAttrMode::DEFAULT; + } + } + else if (rPropertyName == "ParaAutoStyleDef") + { + // Create an autostyle from passed definition (sequence of PropertyValue, same + // as in XAutoStyleFamily::insertStyle), using the currently applied properties + // from the paragraph to not lose their values when creating complex properties + // like SvxULSpaceItem, when only part of the properties stored there is passed; + // and apply it to the paragraph. + uno::Sequence<beans::PropertyValue> def; + if (!(rValue >>= def)) + throw lang::IllegalArgumentException(); + + // See SwUnoCursorHelper::SetPropertyValues + + auto pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE); + + // Build set of attributes we want to fetch + WhichRangesContainer aRanges; + for (auto& rPropVal : def) + { + SfxItemPropertyMapEntry const* pEntry = + pPropSet->getPropertyMap().getByName(rPropVal.Name); + if (!pEntry) + continue; // PropValuesToAutoStyleItemSet ignores invalid names + + aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID); + } + + if (!aRanges.empty()) + { + SwAttrSet aAutoStyleItemSet(rUnoCursor.GetDoc().GetAttrPool(), std::move(aRanges)); + // we need to get up-to-date item set: this makes sure that the complex properties, + // that are only partially defined by passed definition, do not lose the rest of + // their already present data (which will become part of the autostyle, too). + SwUnoCursorHelper::GetCursorAttr(rUnoCursor, aAutoStyleItemSet); + // Set normal set ranges before putting into autostyle, to the same ranges + // that are used for paragraph autostyle in SwXAutoStyleFamily::insertStyle + aAutoStyleItemSet.SetRanges(aTextNodeSetRange); + + // Fill the prepared item set, containing current paragraph property values, + // with the passed definition, and create the autostyle. + auto pStyle = PropValuesToAutoStyleItemSet( + rUnoCursor.GetDoc(), IStyleAccess::AUTO_STYLE_PARA, def, aAutoStyleItemSet); + + SwFormatAutoFormat aFormat(RES_AUTO_STYLE); + aFormat.SetStyleHandle(pStyle); + SfxItemSet rSet(rUnoCursor.GetDoc().GetAttrPool(), RES_AUTO_STYLE, RES_AUTO_STYLE); + rSet.Put(aFormat); + SwUnoCursorHelper::SetCursorAttr(rUnoCursor, rSet, m_nAttrMode); + } + } + else + { + SwUnoCursorHelper::SetPropertyValue(rUnoCursor, + m_rPropSet, rPropertyName, rValue, m_nAttrMode); + } +} + +uno::Any SAL_CALL +SwXTextCursor::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + uno::Any aAny; + if (rPropertyName == UNO_NAME_IS_SKIP_HIDDEN_TEXT) + { + const bool bSet = rUnoCursor.IsSkipOverHiddenSections(); + aAny <<= bSet; + } + else if (rPropertyName == UNO_NAME_IS_SKIP_PROTECTED_TEXT) + { + const bool bSet = rUnoCursor.IsSkipOverProtectSections(); + aAny <<= bSet; + } + else + { + aAny = SwUnoCursorHelper::GetPropertyValue(rUnoCursor, + m_rPropSet, rPropertyName); + } + return aAny; +} + +void SAL_CALL +SwXTextCursor::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextCursor::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextCursor::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextCursor::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextCursor::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextCursor::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextCursor::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextCursor::removeVetoableChangeListener(): not implemented"); +} + +beans::PropertyState SAL_CALL +SwXTextCursor::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const beans::PropertyState eRet = SwUnoCursorHelper::GetPropertyState( + rUnoCursor, m_rPropSet, rPropertyName); + return eRet; +} + +uno::Sequence< beans::PropertyState > SAL_CALL +SwXTextCursor::getPropertyStates( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + return SwUnoCursorHelper::GetPropertyStates( + rUnoCursor, m_rPropSet, rPropertyNames); +} + +void SAL_CALL +SwXTextCursor::setPropertyToDefault(const OUString& rPropertyName) +{ + // forward: need no solar mutex here + uno::Sequence < OUString > aSequence ( &rPropertyName, 1 ); + setPropertiesToDefault ( aSequence ); +} + +uno::Any SAL_CALL +SwXTextCursor::getPropertyDefault(const OUString& rPropertyName) +{ + // forward: need no solar mutex here + const uno::Sequence < OUString > aSequence ( &rPropertyName, 1 ); + return getPropertyDefaults ( aSequence ).getConstArray()[0]; +} + +void SAL_CALL SwXTextCursor::setPropertyValues( + const uno::Sequence< OUString >& aPropertyNames, + const uno::Sequence< uno::Any >& aValues ) +{ + if( aValues.getLength() != aPropertyNames.getLength() ) + { + OSL_FAIL( "mis-matched property value sequences" ); + throw lang::IllegalArgumentException(); + } + + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + // a little lame to have to copy into this. + uno::Sequence< beans::PropertyValue > aPropertyValues( aValues.getLength() ); + auto aPropertyValuesRange = asNonConstRange(aPropertyValues); + for ( sal_Int32 i = 0; i < aPropertyNames.getLength(); i++ ) + { + if ( aPropertyNames[ i ] == UNO_NAME_IS_SKIP_HIDDEN_TEXT || + aPropertyNames[ i ] == UNO_NAME_IS_SKIP_PROTECTED_TEXT ) + { + // the behaviour of these is hard to model in a group + OSL_FAIL("invalid property name for batch setting"); + throw lang::IllegalArgumentException(); + } + aPropertyValuesRange[ i ].Name = aPropertyNames[ i ]; + aPropertyValuesRange[ i ].Value = aValues[ i ]; + } + try + { + SwUnoCursorHelper::SetPropertyValues( rUnoCursor, m_rPropSet, aPropertyValues ); + } + catch (const css::beans::UnknownPropertyException& e) + { + uno::Any a(cppu::getCaughtException()); + throw lang::WrappedTargetException( + "wrapped Exception " + e.Message, + uno::Reference<uno::XInterface>(), a); + } +} + +uno::Sequence< uno::Any > SAL_CALL +SwXTextCursor::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames ) +{ + // a banal implementation for now + uno::Sequence< uno::Any > aValues( aPropertyNames.getLength() ); + std::transform(aPropertyNames.begin(), aPropertyNames.end(), aValues.getArray(), + [this](const OUString& rName) -> uno::Any { return getPropertyValue( rName ); }); + return aValues; +} + +void SAL_CALL SwXTextCursor::addPropertiesChangeListener( + const uno::Sequence< OUString >& /* aPropertyNames */, + const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("SwXTextCursor::addPropertiesChangeListener(): not implemented"); +} +void SAL_CALL SwXTextCursor::removePropertiesChangeListener( + const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("SwXTextCursor::removePropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXTextCursor::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /* aPropertyNames */, + const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("SwXTextCursor::firePropertiesChangeEvent(): not implemented"); +} + +// para specific attribute ranges +static sal_uInt16 g_ParaResetableSetRange[] = { + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + 0 +}; + +// selection specific attribute ranges +static sal_uInt16 g_ResetableSetRange[] = { + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_TXTATR_INETFMT, RES_TXTATR_INETFMT, + RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT, + RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY, + RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER, + 0 +}; + +static void +lcl_EnumerateIds(sal_uInt16 const* pIdRange, o3tl::sorted_vector<sal_uInt16> &rWhichIds) +{ + while (*pIdRange) + { + const sal_uInt16 nStart = *pIdRange++; + const sal_uInt16 nEnd = *pIdRange++; + for (sal_uInt16 nId = nStart + 1; nId <= nEnd; ++nId) + { + rWhichIds.insert( nId ); + } + } +} + +void SAL_CALL +SwXTextCursor::setAllPropertiesToDefault() +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + o3tl::sorted_vector<sal_uInt16> aParaWhichIds; + o3tl::sorted_vector<sal_uInt16> aWhichIds; + lcl_EnumerateIds(g_ParaResetableSetRange, aParaWhichIds); + lcl_EnumerateIds(g_ResetableSetRange, aWhichIds); + if (!aParaWhichIds.empty()) + { + lcl_SelectParaAndReset(rUnoCursor, rUnoCursor.GetDoc(), + aParaWhichIds); + } + if (!aWhichIds.empty()) + { + rUnoCursor.GetDoc().ResetAttrs(rUnoCursor, true, aWhichIds); + } +} + +void SAL_CALL +SwXTextCursor::setPropertiesToDefault( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if ( !rPropertyNames.hasElements() ) + return; + + SwDoc& rDoc = rUnoCursor.GetDoc(); + o3tl::sorted_vector<sal_uInt16> aWhichIds; + o3tl::sorted_vector<sal_uInt16> aParaWhichIds; + for (const OUString& rName : rPropertyNames) + { + SfxItemPropertyMapEntry const*const pEntry = + m_rPropSet.getPropertyMap().getByName( rName ); + if (!pEntry) + { + if (rName == UNO_NAME_IS_SKIP_HIDDEN_TEXT || + rName == UNO_NAME_IS_SKIP_PROTECTED_TEXT) + { + continue; + } + throw beans::UnknownPropertyException( + "Unknown property: " + rName, + getXWeak()); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw uno::RuntimeException( + "setPropertiesToDefault: property is read-only: " + rName, + getXWeak()); + } + + if (pEntry->nWID < RES_FRMATR_END) + { + if (pEntry->nWID < RES_PARATR_BEGIN) + { + aWhichIds.insert( pEntry->nWID ); + } + else + { + aParaWhichIds.insert( pEntry->nWID ); + } + } + else if (pEntry->nWID == FN_UNO_NUM_START_VALUE) + { + SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, rUnoCursor); + } + } + + if (!aParaWhichIds.empty()) + { + lcl_SelectParaAndReset(rUnoCursor, rDoc, aParaWhichIds); + } + if (!aWhichIds.empty()) + { + rDoc.ResetAttrs(rUnoCursor, true, aWhichIds); + } +} + +uno::Sequence< uno::Any > SAL_CALL +SwXTextCursor::getPropertyDefaults( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + const sal_Int32 nCount = rPropertyNames.getLength(); + uno::Sequence< uno::Any > aRet(nCount); + if ( nCount ) + { + SwDoc& rDoc = rUnoCursor.GetDoc(); + const OUString *pNames = rPropertyNames.getConstArray(); + uno::Any *pAny = aRet.getArray(); + for (sal_Int32 i = 0; i < nCount; i++) + { + SfxItemPropertyMapEntry const*const pEntry = + m_rPropSet.getPropertyMap().getByName( pNames[i] ); + if (!pEntry) + { + if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT || + pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT || + pNames[i] == UNO_NAME_NO_FORMAT_ATTR) + { + continue; + } + throw beans::UnknownPropertyException( + "Unknown property: " + pNames[i]); + } + if (pEntry->nWID < RES_FRMATR_END) + { + const SfxPoolItem& rDefItem = + rDoc.GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(pAny[i], pEntry->nMemberId); + } + } + } + return aRet; +} + +void SAL_CALL SwXTextCursor::invalidateMarkings(::sal_Int32 nType) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwNode& node = rUnoCursor.GetPointNode(); + + SwTextNode* txtNode = node.GetTextNode(); + + if (txtNode == nullptr) return; + + if ( text::TextMarkupType::SPELLCHECK == nType ) + { + txtNode->SetWrongDirty(sw::WrongState::TODO); + txtNode->ClearWrong(); + } + else if( text::TextMarkupType::PROOFREADING == nType ) + { + txtNode->SetGrammarCheckDirty(true); + txtNode->ClearGrammarCheck(); + } + else if ( text::TextMarkupType::SMARTTAG == nType ) + { + txtNode->SetSmartTagDirty(true); + txtNode->ClearSmartTags(); + } + else return; + + SwFormatColl* fmtColl=txtNode->GetFormatColl(); + + if (fmtColl == nullptr) return; + + SwFormatChg aNew( fmtColl ); + txtNode->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aNew)); +} + +void SAL_CALL +SwXTextCursor::makeRedline( + const OUString& rRedlineType, + const uno::Sequence< beans::PropertyValue >& rRedlineProperties) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::makeRedline(rUnoCursor, rRedlineType, rRedlineProperties); +} + +void SAL_CALL SwXTextCursor::insertDocumentFromURL(const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rOptions) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwUnoCursorHelper::InsertFile(&rUnoCursor, rURL, rOptions); +} + +uno::Sequence< beans::PropertyValue > +SwUnoCursorHelper::CreateSortDescriptor(const bool bFromTable) +{ + uno::Sequence< beans::PropertyValue > aRet(5); + beans::PropertyValue* pArray = aRet.getArray(); + + uno::Any aVal; + aVal <<= bFromTable; + pArray[0] = beans::PropertyValue("IsSortInTable", -1, aVal, + beans::PropertyState_DIRECT_VALUE); + + aVal <<= u' '; + pArray[1] = beans::PropertyValue("Delimiter", -1, aVal, + beans::PropertyState_DIRECT_VALUE); + + aVal <<= false; + pArray[2] = beans::PropertyValue("IsSortColumns", -1, aVal, + beans::PropertyState_DIRECT_VALUE); + + aVal <<= sal_Int32(3); + pArray[3] = beans::PropertyValue("MaxSortFieldsCount", -1, aVal, + beans::PropertyState_DIRECT_VALUE); + + lang::Locale aLang( SvtSysLocale().GetLanguageTag().getLocale()); + // get collator algorithm to be used for the locale + uno::Sequence< OUString > aSeq( + GetAppCollator().listCollatorAlgorithms( aLang ) ); + const bool bHasElements = aSeq.hasElements(); + OSL_ENSURE( bHasElements, "list of collator algorithms is empty!"); + OUString aCollAlg; + if (bHasElements) + { + aCollAlg = aSeq.getConstArray()[0]; + } + + uno::Sequence< table::TableSortField > aFields + { + // Field, IsAscending, IsCaseSensitive, FieldType, CollatorLocale, CollatorAlgorithm + { 1, true, false, table::TableSortFieldType_ALPHANUMERIC, aLang, aCollAlg }, + { 1, true, false, table::TableSortFieldType_ALPHANUMERIC, aLang, aCollAlg }, + { 1, true, false, table::TableSortFieldType_ALPHANUMERIC, aLang, aCollAlg } + }; + + aVal <<= aFields; + pArray[4] = beans::PropertyValue("SortFields", -1, aVal, + beans::PropertyState_DIRECT_VALUE); + + return aRet; +} + +uno::Sequence< beans::PropertyValue > SAL_CALL +SwXTextCursor::createSortDescriptor() +{ + SolarMutexGuard aGuard; + + return SwUnoCursorHelper::CreateSortDescriptor(false); +} + +bool SwUnoCursorHelper::ConvertSortProperties( + const uno::Sequence< beans::PropertyValue >& rDescriptor, + SwSortOptions& rSortOpt) +{ + bool bRet = true; + + rSortOpt.bTable = false; + rSortOpt.cDeli = ' '; + rSortOpt.eDirection = SwSortDirection::Columns; //!! UI text may be contrary though !! + + SwSortKey aKey1; + aKey1.nColumnId = USHRT_MAX; + aKey1.bIsNumeric = true; + aKey1.eSortOrder = SwSortOrder::Ascending; + + SwSortKey aKey2; + aKey2.nColumnId = USHRT_MAX; + aKey2.bIsNumeric = true; + aKey2.eSortOrder = SwSortOrder::Ascending; + + SwSortKey aKey3; + aKey3.nColumnId = USHRT_MAX; + aKey3.bIsNumeric = true; + aKey3.eSortOrder = SwSortOrder::Ascending; + SwSortKey* aKeys[3] = {&aKey1, &aKey2, &aKey3}; + + bool bOldSortdescriptor(false); + bool bNewSortdescriptor(false); + + for (const beans::PropertyValue& rProperty : rDescriptor) + { + uno::Any aValue( rProperty.Value ); + const OUString& rPropName = rProperty.Name; + + // old and new sortdescriptor + if ( rPropName == "IsSortInTable" ) + { + if (auto b = o3tl::tryAccess<bool>(aValue)) + { + rSortOpt.bTable = *b; + } + else + { + bRet = false; + } + } + else if ( rPropName == "Delimiter" ) + { + sal_Unicode uChar; + sal_uInt16 nChar; + if (aValue >>= uChar) + { + rSortOpt.cDeli = uChar; + } + else if (aValue >>= nChar) + { + // For compatibility with BASIC, also accept an ANY containing + // an UNSIGNED SHORT: + rSortOpt.cDeli = nChar; + } + else + { + bRet = false; + } + } + // old sortdescriptor + else if ( rPropName == "SortColumns" ) + { + bOldSortdescriptor = true; + bool bTemp(false); + if (aValue >>= bTemp) + { + rSortOpt.eDirection = bTemp ? SwSortDirection::Columns : SwSortDirection::Rows; + } + else + { + bRet = false; + } + } + else if ( rPropName == "IsCaseSensitive" ) + { + bOldSortdescriptor = true; + bool bTemp(false); + if (aValue >>= bTemp) + { + rSortOpt.bIgnoreCase = !bTemp; + } + else + { + bRet = false; + } + } + else if ( rPropName == "CollatorLocale" ) + { + bOldSortdescriptor = true; + lang::Locale aLocale; + if (aValue >>= aLocale) + { + rSortOpt.nLanguage = LanguageTag::convertToLanguageType( aLocale); + } + else + { + bRet = false; + } + } + else if (rPropName.startsWith("CollatorAlgorithm") && + rPropName.getLength() == 18 && + (rPropName[17] >= '0' && rPropName[17] <= '9')) + { + bOldSortdescriptor = true; + sal_uInt16 nIndex = rPropName[17]; + nIndex -= '0'; + OUString aText; + if ((aValue >>= aText) && nIndex < 3) + { + aKeys[nIndex]->sSortType = aText; + } + else + { + bRet = false; + } + } + else if (rPropName.startsWith("SortRowOrColumnNo") && + rPropName.getLength() == 18 && + (rPropName[17] >= '0' && rPropName[17] <= '9')) + { + bOldSortdescriptor = true; + sal_uInt16 nIndex = rPropName[17]; + nIndex -= '0'; + sal_Int16 nCol = -1; + if (aValue.getValueType() == ::cppu::UnoType<sal_Int16>::get() + && nIndex < 3) + { + aValue >>= nCol; + } + if (nCol >= 0) + { + aKeys[nIndex]->nColumnId = nCol; + } + else + { + bRet = false; + } + } + else if (rPropName.startsWith("IsSortNumeric") && + rPropName.getLength() == 14 && + (rPropName[13] >= '0' && rPropName[13] <= '9')) + { + bOldSortdescriptor = true; + sal_uInt16 nIndex = rPropName[13]; + nIndex = nIndex - '0'; + std::optional<const bool> bTemp = o3tl::tryAccess<bool>(aValue); + if (bTemp.has_value() && nIndex < 3) + { + aKeys[nIndex]->bIsNumeric = *bTemp; + } + else + { + bRet = false; + } + } + else if (rPropName.startsWith("IsSortAscending") && + rPropName.getLength() == 16 && + (rPropName[15] >= '0' && rPropName[15] <= '9')) + { + bOldSortdescriptor = true; + sal_uInt16 nIndex = rPropName[15]; + nIndex -= '0'; + std::optional<const bool> bTemp = o3tl::tryAccess<bool>(aValue); + if (bTemp.has_value() && nIndex < 3) + { + aKeys[nIndex]->eSortOrder = (*bTemp) + ? SwSortOrder::Ascending : SwSortOrder::Descending; + } + else + { + bRet = false; + } + } + // new sortdescriptor + else if ( rPropName == "IsSortColumns" ) + { + bNewSortdescriptor = true; + if (auto bTemp = o3tl::tryAccess<bool>(aValue)) + { + rSortOpt.eDirection = *bTemp ? SwSortDirection::Columns : SwSortDirection::Rows; + } + else + { + bRet = false; + } + } + else if ( rPropName == "SortFields" ) + { + bNewSortdescriptor = true; + uno::Sequence < table::TableSortField > aFields; + if (aValue >>= aFields) + { + sal_Int32 nCount(aFields.getLength()); + if (nCount <= 3) + { + table::TableSortField* pFields = aFields.getArray(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + rSortOpt.bIgnoreCase = !pFields[i].IsCaseSensitive; + rSortOpt.nLanguage = + LanguageTag::convertToLanguageType( pFields[i].CollatorLocale ); + aKeys[i]->sSortType = pFields[i].CollatorAlgorithm; + aKeys[i]->nColumnId = + o3tl::narrowing<sal_uInt16>(pFields[i].Field); + aKeys[i]->bIsNumeric = (pFields[i].FieldType == + table::TableSortFieldType_NUMERIC); + aKeys[i]->eSortOrder = (pFields[i].IsAscending) + ? SwSortOrder::Ascending : SwSortOrder::Descending; + } + } + else + { + bRet = false; + } + } + else + { + bRet = false; + } + } + } + + if (bNewSortdescriptor && bOldSortdescriptor) + { + OSL_FAIL("someone tried to set the old deprecated and " + "the new sortdescriptor"); + bRet = false; + } + + if (aKey1.nColumnId != USHRT_MAX) + { + rSortOpt.aKeys.push_back(aKey1); + } + if (aKey2.nColumnId != USHRT_MAX) + { + rSortOpt.aKeys.push_back(aKey2); + } + if (aKey3.nColumnId != USHRT_MAX) + { + rSortOpt.aKeys.push_back(aKey3); + } + + return bRet && !rSortOpt.aKeys.empty(); +} + +void SAL_CALL +SwXTextCursor::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor) +{ + SolarMutexGuard aGuard; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + if (!rUnoCursor.HasMark()) + return; + + SwSortOptions aSortOpt; + if (!SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)) + { + throw uno::RuntimeException("Bad sort properties"); + } + UnoActionContext aContext( &rUnoCursor.GetDoc() ); + + SwPosition & rStart = *rUnoCursor.Start(); + SwPosition & rEnd = *rUnoCursor.End(); + + SwNodeIndex aPrevIdx( rStart.GetNode(), -1 ); + const SwNodeOffset nOffset = rEnd.GetNodeIndex() - rStart.GetNodeIndex(); + const sal_Int32 nCntStt = rStart.GetContentIndex(); + + rUnoCursor.GetDoc().SortText(rUnoCursor, aSortOpt); + + // update selection + rUnoCursor.DeleteMark(); + rUnoCursor.GetPoint()->Assign( aPrevIdx.GetNode(), SwNodeOffset(1) ); + SwContentNode *const pCNd = rUnoCursor.GetPointContentNode(); + sal_Int32 nLen = pCNd->Len(); + if (nLen > nCntStt) + { + nLen = nCntStt; + } + rUnoCursor.GetPoint()->SetContent( nLen ); + rUnoCursor.SetMark(); + + rUnoCursor.GetPoint()->Adjust(nOffset); + SwContentNode *const pCNd2 = rUnoCursor.GetPointContentNode(); + rUnoCursor.GetPoint()->SetContent( pCNd2->Len() ); + +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXTextCursor::createContentEnumeration(const OUString& rServiceName) +{ + SolarMutexGuard g; + if (rServiceName != "com.sun.star.text.TextContent") + throw uno::RuntimeException(); + SwUnoCursor& rUnoCursor( GetCursorOrThrow() ); + return SwXParaFrameEnumeration::Create(rUnoCursor, PARAFRAME_PORTION_TEXTRANGE); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXTextCursor::createEnumeration() +{ + SolarMutexGuard g; + + SwUnoCursor & rUnoCursor( GetCursorOrThrow() ); + + SwXText* pParentText = dynamic_cast<SwXText*>(m_xParentText.get()); + OSL_ENSURE(pParentText, "parent is not a SwXText"); + if (!pParentText) + { + throw uno::RuntimeException(); + } + + auto pNewCursor(rUnoCursor.GetDoc().CreateUnoCursor(*rUnoCursor.GetPoint()) ); + if (rUnoCursor.HasMark()) + { + pNewCursor->SetMark(); + *pNewCursor->GetMark() = *rUnoCursor.GetMark(); + } + const CursorType eSetType = (CursorType::TableText == m_eType) + ? CursorType::SelectionInTable : CursorType::Selection; + return SwXParagraphEnumeration::Create(pParentText, pNewCursor, eSetType); +} + +uno::Type SAL_CALL +SwXTextCursor::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXTextCursor::hasElements() +{ + return true; +} + +uno::Sequence< OUString > SAL_CALL +SwXTextCursor::getAvailableServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; + return aRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoobj2.cxx b/sw/source/core/unocore/unoobj2.cxx new file mode 100644 index 0000000000..7614f0a314 --- /dev/null +++ b/sw/source/core/unocore/unoobj2.cxx @@ -0,0 +1,1860 @@ +/* -*- 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 <sal/config.h> + +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> +#include <svl/listener.hxx> +#include <svx/svdobj.hxx> +#include <utility> +#include <vcl/svapp.hxx> + +#include <anchoredobject.hxx> +#include <swtypes.hxx> +#include <hintids.hxx> +#include <IMark.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentMarkAccess.hxx> +#include <textboxhelper.hxx> +#include <ndtxt.hxx> +#include <unocrsr.hxx> +#include <unotextcursor.hxx> +#include <swundo.hxx> +#include <rootfrm.hxx> +#include <ftnidx.hxx> +#include <pam.hxx> +#include <swtblfmt.hxx> +#include <docsh.hxx> +#include <pagedesc.hxx> +#include <cntfrm.hxx> +#include <flyfrm.hxx> +#include <flyfrms.hxx> +#include <unoparaframeenum.hxx> +#include <unofootnote.hxx> +#include <unotextbodyhf.hxx> +#include <unotextrange.hxx> +#include <unoparagraph.hxx> +#include <unomap.hxx> +#include <unoport.hxx> +#include <unocrsrhelper.hxx> +#include <unotbl.hxx> +#include <fmtanchr.hxx> +#include <flypos.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <fmtcntnt.hxx> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <unoframe.hxx> +#include <fmthdft.hxx> +#include <fmtflcnt.hxx> +#include <vector> +#include <sortedobjs.hxx> +#include <frameformats.hxx> +#include <algorithm> +#include <iterator> + +using namespace ::com::sun::star; + +namespace sw { + +void DeepCopyPaM(SwPaM const & rSource, SwPaM & rTarget) +{ + rTarget = rSource; + + if (rSource.GetNext() == &rSource) + return; + + SwPaM *pPam = const_cast<SwPaM*>(rSource.GetNext()); + do + { + // create new PaM + SwPaM *const pNew = new SwPaM(*pPam, nullptr); + // insert into ring + pNew->MoveTo(&rTarget); + pPam = pPam->GetNext(); + } + while (pPam != &rSource); +} + +} // namespace sw + +namespace { + +struct FrameClientSortListLess +{ + bool operator() (FrameClientSortListEntry const& r1, + FrameClientSortListEntry const& r2) const + { + return (r1.nIndex < r2.nIndex) + || ((r1.nIndex == r2.nIndex) && (r1.nOrder < r2.nOrder)); + } +}; + + void lcl_CollectFrameAtNodeWithLayout(const SwContentFrame* pCFrame, + FrameClientSortList_t& rFrames, + const RndStdIds nAnchorType) + { + auto pObjs = pCFrame->GetDrawObjs(); + if(!pObjs) + return; + for(const auto pAnchoredObj : *pObjs) + { + SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat(); + // Filter out textboxes, which are not interesting at a UNO level. + if(SwTextBoxHelper::isTextBox(&rFormat, RES_FLYFRMFMT)) + continue; + + if (nAnchorType == RndStdIds::FLY_AT_PARA) + { + auto pFlyAtContentFrame = dynamic_cast<SwFlyAtContentFrame*>(pAnchoredObj); + if (pFlyAtContentFrame && pFlyAtContentFrame->IsFollow()) + { + // We're collecting frame formats, ignore non-master fly frames to prevent + // duplication. + continue; + } + } + + if(rFormat.GetAnchor().GetAnchorId() == nAnchorType) + { + const sal_Int32 nIdx = rFormat.GetAnchor().GetAnchorContentOffset(); + const auto nOrder = rFormat.GetAnchor().GetOrder(); + rFrames.emplace_back(nIdx, nOrder, std::make_unique<sw::FrameClient>(&rFormat)); + } + } + } +} + + +void CollectFrameAtNode( const SwNode& rNd, + FrameClientSortList_t& rFrames, + const bool bAtCharAnchoredObjs ) +{ + // _bAtCharAnchoredObjs: + // <true>: at-character anchored objects are collected + // <false>: at-paragraph anchored objects are collected + + // search all borders, images, and OLEs that are connected to the paragraph + const SwDoc& rDoc = rNd.GetDoc(); + + const auto nChkType = bAtCharAnchoredObjs ? RndStdIds::FLY_AT_CHAR : RndStdIds::FLY_AT_PARA; + const SwContentFrame* pCFrame; + const SwContentNode* pCNd; + if( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() && + nullptr != (pCNd = rNd.GetContentNode()) && + nullptr != (pCFrame = pCNd->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout())) ) + { + lcl_CollectFrameAtNodeWithLayout(pCFrame, rFrames, nChkType); + } + else + { + for(sw::SpzFrameFormat* pSpz: *rDoc.GetSpzFrameFormats()) + { + const SwFormatAnchor& rAnchor = pSpz->GetAnchor(); + const SwNode* pAnchorNode; + if( rAnchor.GetAnchorId() == nChkType && + nullptr != (pAnchorNode = rAnchor.GetAnchorNode()) && + *pAnchorNode == rNd ) + { + + // OD 2004-05-07 #i28701# - determine insert position for + // sorted <rFrameArr> + const sal_Int32 nIndex = rAnchor.GetAnchorContentOffset(); + sal_uInt32 nOrder = rAnchor.GetOrder(); + + rFrames.emplace_back(nIndex, nOrder, std::make_unique<sw::FrameClient>(pSpz)); + } + } + std::sort(rFrames.begin(), rFrames.end(), FrameClientSortListLess()); + } +} + +UnoActionContext::UnoActionContext(SwDoc *const pDoc) + : m_pDoc(pDoc) +{ + SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + if (pRootFrame) + { + pRootFrame->StartAllAction(); + } +} + +UnoActionContext::~UnoActionContext() COVERITY_NOEXCEPT_FALSE +{ + // Doc may already have been removed here + if (m_pDoc) + { + SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + if (pRootFrame) + { + pRootFrame->EndAllAction(); + } + } +} + +static void lcl_RemoveImpl(SwDoc *const pDoc) +{ + assert(pDoc); + SwRootFrame *const pRootFrame = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + if (pRootFrame) + { + pRootFrame->UnoRemoveAllActions(); + } +} + +UnoActionRemoveContext::UnoActionRemoveContext(SwDoc *const pDoc) + : m_pDoc(pDoc) +{ + lcl_RemoveImpl(m_pDoc); +} + +static SwDoc * lcl_IsNewStyleTable(SwUnoTableCursor const& rCursor) +{ + SwTableNode *const pTableNode = rCursor.GetPointNode().FindTableNode(); + return (pTableNode && !pTableNode->GetTable().IsNewModel()) + ? &rCursor.GetDoc() + : nullptr; +} + +UnoActionRemoveContext::UnoActionRemoveContext(SwUnoTableCursor const& rCursor) + : m_pDoc(lcl_IsNewStyleTable(rCursor)) +{ + // this insanity is only necessary for old-style tables + // because SwRootFrame::MakeTableCursors() creates the table cursor for these + if (m_pDoc) + { + lcl_RemoveImpl(m_pDoc); + } +} + +UnoActionRemoveContext::~UnoActionRemoveContext() COVERITY_NOEXCEPT_FALSE +{ + if (m_pDoc) + { + SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + if (pRootFrame) + { + pRootFrame->UnoRestoreAllActions(); + } + } +} + +void SwUnoCursorHelper::SetCursorAttr(SwPaM & rPam, + const SfxItemSet& rSet, + const SetAttrMode nAttrMode, const bool bTableMode) +{ + const SetAttrMode nFlags = nAttrMode | SetAttrMode::APICALL; + SwDoc& rDoc = rPam.GetDoc(); + //StartEndAction + UnoActionContext aAction(&rDoc); + if (rPam.GetNext() != &rPam) // Ring of Cursors + { + rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSATTR, nullptr); + + for(SwPaM& rCurrent : rPam.GetRingContainer()) + { + if (rCurrent.HasMark() && + ( bTableMode || + (*rCurrent.GetPoint() != *rCurrent.GetMark()) )) + { + rDoc.getIDocumentContentOperations().InsertItemSet(rCurrent, rSet, nFlags); + } + } + + rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSATTR, nullptr); + } + else + { + rDoc.getIDocumentContentOperations().InsertItemSet( rPam, rSet, nFlags ); + } + + if( rSet.GetItemState( RES_PARATR_OUTLINELEVEL, false ) >= SfxItemState::DEFAULT ) + { + SwTextNode * pTmpNode = rPam.GetPointNode().GetTextNode(); + if ( pTmpNode ) + { + rPam.GetDoc().GetNodes().UpdateOutlineNode( *pTmpNode ); + } + } +} + +// #i63870# +// split third parameter <bCurrentAttrOnly> into new parameters <bOnlyTextAttr> +// and <bGetFromChrFormat> to get better control about resulting <SfxItemSet> +void SwUnoCursorHelper::GetCursorAttr(SwPaM & rPam, + SfxItemSet & rSet, const bool bOnlyTextAttr, const bool bGetFromChrFormat) +{ + static const sal_uLong nMaxLookup = 1000; + SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() ); + SfxItemSet *pSet = &rSet; + for(SwPaM& rCurrent : rPam.GetRingContainer()) + { + SwPosition const & rStart( *rCurrent.Start() ); + SwPosition const & rEnd( *rCurrent.End() ); + const SwNodeOffset nSttNd = rStart.GetNodeIndex(); + const SwNodeOffset nEndNd = rEnd .GetNodeIndex(); + + if (nEndNd - nSttNd >= SwNodeOffset(nMaxLookup)) + { + rSet.ClearItem(); + rSet.InvalidateAllItems(); + return;// uno::Any(); + } + + // the first node inserts the values into the get set + // all other nodes merge their values into the get set + for (SwNodeOffset n = nSttNd; n <= nEndNd; ++n) + { + SwNode *const pNd = rPam.GetDoc().GetNodes()[ n ]; + switch (pNd->GetNodeType()) + { + case SwNodeType::Text: + { + const sal_Int32 nStart = (n == nSttNd) + ? rStart.GetContentIndex() : 0; + const sal_Int32 nEnd = (n == nEndNd) + ? rEnd.GetContentIndex() + : pNd->GetTextNode()->GetText().getLength(); + pNd->GetTextNode()->GetParaAttr(*pSet, nStart, nEnd, bOnlyTextAttr, bGetFromChrFormat); + } + break; + + case SwNodeType::Grf: + case SwNodeType::Ole: + static_cast<SwContentNode*>(pNd)->GetAttr( *pSet ); + break; + + default: + continue; // skip this node + } + + if (pSet != &rSet) + { + rSet.MergeValues( aSet ); + } + else + { + pSet = &aSet; + } + + if (aSet.Count()) + { + aSet.ClearItem(); + } + } + } +} + +namespace { + +struct SwXParagraphEnumerationImpl final : public SwXParagraphEnumeration +{ + uno::Reference< text::XText > const m_xParentText; + const CursorType m_eCursorType; + /// Start node of the cell _or_ table the enumeration belongs to. + /// Used to restrict the movement of the UNO cursor to the cell and its + /// embedded tables. + SwStartNode const*const m_pOwnStartNode; + SwTable const*const m_pOwnTable; + const SwNodeOffset m_nEndIndex; + sal_Int32 m_nFirstParaStart; + sal_Int32 m_nLastParaEnd; + bool m_bFirstParagraph; + uno::Reference< text::XTextContent > m_xNextPara; + sw::UnoCursorPointer m_pCursor; + + SwXParagraphEnumerationImpl( + uno::Reference< text::XText > xParent, + const std::shared_ptr<SwUnoCursor>& pCursor, + const CursorType eType, + SwStartNode const*const pStartNode, SwTable const*const pTable) + : m_xParentText(std::move( xParent )) + , m_eCursorType( eType ) + // remember table and start node for later travelling + // (used in export of tables in tables) + , m_pOwnStartNode( pStartNode ) + // for import of tables in tables we have to remember the actual + // table and start node of the current position in the enumeration. + , m_pOwnTable( pTable ) + , m_nEndIndex( pCursor->End()->GetNodeIndex() ) + , m_nFirstParaStart( -1 ) + , m_nLastParaEnd( -1 ) + , m_bFirstParagraph( true ) + , m_pCursor(pCursor) + { + OSL_ENSURE(m_xParentText.is(), "SwXParagraphEnumeration: no parent?"); + assert( !((CursorType::SelectionInTable == eType) + || (CursorType::TableText == eType)) + || (m_pOwnTable && m_pOwnStartNode)); + + if ((CursorType::Selection == m_eCursorType) || + (CursorType::SelectionInTable == m_eCursorType)) + { + SwUnoCursor & rCursor = GetCursor(); + rCursor.Normalize(); + m_nFirstParaStart = rCursor.GetPoint()->GetContentIndex(); + m_nLastParaEnd = rCursor.GetMark()->GetContentIndex(); + rCursor.DeleteMark(); + } + } + + virtual ~SwXParagraphEnumerationImpl() override + { m_pCursor.reset(nullptr); } + virtual void SAL_CALL release() noexcept override + { + SolarMutexGuard g; + OWeakObject::release(); + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return "SwXParagraphEnumeration"; } + virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName) override + { return cppu::supportsService(this, rServiceName); }; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { return {"com.sun.star.text.ParagraphEnumeration"}; }; + + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual css::uno::Any SAL_CALL nextElement() override; + + SwUnoCursor& GetCursor() + { return *m_pCursor; } + /// @throws container::NoSuchElementException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + uno::Reference< text::XTextContent > NextElement_Impl(); + + /** + * Determines if the last element in the enumeration should be ignored or + * not. + */ + bool IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable); +}; + +} + +rtl::Reference<SwXParagraphEnumeration> SwXParagraphEnumeration::Create( + uno::Reference< text::XText > const& xParent, + const std::shared_ptr<SwUnoCursor>& pCursor, + const CursorType eType, + SwTableBox const*const pTableBox) +{ + SwStartNode const* pStartNode(nullptr); + SwTable const* pTable(nullptr); + assert((eType == CursorType::TableText) == (pTableBox != nullptr)); + switch (eType) + { + case CursorType::TableText: + { + pStartNode = pTableBox->GetSttNd(); + pTable = & pStartNode->FindTableNode()->GetTable(); + break; + } + case CursorType::SelectionInTable: + { + SwTableNode const*const pTableNode( + pCursor->GetPoint()->GetNode().FindTableNode()); + pStartNode = pTableNode; + pTable = & pTableNode->GetTable(); + break; + } + default: + break; + } + return new SwXParagraphEnumerationImpl(xParent, pCursor, eType, pStartNode, pTable); +} + +sal_Bool SAL_CALL +SwXParagraphEnumerationImpl::hasMoreElements() +{ + SolarMutexGuard aGuard; + return m_bFirstParagraph || m_xNextPara.is(); +} + +//!! compare to SwShellTableCursor::FillRects() in viscrs.cxx +static SwTableNode * +lcl_FindTopLevelTable( + SwTableNode *const pTableNode, SwTable const*const pOwnTable) +{ + // find top-most table in current context (section) level + + SwTableNode * pLast = pTableNode; + for (SwTableNode* pTmp = pLast; + pTmp != nullptr && &pTmp->GetTable() != pOwnTable; /* we must not go up higher than the own table! */ + pTmp = pTmp->StartOfSectionNode()->FindTableNode() ) + { + pLast = pTmp; + } + return pLast; +} + +static bool +lcl_CursorIsInSection( + SwUnoCursor const*const pUnoCursor, SwStartNode const*const pOwnStartNode) +{ + // returns true if the cursor is in the section (or in a sub section!) + // represented by pOwnStartNode + + bool bRes = true; + if (pUnoCursor && pOwnStartNode) + { + const SwEndNode * pOwnEndNode = pOwnStartNode->EndOfSectionNode(); + bRes = pOwnStartNode->GetIndex() <= pUnoCursor->Start()->GetNodeIndex() && + pUnoCursor->End()->GetNodeIndex() <= pOwnEndNode->GetIndex(); + } + return bRes; +} + +bool SwXParagraphEnumerationImpl::IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable) +{ + // Ignore the last element of a selection enumeration if this is a stub + // paragraph (directly after table, selection ends at paragraph start). + + if (rCursor.Start()->GetNodeIndex() != m_nEndIndex) + return false; + + if (m_eCursorType != CursorType::Selection) + return false; + + if (!bMovedFromTable) + return false; + + return m_nLastParaEnd == 0; +} + +uno::Reference< text::XTextContent > +SwXParagraphEnumerationImpl::NextElement_Impl() +{ + SwUnoCursor& rUnoCursor = GetCursor(); + + // check for exceeding selections + if (!m_bFirstParagraph && + ((CursorType::Selection == m_eCursorType) || + (CursorType::SelectionInTable == m_eCursorType))) + { + SwPosition* pStart = rUnoCursor.Start(); + auto aNewCursor(rUnoCursor.GetDoc().CreateUnoCursor(*pStart)); + // one may also go into tables here + if (CursorType::SelectionInTable != m_eCursorType) + { + aNewCursor->SetRemainInSection( false ); + } + + // os 2005-01-14: This part is only necessary to detect movements out + // of a selection; if there is no selection we don't have to care + SwTableNode *const pTableNode = aNewCursor->GetPointNode().FindTableNode(); + bool bMovedFromTable = false; + if (CursorType::SelectionInTable != m_eCursorType && pTableNode) + { + aNewCursor->GetPoint()->Assign( pTableNode->EndOfSectionIndex() ); + aNewCursor->Move(fnMoveForward, GoInNode); + bMovedFromTable = true; + } + else + { + aNewCursor->MovePara(GoNextPara, fnParaStart); + } + if (m_nEndIndex < aNewCursor->Start()->GetNodeIndex()) + { + return nullptr; + } + + if (IgnoreLastElement(*aNewCursor, bMovedFromTable)) + { + return nullptr; + } + } + + bool bInTable = false; + if (!m_bFirstParagraph) + { + rUnoCursor.SetRemainInSection( false ); + // what to do if already in a table? + SwTableNode * pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + pTableNode = lcl_FindTopLevelTable( pTableNode, m_pOwnTable ); + if (pTableNode && (&pTableNode->GetTable() != m_pOwnTable)) + { + // this is a foreign table: go to end + rUnoCursor.GetPoint()->Assign( pTableNode->EndOfSectionIndex() ); + if (!rUnoCursor.Move(fnMoveForward, GoInNode)) + { + return nullptr; + } + bInTable = true; + } + } + + uno::Reference< text::XTextContent > xRef; + // the cursor must remain in the current section or a subsection + // before AND after the movement... + if (lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode ) && + (m_bFirstParagraph || bInTable || + (rUnoCursor.MovePara(GoNextPara, fnParaStart) && + lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode )))) + { + if (m_eCursorType == CursorType::Selection || m_eCursorType == CursorType::SelectionInTable) + { + // This is a selection, check if the cursor would go past the end + // of the selection. + if (rUnoCursor.Start()->GetNodeIndex() > m_nEndIndex) + return nullptr; + } + + SwPosition* pStart = rUnoCursor.Start(); + const sal_Int32 nFirstContent = + m_bFirstParagraph ? m_nFirstParaStart : -1; + const sal_Int32 nLastContent = + (m_nEndIndex == pStart->GetNodeIndex()) ? m_nLastParaEnd : -1; + + // position in a table, or in a simple paragraph? + SwTableNode * pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + pTableNode = lcl_FindTopLevelTable( pTableNode, m_pOwnTable ); + if (/*CursorType::TableText != eCursorType && CursorType::SelectionInTable != eCursorType && */ + pTableNode && (&pTableNode->GetTable() != m_pOwnTable)) + { + // this is a foreign table + SwFrameFormat* pTableFormat = pTableNode->GetTable().GetFrameFormat(); + xRef = SwXTextTable::CreateXTextTable(pTableFormat); + } + else + { + text::XText *const pText = m_xParentText.get(); + xRef = SwXParagraph::CreateXParagraph(rUnoCursor.GetDoc(), + pStart->GetNode().GetTextNode(), + static_cast<SwXText*>(pText), nFirstContent, nLastContent); + } + } + + return xRef; +} + +uno::Any SAL_CALL SwXParagraphEnumerationImpl::nextElement() +{ + SolarMutexGuard aGuard; + if (m_bFirstParagraph) + { + m_xNextPara = NextElement_Impl(); + m_bFirstParagraph = false; + } + const uno::Reference< text::XTextContent > xRef = m_xNextPara; + if (!xRef.is()) + { + throw container::NoSuchElementException(); + } + m_xNextPara = NextElement_Impl(); + + uno::Any aRet; + aRet <<= xRef; + return aRet; +} + +class SwXTextRange::Impl + : public SvtListener +{ +public: + const SfxItemPropertySet& m_rPropSet; + const enum RangePosition m_eRangePosition; + SwDoc& m_rDoc; + uno::Reference<text::XText> m_xParentText; + const SwFrameFormat* m_pTableOrSectionFormat; + const ::sw::mark::IMark* m_pMark; + + Impl(SwDoc& rDoc, const enum RangePosition eRange, + SwFrameFormat* const pTableOrSectionFormat, + uno::Reference<text::XText> xParent = nullptr) + : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR)) + , m_eRangePosition(eRange) + , m_rDoc(rDoc) + , m_xParentText(std::move(xParent)) + , m_pTableOrSectionFormat(pTableOrSectionFormat) + , m_pMark(nullptr) + { + if (m_pTableOrSectionFormat) + { + assert(m_eRangePosition == RANGE_IS_TABLE || m_eRangePosition == RANGE_IS_SECTION); + StartListening(pTableOrSectionFormat->GetNotifier()); + } + else + { + assert(m_eRangePosition != RANGE_IS_TABLE && m_eRangePosition != RANGE_IS_SECTION); + } + } + + virtual ~Impl() override + { + // Impl owns the bookmark; delete it here: SolarMutex is locked + Invalidate(); + } + + void Invalidate() + { + if (m_pMark) + { + m_rDoc.getIDocumentMarkAccess()->deleteMark(m_pMark); + m_pMark = nullptr; + } + m_pTableOrSectionFormat = nullptr; + EndListeningAll(); + } + + const ::sw::mark::IMark* GetBookmark() const { return m_pMark; } + void SetMark(::sw::mark::IMark& rMark) + { + EndListeningAll(); + m_pTableOrSectionFormat = nullptr; + m_pMark = &rMark; + StartListening(rMark.GetNotifier()); + } + +protected: + virtual void Notify(const SfxHint&) override; +}; + +void SwXTextRange::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + EndListeningAll(); + m_pTableOrSectionFormat = nullptr; + m_pMark = nullptr; + } +} + +SwXTextRange::SwXTextRange(SwPaM const & rPam, + const uno::Reference< text::XText > & xParent, + const enum RangePosition eRange) + : m_pImpl( new SwXTextRange::Impl(rPam.GetDoc(), eRange, nullptr, xParent) ) +{ + SetPositions(rPam); +} + +SwXTextRange::SwXTextRange(SwTableFormat& rTableFormat) + : m_pImpl( + new SwXTextRange::Impl(*rTableFormat.GetDoc(), RANGE_IS_TABLE, &rTableFormat) ) +{ + SwTable *const pTable = SwTable::FindTable( &rTableFormat ); + SwTableNode *const pTableNode = pTable->GetTableNode(); + SwPaM aPam( *pTableNode ); + + SetPositions( aPam ); +} + +SwXTextRange::SwXTextRange(SwSectionFormat& rSectionFormat) + : m_pImpl( + new SwXTextRange::Impl(*rSectionFormat.GetDoc(), RANGE_IS_SECTION, &rSectionFormat) ) +{ + // no SetPositions here for now +} + +SwXTextRange::~SwXTextRange() +{ +} + +const SwDoc& SwXTextRange::GetDoc() const +{ + return m_pImpl->m_rDoc; +} + +SwDoc& SwXTextRange::GetDoc() +{ + return m_pImpl->m_rDoc; +} + +void SwXTextRange::Invalidate() +{ + m_pImpl->Invalidate(); +} + +void SwXTextRange::SetPositions(const SwPaM& rPam) +{ + m_pImpl->Invalidate(); + IDocumentMarkAccess* const pMA = m_pImpl->m_rDoc.getIDocumentMarkAccess(); + auto pMark = pMA->makeMark(rPam, OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK, sw::mark::InsertMode::New); + if (pMark) + m_pImpl->SetMark(*pMark); +} + +static void DeleteTable(SwDoc & rDoc, SwTable& rTable) +{ + SwSelBoxes aSelBoxes; + for (auto& rBox : rTable.GetTabSortBoxes()) + { + aSelBoxes.insert(rBox); + } + // note: if the table is the content in the section, this will create + // a new text node - that's desirable here + rDoc.DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected); +} + +void SwXTextRange::DeleteAndInsert( + std::u16string_view aText, ::sw::DeleteAndInsertMode const eMode) +{ + if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) + { + // setString on table not allowed + throw uno::RuntimeException("not possible for table"); + } + + const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); + SwCursor aCursor(aPos, nullptr); + + UnoActionContext aAction(& m_pImpl->m_rDoc); + + if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition) + { + SwSectionNode const* pSectionNode = m_pImpl->m_pTableOrSectionFormat ? + static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat)->GetSectionNode() : + nullptr; + if (!pSectionNode) + { + throw uno::RuntimeException("disposed?"); + } + m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + SwNodeIndex const start(*pSectionNode); + SwNodeIndex const end(*start.GetNode().EndOfSectionNode()); + + // delete tables at start + for (SwNodeIndex i = start; i < end; ) + { + SwNode & rNode(i.GetNode()); + if (rNode.IsSectionNode()) + { + ++i; + continue; + } + else if (SwTableNode *const pTableNode = rNode.GetTableNode()) + { + DeleteTable(m_pImpl->m_rDoc, pTableNode->GetTable()); + // where does that leave index? presumably behind? + } + else + { + assert(rNode.IsTextNode()); + break; + } + } + // delete tables at end + for (SwNodeIndex i = end; start <= i; ) + { + --i; + SwNode & rNode(i.GetNode()); + if (rNode.IsEndNode()) + { + if (SwTableNode *const pTableNode = rNode.StartOfSectionNode()->GetTableNode()) + { + DeleteTable(m_pImpl->m_rDoc, pTableNode->GetTable()); + } + else + { + assert(rNode.StartOfSectionNode()->IsSectionNode()); + continue; + } + } + else + { + assert(rNode.IsTextNode()); + break; + } + } + // now there should be a text node at the start and end of it! + aCursor.GetPoint()->Assign(start); + aCursor.Move( fnMoveForward, GoInContent ); + assert(aCursor.GetPoint()->GetNode() <= end.GetNode()); + aCursor.SetMark(); + aCursor.GetPoint()->Assign(end); + aCursor.Move( fnMoveBackward, GoInContent ); + assert(start <= aCursor.GetPoint()->GetNode()); + } + else + { + if (!GetPositions(aCursor)) + return; + m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + } + + if (aCursor.HasMark()) + { + m_pImpl->m_rDoc.getIDocumentContentOperations().DeleteAndJoin(aCursor, + (!aText.empty() || eMode & ::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default); + } + + if (!aText.empty()) + { + SwUnoCursorHelper::DocInsertStringSplitCR( + m_pImpl->m_rDoc, aCursor, aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints)); + + SwUnoCursorHelper::SelectPam(aCursor, true); + aCursor.Left(aText.size()); + } + SetPositions(aCursor); + m_pImpl->m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); +} + +OUString SAL_CALL +SwXTextRange::getImplementationName() +{ + return "SwXTextRange"; +} + +sal_Bool SAL_CALL SwXTextRange::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXTextRange::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextRange", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" + }; +} + +uno::Reference< text::XText > SAL_CALL +SwXTextRange::getText() +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_xParentText.is() && m_pImpl->m_pTableOrSectionFormat) + { + std::optional<SwPosition> oPosition; + if (m_pImpl->m_eRangePosition == RANGE_IS_TABLE) + { + SwTable const*const pTable = SwTable::FindTable( m_pImpl->m_pTableOrSectionFormat ); + SwTableNode const*const pTableNode = pTable->GetTableNode(); + oPosition.emplace(*pTableNode); + } + else + { + assert(m_pImpl->m_eRangePosition == RANGE_IS_SECTION); + auto const pSectFormat(static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat)); + oPosition.emplace(pSectFormat->GetContent().GetContentIdx()->GetNode()); + } + m_pImpl->m_xParentText = + ::sw::CreateParentXText(m_pImpl->m_rDoc, *oPosition); + } + OSL_ENSURE(m_pImpl->m_xParentText.is(), "SwXTextRange::getText: no text"); + return m_pImpl->m_xParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextRange::getStart() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRet; + ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); + if (!m_pImpl->m_xParentText.is()) + { + getText(); + } + if(pBkmk) + { + SwPaM aPam(pBkmk->GetMarkStart()); + xRet = new SwXTextRange(aPam, m_pImpl->m_xParentText); + } + else if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) + { + // start and end are this, if it's a table + xRet = this; + } + else if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition + && m_pImpl->m_pTableOrSectionFormat) + { + auto const pSectFormat(static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat)); + SwPaM aPaM(*pSectFormat->GetContent().GetContentIdx()); + aPaM.Move( fnMoveForward, GoInContent ); + assert(aPaM.GetPoint()->GetNode() < *pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode()); + xRet = new SwXTextRange(aPaM, m_pImpl->m_xParentText); + } + else + { + throw uno::RuntimeException("disposed?"); + } + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextRange::getEnd() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRet; + ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); + if (!m_pImpl->m_xParentText.is()) + { + getText(); + } + if(pBkmk) + { + SwPaM aPam(pBkmk->GetMarkEnd()); + xRet = new SwXTextRange(aPam, m_pImpl->m_xParentText); + } + else if (RANGE_IS_TABLE == m_pImpl->m_eRangePosition) + { + // start and end are this, if it's a table + xRet = this; + } + else if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition + && m_pImpl->m_pTableOrSectionFormat) + { + auto const pSectFormat(static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat)); + SwPaM aPaM(*pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode()); + aPaM.Move( fnMoveBackward, GoInContent ); + assert(*pSectFormat->GetContent().GetContentIdx() < aPaM.GetPoint()->GetNode()); + xRet = new SwXTextRange(aPaM, m_pImpl->m_xParentText); + } + else + { + throw uno::RuntimeException("disposed?"); + } + return xRet; +} + +OUString SAL_CALL SwXTextRange::getString() +{ + SolarMutexGuard aGuard; + + OUString sRet; + // for tables there is no bookmark, thus also no text + // one could export the table as ASCII here maybe? + SwPaM aPaM(GetDoc().GetNodes()); + if (GetPositions(aPaM, sw::TextRangeMode::AllowNonTextNode) && aPaM.HasMark()) + { + SwUnoCursorHelper::GetTextFromPam(aPaM, sRet); + } + return sRet; +} + +void SAL_CALL SwXTextRange::setString(const OUString& rString) +{ + SolarMutexGuard aGuard; + + DeleteAndInsert(rString, ::sw::DeleteAndInsertMode::Default); +} + +bool SwXTextRange::GetPositions(SwPaM& rToFill, ::sw::TextRangeMode const eMode) const +{ + if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition) + { + if (auto const pSectFormat = static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat)) + { + if (eMode == ::sw::TextRangeMode::AllowNonTextNode) + { + SwNodeIndex const*const pSectionNode(pSectFormat->GetContent().GetContentIdx()); + assert(pSectionNode); + assert(pSectionNode->GetNodes().IsDocNodes()); + rToFill.GetPoint()->Assign( pSectionNode->GetNode(), SwNodeOffset(1) ); + rToFill.SetMark(); + rToFill.GetMark()->Assign( *pSectionNode->GetNode().EndOfSectionNode(), SwNodeOffset(-1) ); + if (const SwContentNode* pCNd = rToFill.GetMark()->GetContentNode()) + rToFill.GetMark()->AssignEndIndex(*pCNd); + return true; + } + else + { + SwPaM aPaM(*pSectFormat->GetContent().GetContentIdx()); + aPaM.Move(fnMoveForward, GoInContent); + assert(aPaM.GetPoint()->GetNode() < *pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode()); + aPaM.SetMark(); + *aPaM.GetPoint() = SwPosition(*pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode()); + aPaM.Move(fnMoveBackward, GoInContent); + assert(*pSectFormat->GetContent().GetContentIdx() < aPaM.GetPoint()->GetNode()); + // tdf#149555 if there is no table involved, only nested + // sections, then PaM is valid + if (aPaM.GetPoint()->GetNode().FindTableNode() + == aPaM.GetMark()->GetNode().FindTableNode()) + { + rToFill = aPaM; + return true; + } + } + } + } + ::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark(); + if(pBkmk) + { + *rToFill.GetPoint() = pBkmk->GetMarkPos(); + if(pBkmk->IsExpanded()) + { + rToFill.SetMark(); + *rToFill.GetMark() = pBkmk->GetOtherMarkPos(); + } + else + { + rToFill.DeleteMark(); + } + return true; + } + return false; +} + +namespace sw { + +bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill, + const uno::Reference<text::XTextRange> & xTextRange, + ::sw::TextRangeMode const eMode) +{ + bool bRet = false; + + SwXHeadFootText* pHeadText + = eMode == TextRangeMode::AllowTableNode ? dynamic_cast<SwXHeadFootText*>(xTextRange.get()) : nullptr; + + // if it's a text then create a temporary cursor there and re-use + // the pCursor variable + // #i108489#: Reference in outside scope to keep cursor alive + rtl::Reference< SwXTextCursor > xTextCursor; + OTextCursorHelper* pCursor; + if (pHeadText) + { + // if it is a header / footer text, and eMode == TextRangeMode::AllowTableNode + // then set the cursor to the beginning of the text + // if it is started with a table then set into the table + xTextCursor = pHeadText->CreateTextCursor(true); + xTextCursor->gotoEnd(true); + pCursor = xTextCursor.get(); + pCursor->GetPaM()->Normalize(); + } + else if (SwXText* pText = dynamic_cast<SwXText*>(xTextRange.get())) + { + xTextCursor = pText->createXTextCursor(); + xTextCursor->gotoEnd(true); + pCursor = xTextCursor.get(); + } + else + { + pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + } + + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + if(pRange && &pRange->GetDoc() == &rToFill.GetDoc()) + { + bRet = pRange->GetPositions(rToFill, eMode); + } + else if (SwXParagraph* pPara = dynamic_cast<SwXParagraph*>(xTextRange.get())) + { + bRet = pPara->SelectPaM(rToFill); + } + else + { + SwDoc* pDoc = nullptr; + const SwPaM* pUnoCursor = nullptr; + if (pCursor) + { + pDoc = pCursor->GetDoc(); + pUnoCursor = pCursor->GetPaM(); + } + else if (SwXTextPortion* pPortion = dynamic_cast<SwXTextPortion*>(xTextRange.get())) + { + pDoc = &pPortion->GetCursor().GetDoc(); + pUnoCursor = &pPortion->GetCursor(); + } + if (pUnoCursor && pDoc == &rToFill.GetDoc()) + { + OSL_ENSURE(!pUnoCursor->IsMultiSelection(), + "what to do about rings?"); + bRet = true; + *rToFill.GetPoint() = *pUnoCursor->GetPoint(); + if (pUnoCursor->HasMark()) + { + rToFill.SetMark(); + *rToFill.GetMark() = *pUnoCursor->GetMark(); + } + else + rToFill.DeleteMark(); + } + } + return bRet; +} + +static bool +lcl_IsStartNodeInFormat(const bool bHeader, SwStartNode const *const pSttNode, + SwFrameFormat const*const pFrameFormat, SwFrameFormat*& rpFormat) +{ + bool bRet = false; + const SfxItemSet& rSet = pFrameFormat->GetAttrSet(); + const SfxPoolItem* pItem; + if (SfxItemState::SET == rSet.GetItemState( + bHeader ? sal_uInt16(RES_HEADER) : sal_uInt16(RES_FOOTER), + true, &pItem)) + { + SfxPoolItem *const pItemNonConst(const_cast<SfxPoolItem *>(pItem)); + SwFrameFormat *const pHeadFootFormat = bHeader ? + static_cast<SwFormatHeader*>(pItemNonConst)->GetHeaderFormat() : + static_cast<SwFormatFooter*>(pItemNonConst)->GetFooterFormat(); + if (pHeadFootFormat) + { + const SwFormatContent& rFlyContent = pHeadFootFormat->GetContent(); + // tdf#146248 avoid Undo crash at shared first page + if ( !rFlyContent.GetContentIdx() ) + return false; + const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); + SwStartNode const*const pCurSttNode = rNode.FindSttNodeByType( + bHeader ? SwHeaderStartNode : SwFooterStartNode); + if (pCurSttNode && (pCurSttNode == pSttNode)) + { + rpFormat = pHeadFootFormat; + bRet = true; + } + } + } + return bRet; +} + +} // namespace sw + +rtl::Reference< SwXTextRange > +SwXTextRange::CreateXTextRange( + SwDoc & rDoc, const SwPosition& rPos, const SwPosition *const pMark) +{ + const uno::Reference<text::XText> xParentText( + ::sw::CreateParentXText(rDoc, rPos)); + const auto pNewCursor(rDoc.CreateUnoCursor(rPos)); + if(pMark) + { + pNewCursor->SetMark(); + *pNewCursor->GetMark() = *pMark; + } + const bool isCell( dynamic_cast<SwXCell*>(xParentText.get()) ); + return new SwXTextRange(*pNewCursor, xParentText, + isCell ? RANGE_IN_CELL : RANGE_IN_TEXT); +} + +namespace sw { + +css::uno::Reference< SwXText > +CreateParentXText(SwDoc & rDoc, const SwPosition& rPos) +{ + css::uno::Reference< SwXText > xParentText; + SwStartNode* pSttNode = rPos.GetNode().StartOfSectionNode(); + while(pSttNode && pSttNode->IsSectionNode()) + { + pSttNode = pSttNode->StartOfSectionNode(); + } + SwStartNodeType eType = pSttNode ? pSttNode->GetStartNodeType() : SwNormalStartNode; + switch(eType) + { + case SwTableBoxStartNode: + { + SwTableNode const*const pTableNode = pSttNode->FindTableNode(); + SwFrameFormat *const pTableFormat = + pTableNode->GetTable().GetFrameFormat(); + SwTableBox *const pBox = pSttNode->GetTableBox(); + + xParentText = pBox + ? SwXCell::CreateXCell( pTableFormat, pBox ) + : new SwXCell( pTableFormat, *pSttNode ); + } + break; + case SwFlyStartNode: + { + SwFrameFormat *const pFormat = pSttNode->GetFlyFormat(); + if (nullptr != pFormat) + { + xParentText = SwXTextFrame::CreateXTextFrame(rDoc, pFormat); + } + } + break; + case SwHeaderStartNode: + case SwFooterStartNode: + { + const bool bHeader = (SwHeaderStartNode == eType); + const size_t nPDescCount = rDoc.GetPageDescCnt(); + for(size_t i = 0; i < nPDescCount; i++) + { + const SwPageDesc& rDesc = rDoc.GetPageDesc( i ); + + const SwFrameFormat* pFrameFormatMaster = &rDesc.GetMaster(); + const SwFrameFormat* pFrameFormatLeft = &rDesc.GetLeft(); + const SwFrameFormat* pFrameFormatFirstMaster = &rDesc.GetFirstMaster(); + const SwFrameFormat* pFrameFormatFirstLeft = &rDesc.GetFirstLeft(); + + SwFrameFormat* pHeadFootFormat = nullptr; + if (!lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatMaster, + pHeadFootFormat)) + { + if (!lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatLeft, + pHeadFootFormat)) + { + if (!lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatFirstMaster, + pHeadFootFormat)) + { + lcl_IsStartNodeInFormat(bHeader, pSttNode, pFrameFormatFirstLeft, pHeadFootFormat); + } + } + } + + if (pHeadFootFormat) + { + xParentText = SwXHeadFootText::CreateXHeadFootText( + *pHeadFootFormat, bHeader); + } + } + } + break; + case SwFootnoteStartNode: + { + const size_t nFootnoteCnt = rDoc.GetFootnoteIdxs().size(); + for (size_t n = 0; n < nFootnoteCnt; ++n ) + { + const SwTextFootnote* pTextFootnote = rDoc.GetFootnoteIdxs()[ n ]; + const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); + pTextFootnote = rFootnote.GetTextFootnote(); + + if (pSttNode == pTextFootnote->GetStartNode()->GetNode(). + FindSttNodeByType(SwFootnoteStartNode)) + { + xParentText = SwXFootnote::CreateXFootnote(rDoc, + &const_cast<SwFormatFootnote&>(rFootnote)); + break; + } + } + } + break; + default: + { + if (SwDocShell *const pDocSh = rDoc.GetDocShell()) + { + // then it is the body text + const uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel(); + const uno::Reference< text::XTextDocument > xDoc( + xModel, uno::UNO_QUERY); + xParentText = dynamic_cast<SwXText*>(xDoc->getText().get()); + } + } + } + OSL_ENSURE(xParentText.is(), "no parent text?"); + return xParentText; +} + +} // namespace sw + +uno::Reference< container::XEnumeration > SAL_CALL +SwXTextRange::createContentEnumeration(const OUString& rServiceName) +{ + SolarMutexGuard g; + + if ( rServiceName != "com.sun.star.text.TextContent" ) + { + throw uno::RuntimeException("unsupported service"); + } + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); + const auto pNewCursor(m_pImpl->m_rDoc.CreateUnoCursor(aPos)); + if (!GetPositions(*pNewCursor)) + { + throw uno::RuntimeException("range has no positions"); + } + + return SwXParaFrameEnumeration::Create(*pNewCursor, PARAFRAME_PORTION_TEXTRANGE); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXTextRange::createEnumeration() +{ + SolarMutexGuard g; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); + auto pNewCursor(m_pImpl->m_rDoc.CreateUnoCursor(aPos)); + if (!GetPositions(*pNewCursor)) + { + throw uno::RuntimeException("range has no positions"); + } + if (!m_pImpl->m_xParentText.is()) + { + getText(); + } + + const CursorType eSetType = (RANGE_IN_CELL == m_pImpl->m_eRangePosition) + ? CursorType::SelectionInTable : CursorType::Selection; + return SwXParagraphEnumeration::Create(m_pImpl->m_xParentText, pNewCursor, eSetType); +} + +uno::Type SAL_CALL SwXTextRange::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXTextRange::hasElements() +{ + return true; +} + +uno::Sequence< OUString > SAL_CALL +SwXTextRange::getAvailableServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; + return aRet; +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXTextRange::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + + static uno::Reference< beans::XPropertySetInfo > xRef = + m_pImpl->m_rPropSet.getPropertySetInfo(); + return xRef; +} + +void SAL_CALL +SwXTextRange::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + SwUnoCursorHelper::SetPropertyValue(aPaM, m_pImpl->m_rPropSet, + rPropertyName, rValue); +} + +uno::Any SAL_CALL +SwXTextRange::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + return SwUnoCursorHelper::GetPropertyValue(aPaM, m_pImpl->m_rPropSet, + rPropertyName); +} + +void SAL_CALL +SwXTextRange::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextRange::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextRange::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextRange::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextRange::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextRange::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextRange::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextRange::removeVetoableChangeListener(): not implemented"); +} + +beans::PropertyState SAL_CALL +SwXTextRange::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + return SwUnoCursorHelper::GetPropertyState(aPaM, m_pImpl->m_rPropSet, + rPropertyName); +} + +uno::Sequence< beans::PropertyState > SAL_CALL +SwXTextRange::getPropertyStates(const uno::Sequence< OUString >& rPropertyName) +{ + SolarMutexGuard g; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + return SwUnoCursorHelper::GetPropertyStates(aPaM, m_pImpl->m_rPropSet, + rPropertyName); +} + +void SAL_CALL SwXTextRange::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + SwUnoCursorHelper::SetPropertyToDefault(aPaM, m_pImpl->m_rPropSet, + rPropertyName); +} + +uno::Any SAL_CALL +SwXTextRange::getPropertyDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + GetPositions(aPaM); + return SwUnoCursorHelper::GetPropertyDefault(aPaM, m_pImpl->m_rPropSet, + rPropertyName); +} + +void SAL_CALL +SwXTextRange::makeRedline( + const OUString& rRedlineType, + const uno::Sequence< beans::PropertyValue >& rRedlineProperties ) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->GetBookmark()) + { + throw uno::RuntimeException("range has no mark (table?)"); + } + SwPaM aPaM(GetDoc().GetNodes()); + SwXTextRange::GetPositions(aPaM); + SwUnoCursorHelper::makeRedline( aPaM, rRedlineType, rRedlineProperties ); +} + +namespace { + +struct SwXTextRangesImpl final : public SwXTextRanges +{ + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return "SwXTextRanges"; }; + virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName) override + { return cppu::supportsService(this, rServiceName); }; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { return { "com.sun.star.text.TextRanges" }; }; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override + { return cppu::UnoType<text::XTextRange>::get(); }; + virtual sal_Bool SAL_CALL hasElements() override + { return getCount() > 0; }; + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override; + + explicit SwXTextRangesImpl(SwPaM *const pPaM) + { + if (pPaM) + { + m_pUnoCursor.reset(pPaM->GetDoc().CreateUnoCursor(*pPaM->GetPoint())); + ::sw::DeepCopyPaM(*pPaM, *GetCursor()); + } + MakeRanges(); + } + virtual void SAL_CALL release() noexcept override + { + SolarMutexGuard g; + OWeakObject::release(); + } + virtual SwUnoCursor* GetCursor() override + { return &(*m_pUnoCursor); }; + void MakeRanges(); + std::vector< rtl::Reference<SwXTextRange> > m_Ranges; + sw::UnoCursorPointer m_pUnoCursor; +}; + +} + +void SwXTextRangesImpl::MakeRanges() +{ + if (!GetCursor()) + return; + + for(SwPaM& rTmpCursor : GetCursor()->GetRingContainer()) + { + const rtl::Reference<SwXTextRange> xRange( + SwXTextRange::CreateXTextRange( + rTmpCursor.GetDoc(), + *rTmpCursor.GetPoint(), rTmpCursor.GetMark())); + if (xRange.is()) + { + m_Ranges.push_back(xRange); + } + } +} + +rtl::Reference<SwXTextRanges> SwXTextRanges::Create(SwPaM *const pPaM) + { return new SwXTextRangesImpl(pPaM); } + +/* + * Text positions + * Up to the first access to a text position, only a SwCursor is stored. + * Afterwards, an array with uno::Reference<XTextPosition> will be created. + */ + +sal_Int32 SAL_CALL SwXTextRangesImpl::getCount() +{ + SolarMutexGuard aGuard; + return static_cast<sal_Int32>(m_Ranges.size()); +} + +uno::Any SAL_CALL SwXTextRangesImpl::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= m_Ranges.size())) + throw lang::IndexOutOfBoundsException(); + uno::Any ret(uno::Reference<text::XTextRange>(m_Ranges.at(nIndex))); + return ret; +} + +void SwUnoCursorHelper::SetString(SwCursor & rCursor, std::u16string_view aString) +{ + // Start/EndAction + SwDoc& rDoc = rCursor.GetDoc(); + UnoActionContext aAction(&rDoc); + rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + if (rCursor.HasMark()) + { + rDoc.getIDocumentContentOperations().DeleteAndJoin(rCursor); + } + if (!aString.empty()) + { + const bool bSuccess( SwUnoCursorHelper::DocInsertStringSplitCR( + rDoc, rCursor, aString, false ) ); + OSL_ENSURE( bSuccess, "DocInsertStringSplitCR" ); + SwUnoCursorHelper::SelectPam(rCursor, true); + rCursor.Left(aString.size()); + } + rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); +} + +namespace { + +struct SwXParaFrameEnumerationImpl final : public SwXParaFrameEnumeration +{ + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return "SwXParaFrameEnumeration"; }; + virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override + { return cppu::supportsService(this, rServiceName); }; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { return {"com.sun.star.util.ContentEnumeration"}; }; + + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual css::uno::Any SAL_CALL nextElement() override; + + SwXParaFrameEnumerationImpl(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat); + virtual void SAL_CALL release() noexcept override + { + SolarMutexGuard g; + OWeakObject::release(); + } + SwUnoCursor& GetCursor() + { return *m_pUnoCursor; } + void PurgeFrameClients() + { + if(!m_pUnoCursor) + { + m_vFrames.clear(); + m_xNextObject = nullptr; + } + else + { + // removing orphaned Clients + std::erase_if(m_vFrames, + [] (std::unique_ptr<sw::FrameClient>& rEntry) -> bool { return !rEntry->GetRegisteredIn(); }); + } + } + void FillFrame(); + bool CreateNextObject(); + uno::Reference< text::XTextContent > m_xNextObject; + std::deque< std::unique_ptr<sw::FrameClient> > m_vFrames; + ::sw::UnoCursorPointer m_pUnoCursor; +}; + +} + +rtl::Reference<SwXParaFrameEnumeration> SwXParaFrameEnumeration::Create(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat) + { return new SwXParaFrameEnumerationImpl(rPaM, eParaFrameMode, pFormat); } + +SwXParaFrameEnumerationImpl::SwXParaFrameEnumerationImpl( + const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, + SwFrameFormat* const pFormat) + : m_pUnoCursor(rPaM.GetDoc().CreateUnoCursor(*rPaM.GetPoint())) +{ + if (rPaM.HasMark()) + { + GetCursor().SetMark(); + *GetCursor().GetMark() = *rPaM.GetMark(); + } + if (PARAFRAME_PORTION_PARAGRAPH == eParaFrameMode) + { + FrameClientSortList_t vFrames; + ::CollectFrameAtNode(rPaM.GetPoint()->GetNode(), vFrames, false); + std::transform(vFrames.begin(), vFrames.end(), + std::back_inserter(m_vFrames), + [] (FrameClientSortListEntry& rEntry) { return std::move(rEntry.pFrameClient); }); + } + else if (pFormat) + { + m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFormat)); + } + else if ((PARAFRAME_PORTION_CHAR == eParaFrameMode) || + (PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode)) + { + if (PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode) + { + //get all frames that are bound at paragraph or at character + for(const SwPosFlyFrame& rFlyFrame : rPaM.GetDoc().GetAllFlyFormats(&GetCursor(), false, true)) + { + const auto pFrameFormat = const_cast<SwFrameFormat*>(&rFlyFrame.GetFormat()); + m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFrameFormat)); + } + } + FillFrame(); + } +} + +// Search for a FLYCNT text attribute at the cursor point and fill the frame +// into the array +void SwXParaFrameEnumerationImpl::FillFrame() +{ + if(!m_pUnoCursor->GetPointNode().IsTextNode()) + return; + // search for objects at the cursor - anchored at/as char + const auto pTextAttr = m_pUnoCursor->GetPointNode().GetTextNode()->GetTextAttrForCharAt( + m_pUnoCursor->GetPoint()->GetContentIndex(), RES_TXTATR_FLYCNT); + if(!pTextAttr) + return; + const SwFormatFlyCnt& rFlyCnt = pTextAttr->GetFlyCnt(); + SwFrameFormat* const pFrameFormat = rFlyCnt.GetFrameFormat(); + m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFrameFormat)); +} + +bool SwXParaFrameEnumerationImpl::CreateNextObject() +{ + if (m_vFrames.empty()) + return false; + + m_xNextObject.set(FrameClientToXTextContent(m_vFrames.front().get())); + m_vFrames.pop_front(); + return m_xNextObject.is(); +} + +uno::Reference<text::XTextContent> FrameClientToXTextContent(sw::FrameClient* pClient) +{ + assert(pClient); + + uno::Reference<text::XTextContent> xRet; + SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>(pClient->GetRegisteredIn()); + // the format should be valid here, otherwise the client + // would have been removed by PurgeFrameClients + // check for a shape first + if(pFormat->Which() == RES_DRAWFRMFMT) + { + SdrObject* pObject(nullptr); + pFormat->CallSwClientNotify(sw::FindSdrObjectHint(pObject)); + if(pObject) + xRet.set(pObject->getUnoShape(), uno::UNO_QUERY); + } + else + { + const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); + OSL_ENSURE(pIdx, "where is the index?"); + SwNode const* const pNd = pIdx->GetNodes()[pIdx->GetIndex() + 1]; + + if (!pNd->IsNoTextNode()) + { + xRet = static_cast<SwXFrame*>(SwXTextFrame::CreateXTextFrame( + *pFormat->GetDoc(), pFormat).get()); + } + else if (pNd->IsGrfNode()) + { + xRet.set(SwXTextGraphicObject::CreateXTextGraphicObject( + *pFormat->GetDoc(), pFormat)); + } + else + { + assert(pNd->IsOLENode()); + xRet.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + *pFormat->GetDoc(), pFormat)); + } + } + return xRet; +} + +sal_Bool SAL_CALL +SwXParaFrameEnumerationImpl::hasMoreElements() +{ + SolarMutexGuard aGuard; + PurgeFrameClients(); + return m_xNextObject.is() || CreateNextObject(); +} + +uno::Any SAL_CALL SwXParaFrameEnumerationImpl::nextElement() +{ + SolarMutexGuard aGuard; + PurgeFrameClients(); + if (!m_xNextObject.is() && !m_vFrames.empty()) + CreateNextObject(); + if (!m_xNextObject.is()) + throw container::NoSuchElementException(); + uno::Any aRet; + aRet <<= m_xNextObject; + m_xNextObject = nullptr; + return aRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoparagraph.cxx b/sw/source/core/unocore/unoparagraph.cxx new file mode 100644 index 0000000000..dab5270588 --- /dev/null +++ b/sw/source/core/unocore/unoparagraph.cxx @@ -0,0 +1,1457 @@ +/* -*- 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 <unoparagraph.hxx> + +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> + +#include <cmdid.h> +#include <fmtautofmt.hxx> +#include <unomid.h> +#include <unoparaframeenum.hxx> +#include <unotext.hxx> +#include <unotextrange.hxx> +#include <unoport.hxx> +#include <unomap.hxx> +#include <unocrsr.hxx> +#include <unoprnms.hxx> +#include <unocrsrhelper.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <algorithm> +#include <utility> +#include <vcl/svapp.hxx> +#include <docsh.hxx> +#include <swunohelper.hxx> + +#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp> +#include <com/sun/star/beans/GetPropertyTolerantResult.hpp> +#include <com/sun/star/beans/TolerantPropertySetResultType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> + +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <editeng/unoipset.hxx> +#include <svl/listener.hxx> +#include <svx/unobrushitemhelper.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbstit.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SwParaSelection +{ + SwCursor & m_rCursor; +public: + explicit SwParaSelection(SwCursor & rCursor); + ~SwParaSelection(); +}; + +} + +SwParaSelection::SwParaSelection(SwCursor & rCursor) + : m_rCursor(rCursor) +{ + if (m_rCursor.HasMark()) + { + m_rCursor.DeleteMark(); + } + // is it at the start? + if (m_rCursor.GetPoint()->GetContentIndex() != 0) + { + m_rCursor.MovePara(GoCurrPara, fnParaStart); + } + // or at the end already? + if (m_rCursor.GetPoint()->GetContentIndex() != m_rCursor.GetPointContentNode()->Len()) + { + m_rCursor.SetMark(); + m_rCursor.MovePara(GoCurrPara, fnParaEnd); + } +} + +SwParaSelection::~SwParaSelection() +{ + if (m_rCursor.GetPoint()->GetContentIndex() != 0) + { + m_rCursor.DeleteMark(); + m_rCursor.MovePara(GoCurrPara, fnParaStart); + } +} + +/// @throws beans::UnknownPropertyException +/// @throws uno::RuntimeException +static beans::PropertyState lcl_SwXParagraph_getPropertyState( + const SwTextNode& rTextNode, + const SwAttrSet** ppSet, + const SfxItemPropertyMapEntry& rEntry, + bool &rAttrSetFetched ); + +class SwXParagraph::Impl + : public SvtListener +{ +public: + SwXParagraph& m_rThis; + unotools::WeakReference<SwXParagraph> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + SfxItemPropertySet const& m_rPropSet; + bool m_bIsDescriptor; + sal_Int32 m_nSelectionStartPos; + sal_Int32 m_nSelectionEndPos; + OUString m_sText; + css::uno::Reference<SwXText> m_xParentText; + SwTextNode* m_pTextNode; + + Impl(SwXParagraph& rThis, + SwTextNode* const pTextNode = nullptr, css::uno::Reference<SwXText> xParent = nullptr, + const sal_Int32 nSelStart = -1, const sal_Int32 nSelEnd = -1) + : m_rThis(rThis) + , m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH)) + , m_bIsDescriptor(nullptr == pTextNode) + , m_nSelectionStartPos(nSelStart) + , m_nSelectionEndPos(nSelEnd) + , m_xParentText(std::move(xParent)) + , m_pTextNode(pTextNode) + { + m_pTextNode && StartListening(m_pTextNode->GetNotifier()); + } + + SwTextNode* GetTextNode() { + return m_pTextNode; + } + + SwTextNode& GetTextNodeOrThrow() { + if (!m_pTextNode) { + throw uno::RuntimeException("SwXParagraph: disposed or invalid", nullptr); + } + return *m_pTextNode; + } + + bool IsDescriptor() const { return m_bIsDescriptor; } + + /// @throws beans::UnknownPropertyException + /// @throws beans::PropertyVetoException + /// @throws lang::IllegalArgumentException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + void SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues); + + /// @throws beans::UnknownPropertyException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + uno::Sequence< uno::Any > + GetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames); + + /// @throws uno::RuntimeException + void GetSinglePropertyValue_Impl( + const SfxItemPropertyMapEntry& rEntry, + const SfxItemSet& rSet, + uno::Any& rAny ) const; + + /// @throws uno::RuntimeException + uno::Sequence< beans::GetDirectPropertyTolerantResult > + GetPropertyValuesTolerant_Impl( + const uno::Sequence< OUString >& rPropertyNames, + bool bDirectValuesOnly); +protected: + virtual void Notify(const SfxHint& rHint) override; + +}; + +void SwXParagraph::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pTextNode = nullptr; + std::unique_lock aGuard(m_Mutex); + if (m_EventListeners.getLength(aGuard) != 0) + { + // fdo#72695: if UNO object is already dead, don't revive it with event + // The specific pattern we are guarding against is this: + // [1] Thread1 takes the SolarMutex + // [2] Thread2 decrements the SwXParagraph reference count, and calls the + // SwXParagraph destructor, which tries to take the SolarMutex, and blocks + // [3] Thread1 destroys a SwTextNode, which calls this Notify event, which results + // in a double-free if we construct the xThis object. + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + m_EventListeners.disposeAndClear(aGuard, ev); + } + } +} + +SwXParagraph::SwXParagraph() + : m_pImpl( new SwXParagraph::Impl(*this) ) +{ +} + +SwXParagraph::SwXParagraph( + css::uno::Reference< SwXText > const & xParent, + SwTextNode & rTextNode, + const sal_Int32 nSelStart, const sal_Int32 nSelEnd) + : m_pImpl( + new SwXParagraph::Impl(*this, &rTextNode, xParent, nSelStart, nSelEnd)) +{ +} + +SwXParagraph::~SwXParagraph() +{ +} + +const SwTextNode * SwXParagraph::GetTextNode() const +{ + return m_pImpl->GetTextNode(); +} + +bool SwXParagraph::IsDescriptor() const +{ + return m_pImpl->IsDescriptor(); +} + +rtl::Reference<SwXParagraph> +SwXParagraph::CreateXParagraph(SwDoc & rDoc, SwTextNode *const pTextNode, + css::uno::Reference< SwXText> const& i_xParent, + const sal_Int32 nSelStart, const sal_Int32 nSelEnd) +{ + // re-use existing SwXParagraph + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXParagraph> xParagraph; + if (pTextNode && (-1 == nSelStart) && (-1 == nSelEnd)) + { // only use cache if no selection! + xParagraph = pTextNode->GetXParagraph(); + } + if (xParagraph.is()) + { + return xParagraph; + } + + // create new SwXParagraph + css::uno::Reference<SwXText> xParentText(i_xParent); + if (!xParentText.is() && pTextNode) + { + SwPosition Pos(*pTextNode); + xParentText = ::sw::CreateParentXText( rDoc, Pos ); + } + SwXParagraph *const pXPara( pTextNode + ? new SwXParagraph(xParentText, *pTextNode, nSelStart, nSelEnd) + : new SwXParagraph); + // this is why the constructor is private: need to acquire pXPara here + xParagraph.set(pXPara); + // in order to initialize the weak pointer cache in the core object + if (pTextNode && (-1 == nSelStart) && (-1 == nSelEnd)) + { + pTextNode->SetXParagraph(xParagraph); + } + // need a permanent Reference to initialize m_wThis + pXPara->m_pImpl->m_wThis = xParagraph.get(); + return xParagraph; +} + +bool SwXParagraph::SelectPaM(SwPaM & rPaM) +{ + SwTextNode const*const pTextNode( GetTextNode() ); + + if (!pTextNode) + { + return false; + } + + rPaM.GetPoint()->Assign( *pTextNode ); + // set selection to the whole paragraph + rPaM.SetMark(); + rPaM.GetMark()->SetContent( pTextNode->GetText().getLength() ); + return true; +} + +OUString SAL_CALL +SwXParagraph::getImplementationName() +{ + return "SwXParagraph"; +} + +sal_Bool SAL_CALL +SwXParagraph::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXParagraph::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.Paragraph", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" + }; +} + +void +SwXParagraph::attachToText(SwXText & rParent, SwTextNode & rTextNode) +{ + OSL_ENSURE(m_pImpl->m_bIsDescriptor, "Paragraph is not a descriptor"); + if (!m_pImpl->m_bIsDescriptor) + return; + + m_pImpl->m_bIsDescriptor = false; + m_pImpl->EndListeningAll(); + m_pImpl->StartListening(rTextNode.GetNotifier()); + rTextNode.SetXParagraph(this); + m_pImpl->m_xParentText = &rParent; + if (!m_pImpl->m_sText.isEmpty()) + { + try { setString(m_pImpl->m_sText); } + catch(...){} + m_pImpl->m_sText.clear(); + } +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXParagraph::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef = + m_pImpl->m_rPropSet.getPropertySetInfo(); + return xRef; +} + +void SAL_CALL +SwXParagraph::setPropertyValue(const OUString& rPropertyName, + const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + m_pImpl->SetPropertyValues_Impl( { rPropertyName }, { rValue } ); +} + +uno::Any +SwXParagraph::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Sequence<OUString> aPropertyNames { rPropertyName }; + const uno::Sequence< uno::Any > aRet = + m_pImpl->GetPropertyValues_Impl(aPropertyNames); + return aRet.getConstArray()[0]; +} + +void SwXParagraph::Impl::SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + + uno::Sequence< beans::PropertyValue > aValues( rPropertyNames.getLength() ); + std::transform( + rPropertyNames.begin(), rPropertyNames.end(), rValues.begin(), aValues.getArray(), + [&rMap = m_rPropSet.getPropertyMap(), this](const OUString& name, const uno::Any& value) + { + if (SfxItemPropertyMapEntry const* const pEntry = rMap.getByName(name); !pEntry) + { + throw beans::UnknownPropertyException("Unknown property: " + name, + m_rThis.getXWeak()); + } + else if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException("Property is read-only: " + name, + m_rThis.getXWeak()); + } + return comphelper::makePropertyValue(name, value); + }); + SwUnoCursorHelper::SetPropertyValues(aCursor, m_rPropSet, aValues); +} + +void SAL_CALL SwXParagraph::setPropertyValues( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + if (rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException("lengths do not match", + getXWeak(), -1); + + SolarMutexGuard aGuard; + + // workaround for bad designed API + try + { + m_pImpl->SetPropertyValues_Impl( rPropertyNames, rValues ); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a lang::WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +// Support for DrawingLayer FillStyles for GetPropertyValue() usages +void SwXParagraph::Impl::GetSinglePropertyValue_Impl( + const SfxItemPropertyMapEntry& rEntry, + const SfxItemSet& rSet, + uno::Any& rAny ) const +{ + bool bDone(false); + + switch(rEntry.nWID) + { + case RES_BACKGROUND: + { + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND)); + + if(!aOriginalBrushItem->QueryValue(rAny, rEntry.nMemberId)) + { + OSL_ENSURE(false, "Error getting attribute from RES_BACKGROUND (!)"); + } + + bDone = true; + break; + } + case OWN_ATTR_FILLBMP_MODE: + { + if (rSet.Get(XATTR_FILLBMP_TILE).GetValue()) + { + rAny <<= drawing::BitmapMode_REPEAT; + } + else if (rSet.Get(XATTR_FILLBMP_STRETCH).GetValue()) + { + rAny <<= drawing::BitmapMode_STRETCH; + } + else + { + rAny <<= drawing::BitmapMode_NO_REPEAT; + } + + bDone = true; + break; + } + default: break; + } + + if(bDone) + return; + + // fallback to standard get value implementation used before this helper was created + m_rPropSet.getPropertyValue(rEntry, rSet, rAny); + + if(rEntry.aType == cppu::UnoType<sal_Int16>::get() && rEntry.aType != rAny.getValueType()) + { + // since the sfx uInt16 item now exports a sal_Int32, we may have to fix this here + sal_Int32 nValue(0); + + if (rAny >>= nValue) + { + rAny <<= static_cast<sal_Int16>(nValue); + } + } + + // check for needed metric translation + if(!(rEntry.nMoreFlags & PropertyMoreFlags::METRIC_ITEM)) + return; + + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == rEntry.nWID || XATTR_FILLBMP_SIZEY == rEntry.nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(rAny >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const MapUnit eMapUnit(rSet.GetPool()->GetMetric(rEntry.nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertToMM(eMapUnit, rAny); + } + } +} + +uno::Sequence< uno::Any > SwXParagraph::Impl::GetPropertyValues_Impl( + const uno::Sequence< OUString > & rPropertyNames ) +{ + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + uno::Sequence< uno::Any > aValues(rPropertyNames.getLength()); + SwPaM aPam( rTextNode ); + uno::Any* pValues = aValues.getArray(); + const OUString* pPropertyNames = rPropertyNames.getConstArray(); + const SfxItemPropertyMap &rMap = m_rPropSet.getPropertyMap(); + const SwAttrSet& rAttrSet( rTextNode.GetSwAttrSet() ); + for (sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); nProp++) + { + if (pPropertyNames[nProp] == "ParaMarkerAutoStyleSpan") + { + // A hack to tunnel the fake text span to ODF export + // see XMLTextParagraphExport::exportParagraph + if (rTextNode.GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle()) + { + SwUnoCursor aEndCursor(*aPam.GetMark()); + css::uno::Reference<css::beans::XPropertySet> xFakeSpan( + new SwXTextPortion(&aEndCursor, {}, PORTION_LIST_AUTOFMT)); + pValues[nProp] <<= xFakeSpan; + } + continue; + } + + if (pPropertyNames[nProp] == "ODFExport_NodeIndex") + { + // A hack to avoid writing random list ids to ODF when they are not referred later + // see XMLTextParagraphExport::DocumentListNodes::ShouldSkipListId + pValues[nProp] <<= rTextNode.GetIndex().get(); + continue; + } + + if (pPropertyNames[nProp] == "OOXMLImport_AnchoredShapes") + { + // A hack to provide list of anchored objects fast + // See reanchorObjects in writerfilter/source/dmapper/DomainMapper_Impl.cxx + FrameClientSortList_t aFrames; + CollectFrameAtNode(rTextNode, aFrames, false); // Frames anchored to paragraph + CollectFrameAtNode(rTextNode, aFrames, true); // Frames anchored to character + std::vector<uno::Reference<text::XTextContent>> aRet; + aRet.reserve(aFrames.size()); + for (const auto& rFrame : aFrames) + if (auto xContent = FrameClientToXTextContent(rFrame.pFrameClient.get())) + aRet.push_back(xContent); + + pValues[nProp] <<= comphelper::containerToSequence(aRet); + continue; + } + + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName( pPropertyNames[nProp] ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + pPropertyNames[nProp], + m_rThis.getXWeak()); + } + if (! ::sw::GetDefaultTextContentValue( + pValues[nProp], pPropertyNames[nProp], pEntry->nWID)) + { + beans::PropertyState eTemp; + const bool bDone = SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, aPam, &(pValues[nProp]), eTemp, &rTextNode ); + if (!bDone) + { + GetSinglePropertyValue_Impl(*pEntry, rAttrSet, pValues[nProp]); + } + } + } + return aValues; +} + +uno::Sequence< uno::Any > SAL_CALL +SwXParagraph::getPropertyValues(const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Any > aValues; + + // workaround for bad designed API + try + { + aValues = m_pImpl->GetPropertyValues_Impl( rPropertyNames ); + } + catch (beans::UnknownPropertyException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch (lang::WrappedTargetException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + + return aValues; +} + +void SAL_CALL SwXParagraph::addPropertiesChangeListener( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::addPropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXParagraph::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::removePropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXParagraph::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::firePropertiesChangeEvent(): not implemented"); +} + +/* disabled for #i46921# */ + +uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL +SwXParagraph::setPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SolarMutexGuard aGuard; + + if (rPropertyNames.getLength() != rValues.getLength()) + { + throw lang::IllegalArgumentException(); + } + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + //SwNode& rTextNode = pUnoCursor->GetPoint()->GetNode(); + //const SwAttrSet& rAttrSet = static_cast<SwTextNode&>(rTextNode).GetSwAttrSet(); + //sal_uInt16 nAttrCount = rAttrSet.Count(); + + const sal_Int32 nProps = rPropertyNames.getLength(); + const OUString *pProp = rPropertyNames.getConstArray(); + + //sal_Int32 nVals = rValues.getLength(); + const uno::Any *pValue = rValues.getConstArray(); + + sal_Int32 nFailed = 0; + uno::Sequence< beans::SetPropertyTolerantFailed > aFailed( nProps ); + beans::SetPropertyTolerantFailed *pFailed = aFailed.getArray(); + + // get entry to start with + const SfxItemPropertyMap &rPropMap = + m_pImpl->m_rPropSet.getPropertyMap(); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + for (sal_Int32 i = 0; i < nProps; ++i) + { + try + { + pFailed[ nFailed ].Name = pProp[i]; + + SfxItemPropertyMapEntry const*const pEntry = + rPropMap.getByName( pProp[i] ); + if (!pEntry) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + else + { + // set property value + // (compare to SwXParagraph::setPropertyValues) + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + else + { + SwUnoCursorHelper::SetPropertyValue( + aCursor, m_pImpl->m_rPropSet, pProp[i], pValue[i]); + } + } + } + catch (beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (lang::IllegalArgumentException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (beans::PropertyVetoException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (lang::WrappedTargetException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + + aFailed.realloc( nFailed ); + return aFailed; +} + +uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL +SwXParagraph::getPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + + const uno::Sequence< beans::GetDirectPropertyTolerantResult > aTmpRes( + m_pImpl->GetPropertyValuesTolerant_Impl( rPropertyNames, false ) ); + + // copy temporary result to final result type + const sal_Int32 nLen = aTmpRes.getLength(); + uno::Sequence< beans::GetPropertyTolerantResult > aRes( nLen ); + std::copy(aTmpRes.begin(), aTmpRes.end(), aRes.getArray()); + return aRes; +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL +SwXParagraph::getDirectPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + + return m_pImpl->GetPropertyValuesTolerant_Impl( rPropertyNames, true ); +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > +SwXParagraph::Impl::GetPropertyValuesTolerant_Impl( + const uno::Sequence< OUString >& rPropertyNames, + bool bDirectValuesOnly ) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + // #i46786# Use SwAttrSet pointer for determining the state. + // Use the value SwAttrSet (from the paragraph OR the style) + // for determining the actual value(s). + const SwAttrSet* pAttrSet = rTextNode.GetpSwAttrSet(); + const SwAttrSet& rValueAttrSet = rTextNode.GetSwAttrSet(); + + sal_Int32 nProps = rPropertyNames.getLength(); + + uno::Sequence< beans::GetDirectPropertyTolerantResult > aResult( nProps ); + beans::GetDirectPropertyTolerantResult *pResult = aResult.getArray(); + sal_Int32 nIdx = 0; + + // get entry to start with + const SfxItemPropertyMap &rPropMap = m_rPropSet.getPropertyMap(); + + for (const OUString& rProp : rPropertyNames) + { + OSL_ENSURE( nIdx < nProps, "index out of bounds" ); + beans::GetDirectPropertyTolerantResult &rResult = pResult[nIdx]; + + try + { + rResult.Name = rProp; + + SfxItemPropertyMapEntry const*const pEntry = + rPropMap.getByName( rProp ); + if (!pEntry) // property available? + { + rResult.Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + else + { + // get property state + // (compare to SwXParagraph::getPropertyState) + bool bAttrSetFetched = true; + beans::PropertyState eState = lcl_SwXParagraph_getPropertyState( + rTextNode, &pAttrSet, *pEntry, bAttrSetFetched ); + rResult.State = eState; + + rResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_FAILURE; + if (!bDirectValuesOnly || + (beans::PropertyState_DIRECT_VALUE == eState)) + { + // get property value + // (compare to SwXParagraph::getPropertyValue(s)) + uno::Any aValue; + if (! ::sw::GetDefaultTextContentValue( + aValue, rProp, pEntry->nWID ) ) + { + SwPaM aPam( rTextNode ); + // handle properties that are not part of the attribute + // and thus only pretended to be paragraph attributes + beans::PropertyState eTemp; + const bool bDone = + SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, aPam, &aValue, eTemp, &rTextNode ); + + // if not found try the real paragraph attributes... + if (!bDone) + { + GetSinglePropertyValue_Impl(*pEntry, rValueAttrSet, aValue); + } + } + + rResult.Value = aValue; + rResult.Result = beans::TolerantPropertySetResultType::SUCCESS; + + nIdx++; + } + // this assertion should never occur! + OSL_ENSURE( nIdx < 1 || pResult[nIdx - 1].Result != beans::TolerantPropertySetResultType::UNKNOWN_FAILURE, + "unknown failure while retrieving property" ); + + } + } + catch (beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + rResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (lang::IllegalArgumentException &) + { + rResult.Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (beans::PropertyVetoException &) + { + rResult.Result = beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (lang::WrappedTargetException &) + { + rResult.Result = beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + + // resize to actually used size + aResult.realloc( nIdx ); + + return aResult; +} + +bool ::sw::GetDefaultTextContentValue( + uno::Any& rAny, std::u16string_view rPropertyName, sal_uInt16 nWID) +{ + if(!nWID) + { + if(rPropertyName == UNO_NAME_ANCHOR_TYPE) + nWID = FN_UNO_ANCHOR_TYPE; + else if(rPropertyName == UNO_NAME_ANCHOR_TYPES) + nWID = FN_UNO_ANCHOR_TYPES; + else if(rPropertyName == UNO_NAME_TEXT_WRAP) + nWID = FN_UNO_TEXT_WRAP; + else + return false; + } + + switch(nWID) + { + case FN_UNO_TEXT_WRAP: rAny <<= text::WrapTextMode_NONE; break; + case FN_UNO_ANCHOR_TYPE: rAny <<= text::TextContentAnchorType_AT_PARAGRAPH; break; + case FN_UNO_ANCHOR_TYPES: + { uno::Sequence<text::TextContentAnchorType> aTypes { text::TextContentAnchorType_AT_PARAGRAPH }; + rAny <<= aTypes; + } + break; + default: + return false; + } + return true; +} + +void SAL_CALL +SwXParagraph::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::removeVetoableChangeListener(): not implemented"); +} + +static beans::PropertyState lcl_SwXParagraph_getPropertyState( + const SwTextNode& rTextNode, + const SwAttrSet** ppSet, + const SfxItemPropertyMapEntry& rEntry, + bool &rAttrSetFetched) +{ + beans::PropertyState eRet(beans::PropertyState_DEFAULT_VALUE); + + if(!(*ppSet) && !rAttrSetFetched) + { + (*ppSet) = rTextNode.GetpSwAttrSet(); + rAttrSetFetched = true; + } + + SwPosition aPos(rTextNode); + SwPaM aPam(aPos); + bool bDone(false); + + switch(rEntry.nWID) + { + case FN_UNO_NUM_RULES: + { + // if numbering is set, return it; else do nothing + SwUnoCursorHelper::getNumberingProperty(aPam,eRet,nullptr); + bDone = true; + break; + } + case FN_UNO_ANCHOR_TYPES: + { + bDone = true; + break; + } + case RES_ANCHOR: + { + bDone = (MID_SURROUND_SURROUNDTYPE == rEntry.nMemberId); + break; + } + case RES_SURROUND: + { + bDone = (MID_ANCHOR_ANCHORTYPE == rEntry.nMemberId); + break; + } + case FN_UNO_PARA_STYLE: + case FN_UNO_PARA_CONDITIONAL_STYLE_NAME: + { + SwFormatColl* pFormat = SwUnoCursorHelper::GetCurTextFormatColl(aPam,rEntry.nWID == FN_UNO_PARA_CONDITIONAL_STYLE_NAME); + eRet = pFormat ? beans::PropertyState_DIRECT_VALUE : beans::PropertyState_AMBIGUOUS_VALUE; + bDone = true; + break; + } + case FN_UNO_PAGE_STYLE: + { + OUString sVal; + SwUnoCursorHelper::GetCurPageStyle( aPam, sVal ); + eRet = !sVal.isEmpty() ? beans::PropertyState_DIRECT_VALUE + : beans::PropertyState_AMBIGUOUS_VALUE; + bDone = true; + break; + } + + // DrawingLayer PropertyStyle support + case OWN_ATTR_FILLBMP_MODE: + { + if(*ppSet) + { + if(SfxItemState::SET == (*ppSet)->GetItemState(XATTR_FILLBMP_STRETCH, false) + || SfxItemState::SET == (*ppSet)->GetItemState(XATTR_FILLBMP_TILE, false)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + else + { + eRet = beans::PropertyState_AMBIGUOUS_VALUE; + } + + bDone = true; + } + break; + } + case RES_BACKGROUND: + { + if(*ppSet) + { + if (SWUnoHelper::needToMapFillItemsToSvxBrushItemTypes(**ppSet, + rEntry.nMemberId)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + bDone = true; + } + break; + } + } + + if(!bDone) + { + if((*ppSet) && SfxItemState::SET == (*ppSet)->GetItemState(rEntry.nWID, false)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + } + + return eRet; +} + +beans::PropertyState SAL_CALL +SwXParagraph::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + const SwAttrSet* pSet = nullptr; + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + bool bDummy = false; + const beans::PropertyState eRet = + lcl_SwXParagraph_getPropertyState(rTextNode, &pSet, *pEntry, bDummy); + return eRet; +} + +uno::Sequence< beans::PropertyState > SAL_CALL +SwXParagraph::getPropertyStates( + const uno::Sequence< OUString >& PropertyNames) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + const OUString* pNames = PropertyNames.getConstArray(); + uno::Sequence< beans::PropertyState > aRet(PropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + const SfxItemPropertyMap &rMap = m_pImpl->m_rPropSet.getPropertyMap(); + const SwAttrSet* pSet = nullptr; + bool bAttrSetFetched = false; + + for (sal_Int32 i = 0, nEnd = PropertyNames.getLength(); i < nEnd; + ++i, ++pStates, ++pNames) + { + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName( *pNames ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + *pNames, + getXWeak()); + } + + if (bAttrSetFetched && !pSet && isATR(pEntry->nWID)) + { + *pStates = beans::PropertyState_DEFAULT_VALUE; + } + else + { + *pStates = lcl_SwXParagraph_getPropertyState( + rTextNode, &pSet, *pEntry, bAttrSetFetched ); + } + } + + return aRet; +} + +void SAL_CALL +SwXParagraph::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + if (rPropertyName == UNO_NAME_ANCHOR_TYPE || + rPropertyName == UNO_NAME_ANCHOR_TYPES || + rPropertyName == UNO_NAME_TEXT_WRAP) + { + return; + } + + // select paragraph + SwParaSelection aParaSel( aCursor ); + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName( rPropertyName ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw uno::RuntimeException( + "Property is read-only: " + rPropertyName, + getXWeak()); + } + + const bool bBelowFrameAtrEnd(pEntry->nWID < RES_FRMATR_END); + const bool bDrawingLayerRange(XATTR_FILL_FIRST <= pEntry->nWID && XATTR_FILL_LAST >= pEntry->nWID); + + if(bBelowFrameAtrEnd || bDrawingLayerRange) + { + o3tl::sorted_vector<sal_uInt16> aWhichIds; + + // For FillBitmapMode two IDs have to be reset (!) + if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + aWhichIds.insert(XATTR_FILLBMP_STRETCH); + aWhichIds.insert(XATTR_FILLBMP_TILE); + } + else + { + aWhichIds.insert(pEntry->nWID); + } + + if (pEntry->nWID < RES_PARATR_BEGIN) + { + aCursor.GetDoc().ResetAttrs(aCursor, true, aWhichIds); + } + else + { + // for paragraph attributes the selection must be extended + // to paragraph boundaries + SwPosition aStart( *aCursor.Start() ); + SwPosition aEnd ( *aCursor.End() ); + auto pTemp( aCursor.GetDoc().CreateUnoCursor(aStart) ); + if(!SwUnoCursorHelper::IsStartOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaStart); + } + + pTemp->SetMark(); + *pTemp->GetPoint() = aEnd; + + SwUnoCursorHelper::SelectPam(*pTemp, true); + + if (!SwUnoCursorHelper::IsEndOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaEnd); + } + + + pTemp->GetDoc().ResetAttrs(*pTemp, true, aWhichIds); + } + } + else + { + SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, aCursor); + } +} + +uno::Any SAL_CALL +SwXParagraph::getPropertyDefault(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + uno::Any aRet; + if (::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + return aRet; + } + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + + const bool bBelowFrameAtrEnd(pEntry->nWID < RES_FRMATR_END); + const bool bDrawingLayerRange(XATTR_FILL_FIRST <= pEntry->nWID && XATTR_FILL_LAST >= pEntry->nWID); + + if(bBelowFrameAtrEnd || bDrawingLayerRange) + { + const SfxPoolItem& rDefItem = rTextNode.GetDoc().GetAttrPool().GetDefaultItem(pEntry->nWID); + + rDefItem.QueryValue(aRet, pEntry->nMemberId); + } + + return aRet; +} + +void SAL_CALL +SwXParagraph::attach(const uno::Reference< text::XTextRange > & /*xTextRange*/) +{ + // SwXParagraph will only created in order to be inserted by + // 'insertTextContentBefore' or 'insertTextContentAfter' therefore + // they cannot be attached + throw uno::RuntimeException(); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getAnchor() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + // select paragraph + SwParaSelection aParaSel( aCursor ); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aCursor, m_pImpl->m_xParentText); + return xRet; +} + +void SAL_CALL SwXParagraph::dispose() +{ + SolarMutexGuard aGuard; + + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + if (pTextNode) + { + SwCursor aCursor( SwPosition( *pTextNode ), nullptr ); + pTextNode->GetDoc().getIDocumentContentOperations().DelFullPara(aCursor); + lang::EventObject const ev(getXWeak()); + std::unique_lock aGuard2(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard2, ev); + } +} + +void SAL_CALL SwXParagraph::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXParagraph::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXParagraph::createEnumeration() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPaM aPam ( rTextNode ); + const uno::Reference< container::XEnumeration > xRef = + new SwXTextPortionEnumeration(aPam, m_pImpl->m_xParentText, + m_pImpl->m_nSelectionStartPos, m_pImpl->m_nSelectionEndPos); + return xRef; +} + + /// tries to return less data, but may return more than just text fields +rtl::Reference< SwXTextPortionEnumeration > +SwXParagraph::createTextFieldsEnumeration() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + SwPaM aPam ( rTextNode ); + + return new SwXTextPortionEnumeration(aPam, m_pImpl->m_xParentText, + m_pImpl->m_nSelectionStartPos, m_pImpl->m_nSelectionEndPos, /*bOnlyTextFields*/true); +} + +uno::Type SAL_CALL SwXParagraph::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXParagraph::hasElements() +{ + SolarMutexGuard aGuard; + return GetTextNode() != nullptr; +} + +uno::Reference< text::XText > SAL_CALL +SwXParagraph::getText() +{ + SolarMutexGuard g; + + return m_pImpl->m_xParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getStart() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwPaM aPam( *aCursor.Start() ); + uno::Reference< text::XText > xParent = getText(); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aPam, xParent); + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getEnd() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwPaM aPam( *aCursor.End() ); + uno::Reference< text::XText > xParent = getText(); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aPam, xParent); + return xRet; +} + +OUString SAL_CALL SwXParagraph::getString() +{ + SolarMutexGuard aGuard; + OUString aRet; + SwTextNode const*const pTextNode( GetTextNode() ); + if (pTextNode) + { + SwPosition aPos( *pTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwUnoCursorHelper::GetTextFromPam(aCursor, aRet); + } + else if (m_pImpl->IsDescriptor()) + { + aRet = m_pImpl->m_sText; + } + else + { + // Seems object is being disposed or some other problem occurs. + // Anyway from user point of view object still exist, so on that level this is not an error + SAL_WARN("sw.uno", "getString() for invalid paragraph called. Returning empty string."); + } + return aRet; +} + +void SAL_CALL SwXParagraph::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + + SwTextNode const*const pTextNode( GetTextNode() ); + if (pTextNode) + { + SwPosition aPos( *pTextNode ); + SwCursor aCursor( aPos, nullptr ); + if (!SwUnoCursorHelper::IsStartOfPara(aCursor)) { + aCursor.MovePara(GoCurrPara, fnParaStart); + } + SwUnoCursorHelper::SelectPam(aCursor, true); + if (pTextNode->GetText().getLength()) { + aCursor.MovePara(GoCurrPara, fnParaEnd); + } + SwUnoCursorHelper::SetString(aCursor, aString); + SwUnoCursorHelper::SelectPam(aCursor, false); + } + else if (m_pImpl->IsDescriptor()) + { + m_pImpl->m_sText = aString; + } + else + { + throw uno::RuntimeException(); + } +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXParagraph::createContentEnumeration(const OUString& rServiceName) +{ + SolarMutexGuard g; + + if ( rServiceName != "com.sun.star.text.TextContent" ) + { + throw uno::RuntimeException(); + } + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPaM aPam( rTextNode ); + uno::Reference< container::XEnumeration > xRet = + SwXParaFrameEnumeration::Create(aPam, PARAFRAME_PORTION_PARAGRAPH); + return xRet; +} + +uno::Sequence< OUString > SAL_CALL +SwXParagraph::getAvailableServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; + return aRet; +} + +// MetadatableMixin +::sfx2::Metadatable* SwXParagraph::GetCoreObject() +{ + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + return pTextNode; +} + +uno::Reference<frame::XModel> SwXParagraph::GetModel() +{ + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + if (pTextNode) + { + SwDocShell const*const pShell( pTextNode->GetDoc().GetDocShell() ); + return pShell ? pShell->GetModel() : nullptr; + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoport.cxx b/sw/source/core/unocore/unoport.cxx new file mode 100644 index 0000000000..cfbe918ba2 --- /dev/null +++ b/sw/source/core/unocore/unoport.cxx @@ -0,0 +1,871 @@ +/* -*- 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 <unoport.hxx> + +#include <cmdid.h> +#include <cppuhelper/exc_hlp.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <svl/itemprop.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <unocrsrhelper.hxx> +#include <unoparaframeenum.hxx> +#include <unotextrange.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unomid.h> +#include <txtatr.hxx> +#include <ndtxt.hxx> +#include <doc.hxx> +#include <frmfmt.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp> +#include <com/sun/star/beans/GetPropertyTolerantResult.hpp> +#include <com/sun/star/beans/TolerantPropertySetResultType.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/text/XFootnote.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> + +using namespace ::com::sun::star; + +void SwXTextPortion::init(const SwUnoCursor* pPortionCursor) +{ + m_pUnoCursor = pPortionCursor->GetDoc().CreateUnoCursor(*pPortionCursor->GetPoint()); + if (pPortionCursor->HasMark()) + { + m_pUnoCursor->SetMark(); + *m_pUnoCursor->GetMark() = *pPortionCursor->GetMark(); + } +} + +SwXTextPortion::SwXTextPortion( + const SwUnoCursor* pPortionCursor, + uno::Reference< text::XText > xParent, + SwTextPortionType eType) + : m_pPropSet(aSwMapProvider.GetPropertySet( + (PORTION_REDLINE_START == eType || + PORTION_REDLINE_END == eType) + ? PROPERTY_MAP_REDLINE_PORTION + : PROPERTY_MAP_TEXTPORTION_EXTENSIONS)) + , m_xParentText(std::move(xParent)) + , m_pFrameFormat(nullptr) + , m_ePortionType(eType != PORTION_LIST_AUTOFMT ? eType : PORTION_TEXT) + , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) +{ + if (eType == PORTION_LIST_AUTOFMT) + { + m_bIsListAutoFormat = true; + } + init( pPortionCursor); +} + +SwXTextPortion::SwXTextPortion( + const SwUnoCursor* pPortionCursor, + uno::Reference< text::XText > xParent, + SwFrameFormat& rFormat ) + : m_pPropSet(aSwMapProvider.GetPropertySet( + PROPERTY_MAP_TEXTPORTION_EXTENSIONS)) + , m_xParentText(std::move(xParent)) + , m_pFrameFormat(&rFormat) + , m_ePortionType(PORTION_FRAME) + , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) +{ + StartListening(rFormat.GetNotifier()); + init( pPortionCursor); +} + +SwXTextPortion::SwXTextPortion( + const SwUnoCursor* pPortionCursor, + SwTextRuby const& rAttr, + uno::Reference< text::XText > xParent, + bool bIsEnd ) + : m_pPropSet(aSwMapProvider.GetPropertySet( + PROPERTY_MAP_TEXTPORTION_EXTENSIONS)) + , m_xParentText(std::move(xParent)) + , m_pFrameFormat(nullptr) + , m_ePortionType( bIsEnd ? PORTION_RUBY_END : PORTION_RUBY_START ) + , m_bIsCollapsed(false) + , m_bIsListAutoFormat(false) +{ + if (!bIsEnd) + { + m_oRubyText.emplace(); + m_oRubyStyle.emplace(); + m_oRubyAdjust.emplace(); + m_oRubyIsAbove.emplace(); + m_oRubyPosition.emplace(); + } + init( pPortionCursor); + + if (!bIsEnd) + { + const SfxPoolItem& rItem = rAttr.GetAttr(); + rItem.QueryValue(*m_oRubyText); + rItem.QueryValue(*m_oRubyStyle, MID_RUBY_CHARSTYLE); + rItem.QueryValue(*m_oRubyAdjust, MID_RUBY_ADJUST); + rItem.QueryValue(*m_oRubyIsAbove, MID_RUBY_ABOVE); + rItem.QueryValue(*m_oRubyPosition, MID_RUBY_POSITION); + } +} + +SwXTextPortion::~SwXTextPortion() +{ + SolarMutexGuard aGuard; + m_pUnoCursor.reset(nullptr); + EndListeningAll(); +} + +uno::Reference< text::XText > SwXTextPortion::getText() +{ + return m_xParentText; +} + +uno::Reference< text::XTextRange > SwXTextPortion::getStart() +{ + SolarMutexGuard aGuard; + uno::Reference< text::XTextRange > xRet; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwPaM aPam(*rUnoCursor.Start()); + uno::Reference< text::XText > xParent = getText(); + xRet = new SwXTextRange(aPam, xParent); + return xRet; +} + +uno::Reference< text::XTextRange > SwXTextPortion::getEnd() +{ + SolarMutexGuard aGuard; + uno::Reference< text::XTextRange > xRet; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwPaM aPam(*rUnoCursor.End()); + uno::Reference< text::XText > xParent = getText(); + xRet = new SwXTextRange(aPam, xParent); + return xRet; +} + +OUString SwXTextPortion::getString() +{ + SolarMutexGuard aGuard; + OUString aText; + SwUnoCursor& rUnoCursor = GetCursor(); + + // TextPortions are always within a paragraph + SwTextNode* pTextNd = rUnoCursor.GetPointNode().GetTextNode(); + if ( pTextNd ) + { + const sal_Int32 nStt = rUnoCursor.Start()->GetContentIndex(); + aText = pTextNd->GetExpandText(nullptr, nStt, + rUnoCursor.End()->GetContentIndex() - nStt, + false, false, false, ExpandMode::ExpandFootnote); + } + return aText; +} + +void SwXTextPortion::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwUnoCursorHelper::SetString(rUnoCursor, aString); +} + +uno::Reference< beans::XPropertySetInfo > SwXTextPortion::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + //! PropertySetInfo for text portion extensions + static uno::Reference< beans::XPropertySetInfo > + xTextPorExtRef = aSwMapProvider.GetPropertySet( + PROPERTY_MAP_TEXTPORTION_EXTENSIONS)->getPropertySetInfo(); + //! PropertySetInfo for redline portions + static uno::Reference< beans::XPropertySetInfo > + xRedlPorRef = aSwMapProvider.GetPropertySet( + PROPERTY_MAP_REDLINE_PORTION)->getPropertySetInfo(); + + return (PORTION_REDLINE_START == m_ePortionType || + PORTION_REDLINE_END == m_ePortionType) ? xRedlPorRef : xTextPorExtRef; +} + +void SwXTextPortion::setPropertyValue(const OUString& rPropertyName, + const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwUnoCursorHelper::SetPropertyValue(rUnoCursor, *m_pPropSet, + rPropertyName, aValue); +} + +void SwXTextPortion::GetPropertyValue( + uno::Any &rVal, + const SfxItemPropertyMapEntry& rEntry, + SwUnoCursor *pUnoCursor, + std::unique_ptr<SfxItemSet> &pSet ) +{ + static constexpr OUStringLiteral TEXT = u"Text"; + static constexpr OUStringLiteral TEXTFIELD = u"TextField"; + static constexpr OUStringLiteral FRAME = u"Frame"; + static constexpr OUStringLiteral FOOTNOTE = u"Footnote"; + static constexpr OUStringLiteral REDLINE = u"Redline"; + static constexpr OUStringLiteral RUBY = u"Ruby"; + static constexpr OUStringLiteral SOFTPAGEBREAK = u"SoftPageBreak"; + static constexpr OUStringLiteral TEXTFIELDSTART = u"TextFieldStart"; + static constexpr OUStringLiteral TEXTFIELDSEPARATOR = u"TextFieldSeparator"; + static constexpr OUStringLiteral TEXTFIELDEND = u"TextFieldEnd"; + static constexpr OUStringLiteral TEXTFIELDSTARTEND = u"TextFieldStartEnd"; + static constexpr OUStringLiteral ANNOTATION = u"Annotation"; + static constexpr OUStringLiteral ANNOTATIONEND = u"AnnotationEnd"; + static constexpr OUStringLiteral LINEBREAK = u"LineBreak"; + + OSL_ENSURE( pUnoCursor, "UNO cursor missing" ); + if (!pUnoCursor) + return; + switch(rEntry.nWID) + { + case FN_UNO_TEXT_PORTION_TYPE: + { + OUString sRet; + switch (m_ePortionType) + { + case PORTION_TEXT: sRet = TEXT; break; + case PORTION_FIELD: sRet = TEXTFIELD; break; + case PORTION_FRAME: sRet = FRAME; break; + case PORTION_FOOTNOTE: sRet = FOOTNOTE; break; + case PORTION_REFMARK_START: + case PORTION_REFMARK_END: sRet = UNO_NAME_REFERENCE_MARK; break; + case PORTION_TOXMARK_START: + case PORTION_TOXMARK_END: sRet = UNO_NAME_DOCUMENT_INDEX_MARK; break; + case PORTION_BOOKMARK_START: + case PORTION_BOOKMARK_END : sRet = UNO_NAME_BOOKMARK; break; + case PORTION_REDLINE_START: + case PORTION_REDLINE_END: sRet = REDLINE; break; + case PORTION_RUBY_START: + case PORTION_RUBY_END: sRet = RUBY; break; + case PORTION_SOFT_PAGEBREAK: sRet = SOFTPAGEBREAK; break; + case PORTION_META: sRet = UNO_NAME_META; break; + case PORTION_FIELD_START: sRet = TEXTFIELDSTART; break; + case PORTION_FIELD_SEP: sRet = TEXTFIELDSEPARATOR; break; + case PORTION_FIELD_END: sRet = TEXTFIELDEND; break; + case PORTION_FIELD_START_END:sRet = TEXTFIELDSTARTEND; break; + case PORTION_ANNOTATION: sRet = ANNOTATION; break; + case PORTION_ANNOTATION_END: sRet = ANNOTATIONEND; break; + case PORTION_LINEBREAK: sRet = LINEBREAK; break; + case PORTION_CONTENT_CONTROL:sRet = UNO_NAME_CONTENT_CONTROL; break; + default: break; + } + + rVal <<= sRet; + } + break; + case FN_UNO_CONTROL_CHARACTER: // obsolete! + break; + case FN_UNO_DOCUMENT_INDEX_MARK: + rVal <<= m_xTOXMark; + break; + case FN_UNO_REFERENCE_MARK: + rVal <<= m_xRefMark; + break; + case FN_UNO_BOOKMARK: + rVal <<= m_xBookmark; + break; + case FN_UNO_FOOTNOTE: + rVal <<= m_xFootnote; + break; + case FN_UNO_TEXT_FIELD: + rVal <<= m_xTextField; + break; + case FN_UNO_META: + rVal <<= m_xMeta; + break; + case FN_UNO_LINEBREAK: + rVal <<= m_xLineBreak; + break; + case FN_UNO_CONTENT_CONTROL: + rVal <<= m_xContentControl; + break; + case FN_UNO_IS_COLLAPSED: + { + switch (m_ePortionType) + { + case PORTION_REFMARK_START: + case PORTION_BOOKMARK_START : + case PORTION_TOXMARK_START: + case PORTION_REFMARK_END: + case PORTION_TOXMARK_END: + case PORTION_BOOKMARK_END : + case PORTION_REDLINE_START : + case PORTION_REDLINE_END : + case PORTION_RUBY_START: + case PORTION_RUBY_END: + case PORTION_FIELD_START: + case PORTION_FIELD_SEP: + case PORTION_FIELD_END: + rVal <<= m_bIsCollapsed; + break; + default: + break; + } + } + break; + case FN_UNO_IS_START: + { + bool bStart = true, bPut = true; + switch (m_ePortionType) + { + case PORTION_REFMARK_START: + case PORTION_BOOKMARK_START: + case PORTION_TOXMARK_START: + case PORTION_REDLINE_START: + case PORTION_RUBY_START: + case PORTION_FIELD_START: + break; + + case PORTION_REFMARK_END: + case PORTION_TOXMARK_END: + case PORTION_BOOKMARK_END: + case PORTION_REDLINE_END: + case PORTION_RUBY_END: + case PORTION_FIELD_SEP: + case PORTION_FIELD_END: + bStart = false; + break; + default: + bPut = false; + } + if(bPut) + rVal <<= bStart; + } + break; + case RES_TXTATR_CJK_RUBY: + { + const std::optional<uno::Any>* pToSet = nullptr; + switch(rEntry.nMemberId) + { + case MID_RUBY_TEXT : pToSet = &m_oRubyText; break; + case MID_RUBY_ADJUST : pToSet = &m_oRubyAdjust; break; + case MID_RUBY_CHARSTYLE:pToSet = &m_oRubyStyle; break; + case MID_RUBY_ABOVE : pToSet = &m_oRubyIsAbove;break; + case MID_RUBY_POSITION: pToSet = &m_oRubyPosition;break; + } + if(pToSet && *pToSet) + rVal = **pToSet; + } + break; + default: + beans::PropertyState eTemp; + bool bDone = false; + if (m_bIsListAutoFormat) + { + SwTextNode* pTextNode = pUnoCursor->GetPointNode().GetTextNode(); + std::shared_ptr<SfxItemSet> pListSet + = pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle(); + if (pListSet) + { + m_pPropSet->getPropertyValue(rEntry, *pListSet, rVal); + bDone = true; + } + } + if (!bDone) + { + bDone = SwUnoCursorHelper::getCursorPropertyValue( + rEntry, *pUnoCursor, &rVal, eTemp ); + } + if(!bDone) + { + if(!pSet) + { + pSet = std::make_unique<SfxItemSetFixed< + RES_CHRATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_CONTAINER, + RES_UNKNOWNATR_CONTAINER>>(pUnoCursor->GetDoc().GetAttrPool()); + SwUnoCursorHelper::GetCursorAttr(*pUnoCursor, *pSet); + } + m_pPropSet->getPropertyValue(rEntry, *pSet, rVal); + } + } +} + +uno::Sequence< uno::Any > SwXTextPortion::GetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames ) +{ + sal_Int32 nLength = rPropertyNames.getLength(); + const OUString *pPropertyNames = rPropertyNames.getConstArray(); + uno::Sequence< uno::Any > aValues(nLength); + uno::Any *pValues = aValues.getArray(); + SwUnoCursor& rUnoCursor = GetCursor(); + + { + std::unique_ptr<SfxItemSet> pSet; + // get starting point for the look-up, either the provided one or else + // from the beginning of the map + const SfxItemPropertyMap& rMap = m_pPropSet->getPropertyMap(); + for(sal_Int32 nProp = 0; nProp < nLength; nProp++) + { + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(pPropertyNames[nProp]); + if(!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + pPropertyNames[nProp], getXWeak() ); + GetPropertyValue( pValues[nProp], *pEntry, &rUnoCursor, pSet ); + } + } + return aValues; +} + +uno::Any SwXTextPortion::getPropertyValue( + const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Sequence< OUString > aPropertyNames { rPropertyName }; + return GetPropertyValues_Impl(aPropertyNames).getConstArray()[0]; +} + +void SwXTextPortion::SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + if (rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException("lengths do not match", + getXWeak(), -1); + + SwUnoCursor& rUnoCursor = GetCursor(); + + { + const OUString* pPropertyNames = rPropertyNames.getConstArray(); + const uno::Any* pValues = rValues.getConstArray(); + const SfxItemPropertyMap& rMap = m_pPropSet->getPropertyMap(); + uno::Sequence< beans::PropertyValue > aValues( rPropertyNames.getLength() ); + auto aValuesRange = asNonConstRange(aValues); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); nProp++) + { + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(pPropertyNames[nProp]); + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + pPropertyNames[nProp], getXWeak() ); + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException ("Property is read-only: " + pPropertyNames[nProp], getXWeak() ); + + aValuesRange[nProp].Name = pPropertyNames[nProp]; + aValuesRange[nProp].Value = pValues[nProp]; + } + SwUnoCursorHelper::SetPropertyValues( rUnoCursor, *m_pPropSet, aValues ); + } +} + +void SwXTextPortion::setPropertyValues( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SolarMutexGuard aGuard; + + // workaround for bad designed API + try + { + SetPropertyValues_Impl( rPropertyNames, rValues ); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a lang::WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +uno::Sequence< uno::Any > SwXTextPortion::getPropertyValues( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Any > aValues; + + // workaround for bad designed API + try + { + aValues = GetPropertyValues_Impl( rPropertyNames ); + } + catch (beans::UnknownPropertyException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch (lang::WrappedTargetException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + + return aValues; +} + +/* disabled for #i46921# */ +uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL SwXTextPortion::setPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SolarMutexGuard aGuard; + + if (rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException(); + SwUnoCursor& rUnoCursor = GetCursor(); + + sal_Int32 nProps = rPropertyNames.getLength(); + const OUString *pProp = rPropertyNames.getConstArray(); + + //sal_Int32 nVals = rValues.getLength(); + const uno::Any *pValue = rValues.getConstArray(); + + sal_Int32 nFailed = 0; + uno::Sequence< beans::SetPropertyTolerantFailed > aFailed( nProps ); + beans::SetPropertyTolerantFailed *pFailed = aFailed.getArray(); + + const SfxItemPropertyMap& rPropMap = m_pPropSet->getPropertyMap(); + + for (sal_Int32 i = 0; i < nProps; ++i) + { + try + { + pFailed[ nFailed ].Name = pProp[i]; + + const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName( pProp[i] ); + if (!pEntry) + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + else + { + // set property value + // (compare to SwXTextPortion::setPropertyValues) + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO; + else + { + SwUnoCursorHelper::SetPropertyValue( + rUnoCursor, *m_pPropSet, pProp[i], pValue[i] ); + } + } + } + catch (beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "" ); + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (lang::IllegalArgumentException &) + { + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (beans::PropertyVetoException &) + { + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (lang::WrappedTargetException &) + { + pFailed[ nFailed++ ].Result = beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + + aFailed.realloc( nFailed ); + return aFailed; +} + +uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL SwXTextPortion::getPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + + const uno::Sequence< beans::GetDirectPropertyTolerantResult > aTmpRes( + GetPropertyValuesTolerant_Impl( rPropertyNames, false ) ); + + // copy temporary result to final result type + sal_Int32 nLen = aTmpRes.getLength(); + uno::Sequence< beans::GetPropertyTolerantResult > aRes( nLen ); + std::copy(aTmpRes.begin(), aTmpRes.end(), aRes.getArray()); + return aRes; +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL SwXTextPortion::getDirectPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + return GetPropertyValuesTolerant_Impl( rPropertyNames, true ); +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SwXTextPortion::GetPropertyValuesTolerant_Impl( + const uno::Sequence< OUString >& rPropertyNames, + bool bDirectValuesOnly ) +{ + SolarMutexGuard aGuard; + + SwUnoCursor& rUnoCursor = GetCursor(); + + std::vector< beans::GetDirectPropertyTolerantResult > aResultVector; + + try + { + sal_Int32 nProps = rPropertyNames.getLength(); + const OUString *pProp = rPropertyNames.getConstArray(); + + std::unique_ptr<SfxItemSet> pSet; + + const SfxItemPropertyMap& rPropMap = m_pPropSet->getPropertyMap(); + + + uno::Sequence< beans::PropertyState > aPropertyStates; + if (m_bIsListAutoFormat) + { + SwTextNode* pTextNode = rUnoCursor.GetPointNode().GetTextNode(); + std::shared_ptr<SfxItemSet> pListSet + = pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle(); + if (pListSet) + { + std::vector<beans::PropertyState> aStates; + for (const auto& rPropertyName : rPropertyNames) + { + aStates.push_back(m_pPropSet->getPropertyState(rPropertyName, *pListSet)); + } + aPropertyStates = comphelper::containerToSequence(aStates); + } + } + if (!aPropertyStates.hasElements()) + { + aPropertyStates = + SwUnoCursorHelper::GetPropertyStates( + rUnoCursor, *m_pPropSet, + rPropertyNames, + SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT ); + } + const beans::PropertyState* pPropertyStates = aPropertyStates.getConstArray(); + + for (sal_Int32 i = 0; i < nProps; ++i) + { + beans::GetDirectPropertyTolerantResult aResult; + try + { + aResult.Name = pProp[i]; + if(pPropertyStates[i] == beans::PropertyState::PropertyState_MAKE_FIXED_SIZE) // property unknown? + { + if( bDirectValuesOnly ) + continue; + else + aResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + else + { + const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName( pProp[i] ); + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + pProp[i], getXWeak() ); + aResult.State = pPropertyStates[i]; + + aResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_FAILURE; + //#i104499# ruby portion attributes need special handling: + if( pEntry->nWID == RES_TXTATR_CJK_RUBY && + m_ePortionType == PORTION_RUBY_START ) + { + aResult.State = beans::PropertyState_DIRECT_VALUE; + } + if (!bDirectValuesOnly || beans::PropertyState_DIRECT_VALUE == aResult.State) + { + // get property value + // (compare to SwXTextPortion::getPropertyValue(s)) + GetPropertyValue( aResult.Value, *pEntry, &rUnoCursor, pSet ); + aResult.Result = beans::TolerantPropertySetResultType::SUCCESS; + aResultVector.push_back( aResult ); + } + } + } + catch (const beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + aResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (const lang::IllegalArgumentException &) + { + aResult.Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (const beans::PropertyVetoException &) + { + aResult.Result = beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (const lang::WrappedTargetException &) + { + aResult.Result = beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + } + catch (const uno::RuntimeException&) + { + throw; + } + catch (const uno::Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + + return comphelper::containerToSequence(aResultVector); +} + +void SwXTextPortion::addPropertiesChangeListener( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{} + +void SwXTextPortion::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{} + +void SwXTextPortion::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{} + +void SwXTextPortion::addPropertyChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextPortion::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextPortion::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextPortion::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +beans::PropertyState SwXTextPortion::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + beans::PropertyState eRet = beans::PropertyState_DEFAULT_VALUE; + SwUnoCursor& rUnoCursor = GetCursor(); + + if (GetTextPortionType() == PORTION_RUBY_START && + rPropertyName.startsWith("Ruby")) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + else + { + eRet = SwUnoCursorHelper::GetPropertyState(rUnoCursor, *m_pPropSet, + rPropertyName); + } + return eRet; +} + +uno::Sequence< beans::PropertyState > SwXTextPortion::getPropertyStates( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + uno::Sequence< beans::PropertyState > aRet = + SwUnoCursorHelper::GetPropertyStates(rUnoCursor, *m_pPropSet, + rPropertyNames, SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION); + + if(GetTextPortionType() == PORTION_RUBY_START) + { + const OUString* pNames = rPropertyNames.getConstArray(); + beans::PropertyState* pStates = aRet.getArray(); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength();nProp++) + { + if (pNames[nProp].startsWith("Ruby")) + pStates[nProp] = beans::PropertyState_DIRECT_VALUE; + } + } + return aRet; +} + +void SwXTextPortion::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwUnoCursorHelper::SetPropertyToDefault( + rUnoCursor, *m_pPropSet, rPropertyName); +} + +uno::Any SwXTextPortion::getPropertyDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwUnoCursor& rUnoCursor = GetCursor(); + + aRet = SwUnoCursorHelper::GetPropertyDefault(rUnoCursor, *m_pPropSet, + rPropertyName); + return aRet; +} + +uno::Reference< container::XEnumeration > SwXTextPortion::createContentEnumeration(const OUString& /*aServiceName*/) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + return SwXParaFrameEnumeration::Create(rUnoCursor, PARAFRAME_PORTION_CHAR, m_pFrameFormat); +} + +uno::Sequence< OUString > SwXTextPortion::getAvailableServiceNames() +{ + return { "com.sun.star.text.TextContent" }; +} + +OUString SwXTextPortion::getImplementationName() +{ + return { "SwXTextPortion" }; +} + +sal_Bool SwXTextPortion::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextPortion::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextPortion", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" }; +} + +void SwXTextPortion::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFrameFormat = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx new file mode 100644 index 0000000000..4b50a72cf5 --- /dev/null +++ b/sw/source/core/unocore/unoportenum.cxx @@ -0,0 +1,1526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- 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 <sal/config.h> +#include <sal/log.hxx> + +#include <utility> + +#include <unoport.hxx> +#include <unotext.hxx> +#include <IMark.hxx> +#include <crossrefbookmark.hxx> +#include <annotationmark.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <txatbase.hxx> +#include <txtatr.hxx> +#include <ndhints.hxx> +#include <ndtxt.hxx> +#include <unocrsr.hxx> +#include <docary.hxx> +#include <textboxhelper.hxx> +#include <tox.hxx> +#include <unoparaframeenum.hxx> +#include <unocrsrhelper.hxx> +#include <unorefmark.hxx> +#include <unobookmark.hxx> +#include <unofield.hxx> +#include <unometa.hxx> +#include <unolinebreak.hxx> +#include <unocontentcontrol.hxx> +#include <fmtfld.hxx> +#include <fldbas.hxx> +#include <fmtmeta.hxx> +#include <fmtanchr.hxx> +#include <fmtrfmrk.hxx> +#include <frmfmt.hxx> +#include <fmtflcnt.hxx> +#include <unoidx.hxx> +#include <unocoll.hxx> +#include <redline.hxx> +#include <txtannotationfld.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/string.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/container/XEnumeration.hpp> +#include <algorithm> +#include <memory> +#include <set> +#include <stack> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; + +typedef std::pair< TextRangeList_t * const, SwTextAttr const * const > PortionList_t; +typedef std::stack< PortionList_t > PortionStack_t; + +static void lcl_CreatePortions( + TextRangeList_t & i_rPortions, + css::uno::Reference< SwXText > const& i_xParentText, + SwUnoCursor* pUnoCursor, + FrameClientSortList_t & i_rFrames, + const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos, bool bOnlyTextFields ); + +namespace +{ + enum class BkmType { + Start, End, StartEnd + }; + + struct SwXBookmarkPortion_Impl + { + Reference<XTextContent> xBookmark; + BkmType nBkmType; + const SwPosition aPosition; + + SwXBookmarkPortion_Impl(uno::Reference<text::XTextContent> xMark, + const BkmType nType, SwPosition _aPosition) + : xBookmark (std::move( xMark )) + , nBkmType ( nType ) + , aPosition (std::move( _aPosition )) + { + } + sal_Int32 getIndex () const + { + return aPosition.GetContentIndex(); + } + }; + typedef std::shared_ptr < SwXBookmarkPortion_Impl > SwXBookmarkPortion_ImplSharedPtr; + struct BookmarkCompareStruct + { + bool operator () ( const SwXBookmarkPortion_ImplSharedPtr &r1, + const SwXBookmarkPortion_ImplSharedPtr &r2 ) const + { + // #i16896# for bookmark portions at the same position, the start should + // always precede the end. Hence compare positions, and use bookmark type + // as tie-breaker for same position. + // return ( r1->nIndex == r2->nIndex ) + // ? ( r1->nBkmType < r2->nBkmType ) + // : ( r1->nIndex < r2->nIndex ); + + // Note that the above code does not correctly handle + // the case when one bookmark ends, and another begins in the same + // position. When this occurs, the above code will return the + // start of the 2nd bookmark BEFORE the end of the first bookmark + // See bug #i58438# for more details. The below code is correct and + // fixes both #i58438 and #i16896# + return r1->aPosition < r2->aPosition; + } + }; + typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList; + + /// Inserts pBkmk to rBkmArr in case it starts or ends at rOwnNode + void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNode& rOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr) + { + bool const hasOther = pBkmk->IsExpanded(); + + const SwPosition& rStartPos = pBkmk->GetMarkStart(); + if(rStartPos.GetNode() == rOwnNode) + { + // #i109272#: cross reference marks: need special handling! + ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk)); + BkmType const nType = (hasOther || pCrossRefMark) + ? BkmType::Start : BkmType::StartEnd; + rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>( + SwXBookmark::CreateXBookmark(rDoc, pBkmk), + nType, rStartPos)); + } + + const SwPosition& rEndPos = pBkmk->GetMarkEnd(); + if(rEndPos.GetNode() != rOwnNode) + return; + + std::optional<SwPosition> oCrossRefEndPos; + const SwPosition* pEndPos = nullptr; + ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk)); + if(hasOther) + { + pEndPos = &rEndPos; + } + else if (pCrossRefMark) + { + // Crossrefbookmarks only remember the start position but have to span the whole paragraph + SwTextNode& rEndNd = *rEndPos.GetNode().GetTextNode(); + oCrossRefEndPos.emplace(rEndNd, rEndNd.Len()); + pEndPos = &*oCrossRefEndPos; + } + if(pEndPos) + { + rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>( + SwXBookmark::CreateXBookmark(rDoc, pBkmk), + BkmType::End, *pEndPos)); + } + } + + void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCursor& rUnoCursor, SwXBookmarkPortion_ImplList& rBkmArr) + { + IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); + if(!pMarkAccess->getBookmarksCount()) + return; + + SwTextNode* pTextNode = rUnoCursor.GetPoint()->GetNode().GetTextNode(); + assert(pTextNode); + // A text node already knows its marks via its SwIndexes. + o3tl::sorted_vector<const sw::mark::IMark*> aSeenMarks; + for (const SwContentIndex* pIndex = pTextNode->GetFirstIndex(); pIndex; pIndex = pIndex->GetNext()) + { + // Need a non-cost mark here, as we'll create a UNO wrapper around it. + sw::mark::IMark* pBkmk = const_cast<sw::mark::IMark*>(pIndex->GetMark()); + if (!pBkmk) + continue; + IDocumentMarkAccess::MarkType eType = IDocumentMarkAccess::GetType(*pBkmk); + // These are the types stored in the container otherwise accessible via getBookmarks*() + if (eType != IDocumentMarkAccess::MarkType::BOOKMARK && eType != IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK && + eType != IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK) + continue; + // Only handle bookmarks once, if they start and end at this node as well. + if (!aSeenMarks.insert(pBkmk).second) + continue; + lcl_FillBookmark(pBkmk, *pTextNode, rDoc, rBkmArr); + } + } + + struct SwAnnotationStartPortion_Impl + { + + uno::Reference< text::XTextField > mxAnnotationField; + const SwPosition maPosition; + + SwAnnotationStartPortion_Impl( + uno::Reference< text::XTextField > xAnnotationField, + SwPosition aPosition) + : mxAnnotationField (std::move( xAnnotationField )) + , maPosition (std::move( aPosition )) + { + } + + sal_Int32 getIndex () const + { + return maPosition.GetContentIndex(); + } + }; + typedef std::shared_ptr < SwAnnotationStartPortion_Impl > SwAnnotationStartPortion_ImplSharedPtr; + struct AnnotationStartCompareStruct + { + bool operator () ( const SwAnnotationStartPortion_ImplSharedPtr &r1, + const SwAnnotationStartPortion_ImplSharedPtr &r2 ) + const + { + return r1->maPosition < r2->maPosition; + } + }; + typedef std::multiset < SwAnnotationStartPortion_ImplSharedPtr, AnnotationStartCompareStruct > SwAnnotationStartPortion_ImplList; + + void lcl_FillAnnotationStartArray( + SwDoc& rDoc, + SwUnoCursor& rUnoCursor, + SwAnnotationStartPortion_ImplList& rAnnotationStartArr ) + { + IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); + if ( pMarkAccess->getAnnotationMarksCount() == 0 ) + { + return; + } + + // no need to consider annotation marks starting after aEndOfPara + SwContentNode& rPtNd = *rUnoCursor.GetPoint()->GetNode().GetContentNode(); + SwPosition aEndOfPara( rPtNd, rPtNd.Len() ); + const IDocumentMarkAccess::const_iterator_t pCandidatesEnd = + pMarkAccess->findFirstAnnotationStartsAfter(aEndOfPara); + + // search for all annotation marks that have its start position in this paragraph + const SwNode& rOwnNode = rUnoCursor.GetPoint()->GetNode(); + for( IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAnnotationMarksBegin(); + ppMark != pCandidatesEnd; + ++ppMark ) + { + ::sw::mark::AnnotationMark* const pAnnotationMark = + dynamic_cast< ::sw::mark::AnnotationMark* >(*ppMark); + + if (!pAnnotationMark) + continue; + + const SwPosition& rStartPos = pAnnotationMark->GetMarkStart(); + if (rStartPos.GetNode() != rOwnNode) + continue; + + const SwFormatField* pAnnotationFormatField = pAnnotationMark->GetAnnotationFormatField(); + if (!pAnnotationFormatField) + { + SAL_WARN("sw.core", "missing annotation format field"); + continue; + } + + rAnnotationStartArr.insert( + std::make_shared<SwAnnotationStartPortion_Impl>( + SwXTextField::CreateXTextField(&rDoc, + pAnnotationFormatField), + rStartPos)); + } + } +} + +OUString SwXTextPortionEnumeration::getImplementationName() +{ + return "SwXTextPortionEnumeration"; +} + +sal_Bool +SwXTextPortionEnumeration::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXTextPortionEnumeration::getSupportedServiceNames() +{ + return { "com.sun.star.text.TextPortionEnumeration" }; +} + +SwXTextPortionEnumeration::SwXTextPortionEnumeration( + SwPaM& rParaCursor, + css::uno::Reference< SwXText > const & xParentText, + const sal_Int32 nStart, + const sal_Int32 nEnd, + bool bOnlyTextFields) +{ + m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint()); + + OSL_ENSURE(nEnd == -1 || (nStart <= nEnd && + nEnd <= m_pUnoCursor->Start()->GetNode().GetTextNode()->GetText().getLength()), + "start or end value invalid!"); + + // find all frames, graphics and OLEs that are bound AT character in para + FrameClientSortList_t frames; + ::CollectFrameAtNode(m_pUnoCursor->GetPoint()->GetNode(), frames, true); + lcl_CreatePortions(m_Portions, xParentText, &*m_pUnoCursor, frames, nStart, nEnd, bOnlyTextFields); +} + +SwXTextPortionEnumeration::SwXTextPortionEnumeration( + SwPaM& rParaCursor, + TextRangeList_t && rPortions ) + : m_Portions( std::move(rPortions) ) +{ + m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint()); +} + +SwXTextPortionEnumeration::~SwXTextPortionEnumeration() +{ + SolarMutexGuard aGuard; + if( m_pUnoCursor ) + { + m_pUnoCursor->GetDoc().cleanupUnoCursorTable(); + m_pUnoCursor.reset(nullptr); + } +} + +sal_Bool SwXTextPortionEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + + return !m_Portions.empty(); +} + +uno::Any SwXTextPortionEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + + if (m_Portions.empty()) + throw container::NoSuchElementException(); + + Any any; + any <<= uno::Reference<XTextRange>(m_Portions.front()); + m_Portions.pop_front(); + return any; +} + +static void +lcl_FillFieldMarkArray(std::deque<sal_Int32> & rFieldMarks, SwUnoCursor const & rUnoCursor, + const sal_Int32 i_nStartPos) +{ + const SwTextNode * const pTextNode = + rUnoCursor.GetPoint()->GetNode().GetTextNode(); + if (!pTextNode) return; + + const sal_Unicode fld[] = { + CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, CH_TXT_ATR_FORMELEMENT, 0 }; + sal_Int32 pos = std::max(static_cast<sal_Int32>(0), i_nStartPos); + while ((pos = ::comphelper::string::indexOfAny(pTextNode->GetText(), fld, pos)) != -1) + { + rFieldMarks.push_back(pos); + ++pos; + } +} + +static rtl::Reference<SwXTextPortion> +lcl_ExportFieldMark( + uno::Reference< text::XText > const & i_xParentText, + SwUnoCursor * const pUnoCursor, + const SwTextNode * const pTextNode ) +{ + rtl::Reference<SwXTextPortion> pPortion; + SwDoc& rDoc = pUnoCursor->GetDoc(); + // maybe it's a good idea to add a special hint to the hints array and rely on the hint segmentation... + const sal_Int32 start = pUnoCursor->Start()->GetContentIndex(); + OSL_ENSURE(pUnoCursor->End()->GetContentIndex() == start, + "hmm --- why is this different"); + + pUnoCursor->Right(1); + if ( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + { + OSL_FAIL("cannot move cursor?"); + return nullptr; + } + + const sal_Unicode Char = pTextNode->GetText()[start]; + if (CH_TXT_ATR_FIELDSTART == Char) + { + ::sw::mark::IFieldmark* pFieldmark = nullptr; + pFieldmark = rDoc.getIDocumentMarkAccess()-> + getFieldmarkAt(*pUnoCursor->GetMark()); + pPortion = new SwXTextPortion( + pUnoCursor, i_xParentText, PORTION_FIELD_START); + if (pFieldmark) + { + pPortion->SetBookmark( + SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark)); + } + } + else if (CH_TXT_ATR_FIELDSEP == Char) + { + // TODO how to get the field? + pPortion = new SwXTextPortion( + pUnoCursor, i_xParentText, PORTION_FIELD_SEP); + } + else if (CH_TXT_ATR_FIELDEND == Char) + { + ::sw::mark::IFieldmark* pFieldmark = nullptr; + pFieldmark = rDoc.getIDocumentMarkAccess()-> + getFieldmarkAt(*pUnoCursor->GetMark()); + pPortion = new SwXTextPortion( + pUnoCursor, i_xParentText, PORTION_FIELD_END); + if (pFieldmark) + { + pPortion->SetBookmark( + SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark)); + } + } + else if (CH_TXT_ATR_FORMELEMENT == Char) + { + ::sw::mark::IFieldmark* pFieldmark = + rDoc.getIDocumentMarkAccess()->getFieldmarkAt(*pUnoCursor->GetMark()); + pPortion = new SwXTextPortion( + pUnoCursor, i_xParentText, PORTION_FIELD_START_END); + if (pFieldmark) + { + pPortion->SetBookmark( + SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark)); + } + } + else + { + OSL_FAIL("no fieldmark found?"); + } + return pPortion; +} + +static rtl::Reference<SwXTextPortion> +lcl_CreateRefMarkPortion( + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + const SwTextAttr & rAttr, const bool bEnd) +{ + SwDoc& rDoc = pUnoCursor->GetDoc(); + SwFormatRefMark& rRefMark = const_cast<SwFormatRefMark&>( + static_cast<const SwFormatRefMark&>(rAttr.GetAttr())); + Reference<XTextContent> xContent; + if (!xContent.is()) + { + xContent = SwXReferenceMark::CreateXReferenceMark(rDoc, &rRefMark); + } + + rtl::Reference<SwXTextPortion> pPortion; + if (!bEnd) + { + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_START); + pPortion->SetRefMark(xContent); + pPortion->SetCollapsed(rAttr.End() == nullptr); + } + else + { + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_END); + pPortion->SetRefMark(xContent); + } + return pPortion; +} + +static void +lcl_InsertRubyPortion( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + const SwTextAttr & rAttr, const bool bEnd) +{ + rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(pUnoCursor, + static_txtattr_cast<const SwTextRuby&>(rAttr), xParent, bEnd); + rPortions.emplace_back(pPortion); + pPortion->SetCollapsed(rAttr.End() == nullptr); +} + +static rtl::Reference<SwXTextPortion> +lcl_CreateTOXMarkPortion( + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + SwTextAttr & rAttr, const bool bEnd) +{ + SwDoc& rDoc = pUnoCursor->GetDoc(); + SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr()); + + const Reference<XTextContent> xContent = + SwXDocumentIndexMark::CreateXDocumentIndexMark(rDoc, & rTOXMark); + + rtl::Reference<SwXTextPortion> pPortion; + if (!bEnd) + { + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_START); + pPortion->SetTOXMark(xContent); + pPortion->SetCollapsed(rAttr.GetEnd() == nullptr); + } + else + { + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_END); + pPortion->SetTOXMark(xContent); + } + return pPortion; +} + +static rtl::Reference<SwXTextPortion> +lcl_CreateMetaPortion( + css::uno::Reference<SwXText> const& xParent, + const SwUnoCursor * const pUnoCursor, + SwTextAttr & rAttr, std::unique_ptr<TextRangeList_t const> && pPortions) +{ + const rtl::Reference<SwXMeta> xMeta( SwXMeta::CreateXMeta( + *static_cast<SwFormatMeta &>(rAttr.GetAttr()).GetMeta(), + xParent, std::move(pPortions))); + rtl::Reference<SwXTextPortion> pPortion; + if (RES_TXTATR_META == rAttr.Which()) + { + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_META); + pPortion->SetMeta(xMeta); + } + else + { + const uno::Reference<text::XTextField> xField(static_cast<cppu::OWeakObject*>(xMeta.get()), uno::UNO_QUERY); + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_FIELD); + pPortion->SetTextField(xField); + } + return pPortion; +} + +/// Creates a text portion that has a non-empty ContentControl property. +static rtl::Reference<SwXTextPortion> +lcl_CreateContentControlPortion(const css::uno::Reference<SwXText>& xParent, + const SwUnoCursor* pUnoCursor, SwTextAttr& rAttr, + std::unique_ptr<const TextRangeList_t>&& pPortions) +{ + rtl::Reference<SwXContentControl> xContentControl = SwXContentControl::CreateXContentControl( + *static_cast<SwFormatContentControl&>(rAttr.GetAttr()).GetContentControl(), xParent, + std::move(pPortions)); + rtl::Reference<SwXTextPortion> pPortion; + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_CONTENT_CONTROL); + pPortion->SetContentControl(xContentControl); + return pPortion; +} + +/** + * Exports all bookmarks from rBkmArr into rPortions that have the same start + * or end position as nIndex. + * + * @param rBkmArr the array of bookmarks. If bOnlyFrameStarts is true, then + * this is only read, otherwise consumed entries are removed. + * + * @param rFramePositions the list of positions where there is an at-char / + * anchored frame. + * + * @param bOnlyFrameStarts If true: export only the start of the bookmarks + * which cover an at-char anchored frame. If false: export the end of the same + * bookmarks and everything else. + */ +static void lcl_ExportBookmark( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + SwXBookmarkPortion_ImplList& rBkmArr, + const sal_Int32 nIndex, + const o3tl::sorted_vector<sal_Int32>& rFramePositions, + bool bOnlyFrameStarts) +{ + for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; ) + { + const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter; + if ( nIndex > pPtr->getIndex() ) + { + if (bOnlyFrameStarts) + ++aIter; + else + aIter = rBkmArr.erase(aIter); + continue; + } + if ( nIndex < pPtr->getIndex() ) + break; + + if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) || + (BkmType::StartEnd == pPtr->nBkmType)) + { + bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end(); + bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts; + if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts) + { + // At this we create a text portion, due to one of these + // reasons: + // - this is the real start of a non-collapsed bookmark + // - this is the real position of a collapsed bookmark + // - this is the start or end (depending on bOnlyFrameStarts) + // of a collapsed bookmark at the same position as an at-char + // anchored frame + rtl::Reference<SwXTextPortion> pPortion = + new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START); + rPortions.emplace_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart ); + } + } + else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts) + { + rtl::Reference<SwXTextPortion> pPortion = + new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END); + rPortions.emplace_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + } + + // next bookmark + if (bOnlyFrameStarts) + ++aIter; + else + aIter = rBkmArr.erase(aIter); + } +} + +static void lcl_ExportSoftPageBreak( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + SwSoftPageBreakList& rBreakArr, + const sal_Int32 nIndex) +{ + for ( auto aIter = rBreakArr.begin(); aIter != rBreakArr.end(); ) + { + if ( nIndex > *aIter ) + { + aIter = rBreakArr.erase(aIter); + continue; + } + if ( nIndex < *aIter ) + break; + + rPortions.push_back( + new SwXTextPortion(pUnoCursor, xParent, PORTION_SOFT_PAGEBREAK) ); + aIter = rBreakArr.erase(aIter); + } +} + +namespace { + +struct SwXRedlinePortion_Impl +{ + const SwRangeRedline* m_pRedline; + const bool m_bStart; + + SwXRedlinePortion_Impl ( const SwRangeRedline* pRed, const bool bIsStart ) + : m_pRedline(pRed) + , m_bStart(bIsStart) + { + } + + sal_Int32 getRealIndex () const + { + return m_bStart ? m_pRedline->Start()->GetContentIndex() + : m_pRedline->End() ->GetContentIndex(); + } +}; + +} + +typedef std::shared_ptr < SwXRedlinePortion_Impl > + SwXRedlinePortion_ImplSharedPtr; + +namespace { + +struct RedlineCompareStruct +{ + static const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r ) + { + return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End()); + } + + bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1, + const SwXRedlinePortion_ImplSharedPtr &r2 ) const + { + return getPosition ( r1 ) < getPosition ( r2 ); + } +}; + +} + +typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct > +SwXRedlinePortion_ImplList; + +static rtl::Reference<SwXTextPortion> +lcl_ExportHints( + PortionStack_t & rPortionStack, + const css::uno::Reference<SwXText> & xParent, + SwUnoCursor * const pUnoCursor, + SwpHints const * const pHints, + const sal_Int32 i_nStartPos, + const sal_Int32 i_nEndPos, + const sal_Int32 nCurrentIndex, + const bool bRightMoveForbidden, + bool & o_rbCursorMoved, + sal_Int32 & o_rNextAttrPosition) +{ + // if the attribute has a dummy character, then xRef is set (except META and CONTENT_CONTROL) + // otherwise, the portion for the attribute is inserted into rPortions! + rtl::Reference<SwXTextPortion> pPortion; + SwDoc& rDoc = pUnoCursor->GetDoc(); + //search for special text attributes - first some ends + size_t nEndIndex = 0; + const auto nHintsCount = pHints->Count(); + for (;;) + { + if (nEndIndex >= nHintsCount) + break; + SwTextAttr * const pAttr = pHints->GetSortedByEnd(nEndIndex); + const sal_Int32* pAttrEnd = pAttr->GetEnd(); + sal_Int32 nNextEnd = 0; + if (pAttrEnd && + nCurrentIndex < (nNextEnd = (*pAttrEnd))) + break; + if(pAttrEnd) + { + if (nNextEnd == nCurrentIndex) + { + const sal_uInt16 nWhich( pAttr->Which() ); + switch (nWhich) + { + case RES_TXTATR_TOXMARK: + { + rtl::Reference<SwXTextPortion> xTmp = lcl_CreateTOXMarkPortion( + xParent, pUnoCursor, *pAttr, true); + rPortionStack.top().first->push_back(xTmp); + } + break; + case RES_TXTATR_REFMARK: + { + rtl::Reference<SwXTextPortion> xTmp = lcl_CreateRefMarkPortion( + xParent, pUnoCursor, *pAttr, true); + rPortionStack.top().first->push_back(xTmp); + } + break; + case RES_TXTATR_CJK_RUBY: + //#i91534# GetEnd() == 0 mixes the order of ruby start/end + if( *pAttr->GetEnd() == pAttr->GetStart()) + { + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCursor, *pAttr, false); + } + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCursor, *pAttr, true); + break; + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + { + OSL_ENSURE(pAttr->GetStart() != *pAttr->GetEnd(), + "empty meta?"); + if ((i_nStartPos > 0) && + (pAttr->GetStart() < i_nStartPos)) + { + // force skip pAttr and rest of attribute ends + // at nCurrentIndex + // because they are not contained in the meta pAttr + // and the meta pAttr itself is outside selection! + // (necessary for SwXMeta::createEnumeration) + if (pAttr->GetStart() + 1 == i_nStartPos) + { + nEndIndex = pHints->Count() - 1; + } + break; + } + PortionList_t Top = rPortionStack.top(); + if (Top.second != pAttr) + { + OSL_FAIL("ExportHints: stack error" ); + } + else + { + std::unique_ptr<const TextRangeList_t> + pCurrentPortions(Top.first); + rPortionStack.pop(); + rtl::Reference<SwXTextPortion> xPortion( + lcl_CreateMetaPortion(xParent, pUnoCursor, + *pAttr, std::move(pCurrentPortions))); + rPortionStack.top().first->push_back(xPortion); + } + } + break; + case RES_TXTATR_CONTENTCONTROL: + { + if (pAttr->GetStart() == *pAttr->GetEnd()) + { + SAL_WARN("sw.core", "lcl_ExportHints: empty content control"); + } + if ((i_nStartPos > 0) && (pAttr->GetStart() < i_nStartPos)) + { + // If the start pos is the start of the content of the content control, + // skip it: it'll be handled in SwXContentControl::createEnumeration(). + if (pAttr->GetStart() + 1 == i_nStartPos) + { + nEndIndex = pHints->Count() - 1; + } + break; + } + PortionList_t Top = rPortionStack.top(); + if (Top.second != pAttr) + { + SAL_WARN("sw.core", "lcl_ExportHints: content control is not at the " + "top of the portion stack"); + } + else + { + std::unique_ptr<const TextRangeList_t> pCurrentPortions(Top.first); + rPortionStack.pop(); + rtl::Reference<SwXTextPortion> xPortion( + lcl_CreateContentControlPortion(xParent, pUnoCursor, *pAttr, + std::move(pCurrentPortions))); + rPortionStack.top().first->push_back(xPortion); + } + } + break; + } + } + } + nEndIndex++; + } + + // then some starts + size_t nStartIndex = 0; + sal_Int32 nNextStart = 0; + while(nStartIndex < nHintsCount && + nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart())) + { + SwTextAttr * const pAttr = pHints->Get(nStartIndex); + sal_uInt16 nAttrWhich = pAttr->Which(); + if (nNextStart == nCurrentIndex) + { + switch( nAttrWhich ) + { + case RES_TXTATR_FIELD: + if(!bRightMoveForbidden) + { + pUnoCursor->Right(1); + if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + break; + pPortion = new SwXTextPortion( + pUnoCursor, xParent, PORTION_FIELD); + Reference<XTextField> const xField = + SwXTextField::CreateXTextField(&rDoc, + &pAttr->GetFormatField()); + pPortion->SetTextField(xField); + } + break; + + case RES_TXTATR_ANNOTATION: + if(!bRightMoveForbidden) + { + pUnoCursor->Right(1); + if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + break; + + const SwTextAnnotationField* pTextAnnotationField = dynamic_cast<const SwTextAnnotationField*>( pAttr ); + ::sw::mark::IMark* pAnnotationMark = pTextAnnotationField ? pTextAnnotationField->GetAnnotationMark() : nullptr; + if ( pAnnotationMark != nullptr ) + { + pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION_END ); + pPortion->SetBookmark(SwXBookmark::CreateXBookmark( + rDoc, pAnnotationMark)); + } + else + { + pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION ); + Reference<XTextField> xField = + SwXTextField::CreateXTextField(&rDoc, + &pAttr->GetFormatField()); + pPortion->SetTextField(xField); + } + } + break; + + case RES_TXTATR_INPUTFIELD: + if(!bRightMoveForbidden) + { + + pUnoCursor->Right( + pAttr->GetFormatField().GetField()->ExpandField(true, nullptr).getLength() + 2 ); + if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + break; + pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_FIELD); + Reference<XTextField> xField = + SwXTextField::CreateXTextField(&rDoc, + &pAttr->GetFormatField()); + pPortion->SetTextField(xField); + } + break; + + case RES_TXTATR_FLYCNT: + if(!bRightMoveForbidden) + { + pUnoCursor->Right(1); + if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + break; // Robust #i81708# content in covered cells + + // Do not expose inline anchored textboxes. + if (SwTextBoxHelper::isTextBox(pAttr->GetFlyCnt().GetFrameFormat(), RES_FLYFRMFMT)) + break; + + pUnoCursor->Exchange(); + pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_FRAME); + } + break; + + case RES_TXTATR_FTN: + { + if(!bRightMoveForbidden) + { + pUnoCursor->Right(1); + if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() ) + break; + pPortion = new SwXTextPortion( + pUnoCursor, xParent, PORTION_FOOTNOTE); + Reference<XFootnote> xContent = + SwXFootnotes::GetObject(rDoc, pAttr->GetFootnote()); + pPortion->SetFootnote(xContent); + } + } + break; + + case RES_TXTATR_TOXMARK: + case RES_TXTATR_REFMARK: + { + bool bIsPoint = !(pAttr->GetEnd()); + if (!bRightMoveForbidden || !bIsPoint) + { + if (bIsPoint) + { + pUnoCursor->Right(1); + } + rtl::Reference<SwXTextPortion> xTmp = + (RES_TXTATR_REFMARK == nAttrWhich) + ? lcl_CreateRefMarkPortion( + xParent, pUnoCursor, *pAttr, false) + : lcl_CreateTOXMarkPortion( + xParent, pUnoCursor, *pAttr, false); + if (bIsPoint) // consume CH_TXTATR! + { + pUnoCursor->Normalize(false); + pUnoCursor->DeleteMark(); + pPortion = xTmp; + } + else // just insert it + { + rPortionStack.top().first->push_back(xTmp); + } + } + } + break; + case RES_TXTATR_CJK_RUBY: + //#i91534# GetEnd() == 0 mixes the order of ruby start/end + if(pAttr->GetEnd() && (*pAttr->GetEnd() != pAttr->GetStart())) + { + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCursor, *pAttr, false); + } + break; + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + case RES_TXTATR_CONTENTCONTROL: + if (pAttr->GetStart() != *pAttr->GetEnd()) + { + if (!bRightMoveForbidden) + { + pUnoCursor->Right(1); + o_rbCursorMoved = true; + // only if the end is included in selection! + if ((i_nEndPos < 0) || + (*pAttr->GetEnd() <= i_nEndPos)) + { + rPortionStack.push( std::make_pair( + new TextRangeList_t, pAttr )); + } + } + } + break; + case RES_TXTATR_LINEBREAK: + if (!bRightMoveForbidden) + { + pUnoCursor->Right(1); + if (*pUnoCursor->GetMark() == *pUnoCursor->GetPoint()) + break; + pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_LINEBREAK); + rtl::Reference<SwXLineBreak> xLineBreak + = SwXLineBreak::CreateXLineBreak( + &const_cast<SwFormatLineBreak&>(pAttr->GetLineBreak())); + pPortion->SetLineBreak(xLineBreak); + } + break; + case RES_TXTATR_AUTOFMT: + case RES_TXTATR_INETFMT: + case RES_TXTATR_CHARFMT: + break; // these are handled as properties of a "Text" portion + default: + OSL_FAIL("unknown attribute"); + break; + } + } + nStartIndex++; + } + + if (pPortion.is()) // implies that we have moved the cursor + { + o_rbCursorMoved = true; + } + if (!o_rbCursorMoved) + { + // search for attribute changes behind the current cursor position + // break up at frames, bookmarks, redlines + + nStartIndex = 0; + nNextStart = 0; + while(nStartIndex < pHints->Count() && + nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart())) + nStartIndex++; + + nEndIndex = 0; + sal_Int32 nNextEnd = 0; + while(nEndIndex < pHints->Count() && + nCurrentIndex >= (nNextEnd = pHints->GetSortedByEnd(nEndIndex)->GetAnyEnd())) + nEndIndex++; + + sal_Int32 nNextPos = + ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd)) + ? nNextStart : nNextEnd; + if (nNextPos > nCurrentIndex) + { + o_rNextAttrPosition = nNextPos; + } + } + return pPortion; +} + +static void lcl_MoveCursor( SwUnoCursor * const pUnoCursor, + const sal_Int32 nCurrentIndex, + const sal_Int32 nNextFrameIndex, + const sal_Int32 nNextPortionIndex, + const sal_Int32 nNextAttrIndex, + const sal_Int32 nNextMarkIndex, + const sal_Int32 nEndPos ) +{ + sal_Int32 nMovePos = pUnoCursor->GetPointContentNode()->Len(); + + if ((nEndPos >= 0) && (nEndPos < nMovePos)) + { + nMovePos = nEndPos; + } + + if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos)) + { + nMovePos = nNextFrameIndex; + } + + if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos)) + { + nMovePos = nNextPortionIndex; + } + + if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos)) + { + nMovePos = nNextAttrIndex; + } + + if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos)) + { + nMovePos = nNextMarkIndex; + } + + if (nMovePos > nCurrentIndex) + { + pUnoCursor->GetPoint()->SetContent( nMovePos ); + } +} + +static void lcl_FillRedlineArray( + SwDoc const & rDoc, + SwUnoCursor const & rUnoCursor, + SwXRedlinePortion_ImplList& rRedArr ) +{ + const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + const size_t nRedTableCount = rRedTable.size(); + + if ( nRedTableCount <= 0 ) + return; + + const SwPosition* pStart = rUnoCursor.GetPoint(); + const SwNode& rOwnNode = pStart->GetNode(); + + SwRedlineTable::size_type nRed = rDoc.getIDocumentRedlineAccess().GetRedlinePos(rOwnNode, RedlineType::Any); + for(; nRed < nRedTableCount; ++nRed) + { + const SwRangeRedline* pRedline = rRedTable[nRed]; + auto [pRedStart, pRedEnd]= pRedline->StartEnd(); + if ( rOwnNode == pRedStart->GetNode() ) + rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>( + pRedline, true ) ); + if( pRedline->HasMark() && pRedEnd->GetNode() == rOwnNode ) + rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>( + pRedline, false ) ); + } +} + +static void lcl_FillSoftPageBreakArray( + SwUnoCursor const & rUnoCursor, + SwSoftPageBreakList& rBreakArr ) +{ + const SwTextNode *pTextNode = + rUnoCursor.GetPoint()->GetNode().GetTextNode(); + if( pTextNode ) + pTextNode->fillSoftPageBreakList( rBreakArr ); +} + +static void lcl_ExportRedline( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCursor * const pUnoCursor, + SwXRedlinePortion_ImplList& rRedlineArr, + const sal_Int32 nIndex) +{ + + // We want this loop to iterate over all red lines in this + // array. We will only insert the ones with index matches + for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end(); + aIter != aEnd; ) + { + SwXRedlinePortion_ImplSharedPtr pPtr = *aIter; + sal_Int32 nRealIndex = pPtr->getRealIndex(); + // If there are elements before nIndex, remove them + if ( nIndex > nRealIndex ) + aIter = rRedlineArr.erase(aIter); + // If the elements match, and them to the list + else if ( nIndex == nRealIndex ) + { + rPortions.push_back( new SwXRedlinePortion( + *pPtr->m_pRedline, pUnoCursor, xParent, pPtr->m_bStart)); + aIter = rRedlineArr.erase(aIter); + } + // If we've iterated past nIndex, exit the loop + else + break; + } +} + +static void lcl_ExportBkmAndRedline( + TextRangeList_t & rPortions, + Reference<XText> const & xParent, + const SwUnoCursor * const pUnoCursor, + SwXBookmarkPortion_ImplList& rBkmArr, + SwXRedlinePortion_ImplList& rRedlineArr, + SwSoftPageBreakList& rBreakArr, + const sal_Int32 nIndex, + const o3tl::sorted_vector<sal_Int32>& rFramePositions, + bool bOnlyFrameBookmarkStarts) +{ + if (!rBkmArr.empty()) + lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions, + bOnlyFrameBookmarkStarts); + + if (bOnlyFrameBookmarkStarts) + // Only exporting the start of some collapsed bookmarks: no export of + // other arrays. + return; + + if (!rRedlineArr.empty()) + lcl_ExportRedline(rPortions, xParent, pUnoCursor, rRedlineArr, nIndex); + + if (!rBreakArr.empty()) + lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCursor, rBreakArr, nIndex); +} + +/** + * Exports all start annotation marks from rAnnotationStartArr into rPortions that have the same + * start position as nIndex. + * + * @param rAnnotationStartArr the array of annotation marks. Consumed entries are removed. + * + * @param rFramePositions the list of positions where there is an at-char anchored frame. + * + * @param bOnlyFrame If true: export only the start of annotation marks which cover an at-char + * anchored frame. If false: export everything else. + */ +static void lcl_ExportAnnotationStarts( + TextRangeList_t & rPortions, + Reference<XText> const & xParent, + const SwUnoCursor * const pUnoCursor, + SwAnnotationStartPortion_ImplList& rAnnotationStartArr, + const sal_Int32 nIndex, + const o3tl::sorted_vector<sal_Int32>& rFramePositions, + bool bOnlyFrame) +{ + for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end(); + aIter != aEnd; ) + { + SwAnnotationStartPortion_ImplSharedPtr pPtr = *aIter; + if ( nIndex > pPtr->getIndex() ) + { + aIter = rAnnotationStartArr.erase(aIter); + continue; + } + if ( pPtr->getIndex() > nIndex ) + { + break; + } + + bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end(); + if (bFrameStart || !bOnlyFrame) + { + rtl::Reference<SwXTextPortion> pPortion = + new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION ); + pPortion->SetTextField( pPtr->mxAnnotationField ); + rPortions.emplace_back(pPortion); + + aIter = rAnnotationStartArr.erase(aIter); + } + else + ++aIter; + } +} + +/// Fills character positions from rFrames into rFramePositions. +static void lcl_ExtractFramePositions(FrameClientSortList_t& rFrames, sal_Int32 nCurrentIndex, + o3tl::sorted_vector<sal_Int32>& rFramePositions) +{ + for (const auto& rFrame : rFrames) + { + if (rFrame.nIndex < nCurrentIndex) + continue; + + if (rFrame.nIndex > nCurrentIndex) + break; + + const auto pFrame = static_cast<const SwFrameFormat*>(rFrame.pFrameClient->GetRegisteredIn()); + if (!pFrame) + continue; + + auto& rFormat = *const_cast<SwFrameFormat*>(pFrame); + const SwFormatAnchor& rAnchor = rFormat.GetAnchor(); + if (!rAnchor.GetAnchorNode()) + continue; + + rFramePositions.insert(rAnchor.GetAnchorContentOffset()); + } +} + +/** + * Exports at-char anchored frames. + * + * @param i_rFrames the frames for this paragraph, frames at <= i_nCurrentIndex + * are removed from the container. + */ +static sal_Int32 lcl_ExportFrames( + TextRangeList_t & rPortions, + Reference<XText> const & i_xParent, + SwUnoCursor const * const i_pUnoCursor, + FrameClientSortList_t & i_rFrames, + sal_Int32 const i_nCurrentIndex) +{ + // Ignore frames which are not exported, as we are exporting a selection + // and they are anchored before the start of the selection. + while (!i_rFrames.empty() && i_rFrames.front().nIndex < i_nCurrentIndex) + i_rFrames.pop_front(); + + // find first Frame in (sorted) i_rFrames at current position + while (!i_rFrames.empty() && (i_rFrames.front().nIndex == i_nCurrentIndex)) + // do not check for i_nEnd here; this is done implicitly by lcl_MoveCursor + { + auto pFrame = static_cast<SwFrameFormat*>(i_rFrames.front().pFrameClient->GetRegisteredIn()); + if (pFrame) // Frame could be disposed + { + rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(i_pUnoCursor, i_xParent, *pFrame ); + rPortions.emplace_back(pPortion); + } + i_rFrames.pop_front(); + } + + return !i_rFrames.empty() ? i_rFrames.front().nIndex : -1; +} + +static sal_Int32 lcl_GetNextIndex( + SwXBookmarkPortion_ImplList const & rBkmArr, + SwXRedlinePortion_ImplList const & rRedlineArr, + SwSoftPageBreakList const & rBreakArr ) +{ + sal_Int32 nRet = -1; + if(!rBkmArr.empty()) + { + SwXBookmarkPortion_ImplSharedPtr pPtr = *rBkmArr.begin(); + nRet = pPtr->getIndex(); + } + if(!rRedlineArr.empty()) + { + SwXRedlinePortion_ImplSharedPtr pPtr = *rRedlineArr.begin(); + sal_Int32 nTmp = pPtr->getRealIndex(); + if(nRet < 0 || nTmp < nRet) + nRet = nTmp; + } + if(!rBreakArr.empty()) + { + if(nRet < 0 || *rBreakArr.begin() < nRet) + nRet = *rBreakArr.begin(); + } + return nRet; +}; + +static void lcl_CreatePortions( + TextRangeList_t & i_rPortions, + css::uno::Reference< SwXText > const & i_xParentText, + SwUnoCursor * const pUnoCursor, + FrameClientSortList_t & i_rFrames, + const sal_Int32 i_nStartPos, + const sal_Int32 i_nEndPos, + bool bOnlyTextFields ) +{ + if (!pUnoCursor) + return; + + // set the start if a selection should be exported + if ((i_nStartPos > 0) && + (pUnoCursor->Start()->GetContentIndex() != i_nStartPos)) + { + pUnoCursor->DeleteMark(); + OSL_ENSURE(pUnoCursor->Start()->GetNode().GetTextNode() && + (i_nStartPos <= pUnoCursor->Start()->GetNode().GetTextNode()-> + GetText().getLength()), "Incorrect start position" ); + // ??? should this be i_nStartPos - current position ? + pUnoCursor->Right(i_nStartPos); + } + + SwDoc& rDoc = pUnoCursor->GetDoc(); + + std::deque<sal_Int32> FieldMarks; + if (!bOnlyTextFields) + lcl_FillFieldMarkArray(FieldMarks, *pUnoCursor, i_nStartPos); + + SwXBookmarkPortion_ImplList Bookmarks; + if (!bOnlyTextFields) + lcl_FillBookmarkArray(rDoc, *pUnoCursor, Bookmarks); + + SwXRedlinePortion_ImplList Redlines; + if (!bOnlyTextFields) + lcl_FillRedlineArray(rDoc, *pUnoCursor, Redlines); + + SwSoftPageBreakList SoftPageBreaks; + if (!bOnlyTextFields) + lcl_FillSoftPageBreakArray(*pUnoCursor, SoftPageBreaks); + + SwAnnotationStartPortion_ImplList AnnotationStarts; + if (!bOnlyTextFields) + lcl_FillAnnotationStartArray( rDoc, *pUnoCursor, AnnotationStarts ); + + PortionStack_t PortionStack; + PortionStack.push( PortionList_t(&i_rPortions, nullptr) ); + + bool bAtEnd( false ); + while (!bAtEnd) // every iteration consumes at least current character! + { + if (pUnoCursor->HasMark()) + { + pUnoCursor->Normalize(false); + pUnoCursor->DeleteMark(); + } + + SwTextNode * const pTextNode = pUnoCursor->GetPointNode().GetTextNode(); + if (!pTextNode) + { + OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?"); + return; + } + + SwpHints * const pHints = pTextNode->GetpSwpHints(); + const sal_Int32 nCurrentIndex = + pUnoCursor->GetPoint()->GetContentIndex(); + // this contains the portion which consumes the character in the + // text at nCurrentIndex; i.e. it must be set _once_ per iteration + rtl::Reference<SwXTextPortion> xRef; + + SwUnoCursorHelper::SelectPam(*pUnoCursor, true); // set mark + + // First remember the frame positions. + o3tl::sorted_vector<sal_Int32> aFramePositions; + lcl_ExtractFramePositions(i_rFrames, nCurrentIndex, aFramePositions); + + // Then export start of collapsed bookmarks which "cover" at-char + // anchored frames. + lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true ); + + lcl_ExportAnnotationStarts( + *PortionStack.top().first, + i_xParentText, + pUnoCursor, + AnnotationStarts, + nCurrentIndex, + aFramePositions, + /*bOnlyFrame=*/true ); + + const sal_Int32 nFirstFrameIndex = + lcl_ExportFrames( *PortionStack.top().first, + i_xParentText, pUnoCursor, i_rFrames, nCurrentIndex); + + // Export ends of the previously started collapsed bookmarks + all + // other bookmarks, redlines, etc. + lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false ); + + lcl_ExportAnnotationStarts( + *PortionStack.top().first, + i_xParentText, + pUnoCursor, + AnnotationStarts, + nCurrentIndex, + aFramePositions, + /*bOnlyFrame=*/false ); + + bool bCursorMoved( false ); + sal_Int32 nNextAttrIndex = -1; + // #111716# the cursor must not move right at the + // end position of a selection! + bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos)) + || (nCurrentIndex >= pTextNode->Len()); + if (pHints) + { + // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor + xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCursor, + pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd, + bCursorMoved, nNextAttrIndex); + if (PortionStack.empty()) + { + OSL_FAIL("CreatePortions: stack underflow"); + return; + } + } + + if (!xRef.is() && !bCursorMoved) + { + if (!bAtEnd && + !FieldMarks.empty() && (FieldMarks.front() == nCurrentIndex)) + { + // moves cursor + xRef = lcl_ExportFieldMark(i_xParentText, pUnoCursor, pTextNode); + FieldMarks.pop_front(); + } + } + else + { + OSL_ENSURE(FieldMarks.empty() || + (FieldMarks.front() != nCurrentIndex), + "fieldmark and hint with CH_TXTATR at same pos?"); + } + + if (!bAtEnd && !xRef.is() && !bCursorMoved) + { + const sal_Int32 nNextPortionIndex = + lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks); + + sal_Int32 nNextMarkIndex = ( !FieldMarks.empty() ? FieldMarks.front() : -1 ); + if ( !AnnotationStarts.empty() + && ( nNextMarkIndex == -1 + || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) ) + { + nNextMarkIndex = (*AnnotationStarts.begin())->getIndex(); + } + + lcl_MoveCursor( + pUnoCursor, + nCurrentIndex, + nFirstFrameIndex, + nNextPortionIndex, + nNextAttrIndex, + nNextMarkIndex, + i_nEndPos ); + + xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT); + } + else if (bAtEnd && !xRef.is() && !pTextNode->Len()) + { + // special case: for an empty paragraph, we better put out a + // text portion because there may be a hyperlink attribute + xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT); + } + else if (bAtEnd && !xRef.is() && pHints) + { + // See if there is an empty autofmt at the paragraph end. If so, export it, since that + // affects the formatting of number portions. + for (size_t i = 0; i < pHints->Count(); ++i) + { + const SwTextAttr* pHint = pHints->GetSortedByEnd(i); + if (pHint->GetStart() < pTextNode->Len()) + { + break; + } + if (pHint->Which() == RES_TXTATR_AUTOFMT && pHint->GetEnd() + && pHint->GetStart() == *pHint->GetEnd() + && pHint->GetStart() == pTextNode->Len()) + { + xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT); + break; + } + } + } + + if (xRef.is()) + { + PortionStack.top().first->push_back(xRef); + } + } + + OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second, + "CreatePortions: stack error" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoredline.cxx b/sw/source/core/unocore/unoredline.cxx new file mode 100644 index 0000000000..feeceec92b --- /dev/null +++ b/sw/source/core/unocore/unoredline.cxx @@ -0,0 +1,581 @@ +/* -*- 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 <sal/config.h> +#include <sal/log.hxx> +#include <com/sun/star/text/XTextSection.hpp> +#include <comphelper/propertyvalue.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <vcl/svapp.hxx> + +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <redline.hxx> +#include <section.hxx> +#include <unoprnms.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unoparagraph.hxx> +#include <unocoll.hxx> +#include <unomap.hxx> +#include <unocrsr.hxx> +#include <unoport.hxx> +#include <unoredline.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <docary.hxx> + +using namespace ::com::sun::star; + +SwXRedlineText::SwXRedlineText(SwDoc* _pDoc, const SwNodeIndex& aIndex) : + SwXText(_pDoc, CursorType::Redline), + m_aNodeIndex(aIndex) +{ +} + +const SwStartNode* SwXRedlineText::GetStartNode() const +{ + return m_aNodeIndex.GetNode().GetStartNode(); +} + +uno::Any SwXRedlineText::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet; + + if (cppu::UnoType<container::XEnumerationAccess>::get()== rType) + { + uno::Reference<container::XEnumerationAccess> aAccess = this; + aRet <<= aAccess; + } + else + { + // delegate to SwXText and OWeakObject + aRet = SwXText::queryInterface(rType); + if(!aRet.hasValue()) + { + aRet = OWeakObject::queryInterface(rType); + } + } + + return aRet; +} + +uno::Sequence<uno::Type> SwXRedlineText::getTypes() +{ + return cppu::OTypeCollection( + cppu::UnoType<container::XEnumerationAccess>::get(), + SwXText::getTypes() + ).getTypes(); +} + +uno::Sequence<sal_Int8> SwXRedlineText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +rtl::Reference< SwXTextCursor > SwXRedlineText::createXTextCursor() +{ + SolarMutexGuard aGuard; + + SwPosition aPos(m_aNodeIndex); + rtl::Reference<SwXTextCursor> pXCursor = + new SwXTextCursor(*GetDoc(), this, CursorType::Redline, aPos); + auto& rUnoCursor(pXCursor->GetCursor()); + rUnoCursor.Move(fnMoveForward, GoInNode); + + // #101929# prevent a newly created text cursor from running inside a table + // because table cells have their own XText. + // Patterned after SwXTextFrame::createTextCursor(). + + // skip all tables at the beginning + SwTableNode* pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + bool bTable = pTableNode != nullptr; + while( pTableNode != nullptr ) + { + rUnoCursor.GetPoint()->Assign( *pTableNode->EndOfSectionNode() ); + SwContentNode* pContentNode = GetDoc()->GetNodes().GoNext(rUnoCursor.GetPoint()); + pTableNode = pContentNode->FindTableNode(); + } + if( bTable && rUnoCursor.GetPointNode().FindSttNodeByType( SwNormalStartNode ) + != GetStartNode() ) + { + // We have gone too far and have left our own redline. This means that + // no content node outside of a table could be found, and therefore we + // except. + throw uno::RuntimeException( + "No content node found that is inside this change section " + "but outside of a table"); + } + + return pXCursor; +} + +rtl::Reference< SwXTextCursor > SwXRedlineText::createXTextCursorByRange( + const uno::Reference<text::XTextRange> & aTextRange) +{ + rtl::Reference< SwXTextCursor > xCursor = createXTextCursor(); + xCursor->gotoRange(aTextRange->getStart(), false); + xCursor->gotoRange(aTextRange->getEnd(), true); + return xCursor; +} + +uno::Reference<container::XEnumeration> SwXRedlineText::createEnumeration() +{ + SolarMutexGuard aGuard; + SwPaM aPam(m_aNodeIndex); + aPam.Move(fnMoveForward, GoInNode); + auto pUnoCursor(GetDoc()->CreateUnoCursor(*aPam.Start())); + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Redline); +} + +uno::Type SwXRedlineText::getElementType( ) +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SwXRedlineText::hasElements( ) +{ + return true; // we always have a content index +} + +SwXRedlinePortion::SwXRedlinePortion(SwRangeRedline const& rRedline, + SwUnoCursor const*const pPortionCursor, + uno::Reference< text::XText > const& xParent, bool const bStart) + : SwXTextPortion(pPortionCursor, xParent, + bStart ? PORTION_REDLINE_START : PORTION_REDLINE_END) + , m_rRedline(rRedline) +{ + SetCollapsed(!m_rRedline.HasMark()); +} + +SwXRedlinePortion::~SwXRedlinePortion() +{ +} + +static uno::Sequence<beans::PropertyValue> lcl_GetSuccessorProperties(const SwRangeRedline& rRedline) +{ + const SwRedlineData* pNext = rRedline.GetRedlineData().Next(); + if(pNext) + { + return + { + // GetAuthorString(n) walks the SwRedlineData* chain; + // here we always need element 1 + comphelper::makePropertyValue(UNO_NAME_REDLINE_AUTHOR, rRedline.GetAuthorString(1)), + comphelper::makePropertyValue(UNO_NAME_REDLINE_DATE_TIME, pNext->GetTimeStamp().GetUNODateTime()), + comphelper::makePropertyValue(UNO_NAME_REDLINE_COMMENT, pNext->GetComment()), + comphelper::makePropertyValue(UNO_NAME_REDLINE_TYPE, SwRedlineTypeToOUString(pNext->GetType())) + }; + } + return uno::Sequence<beans::PropertyValue>(4); +} + +uno::Any SwXRedlinePortion::getPropertyValue( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + if (!Validate()) + { + return uno::Any(); + } + uno::Any aRet; + if(rPropertyName == UNO_NAME_REDLINE_TEXT) + { + const SwNodeIndex* pNodeIdx = m_rRedline.GetContentIdx(); + if(pNodeIdx ) + { + if ( SwNodeOffset(1) < ( pNodeIdx->GetNode().EndOfSectionIndex() - pNodeIdx->GetNode().GetIndex() ) ) + { + SwUnoCursor& rUnoCursor = GetCursor(); + uno::Reference<text::XText> xRet = new SwXRedlineText(&rUnoCursor.GetDoc(), *pNodeIdx); + aRet <<= xRet; + } + else { + OSL_FAIL("Empty section in redline portion! (end node immediately follows start node)"); + } + } + } + else + { + aRet = GetPropertyValue(rPropertyName, m_rRedline); + if(!aRet.hasValue() && + rPropertyName != UNO_NAME_REDLINE_SUCCESSOR_DATA) + aRet = SwXTextPortion::getPropertyValue(rPropertyName); + } + return aRet; +} + +bool SwXRedlinePortion::Validate() +{ + SwUnoCursor& rUnoCursor = GetCursor(); + //search for the redline + SwDoc& rDoc = rUnoCursor.GetDoc(); + const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + bool bFound = false; + for(size_t nRed = 0; nRed < rRedTable.size() && !bFound; nRed++) + { + bFound = &m_rRedline == rRedTable[nRed]; + } + return bFound; + // don't throw; the only caller can return void instead +} + +uno::Sequence< sal_Int8 > SAL_CALL SwXRedlinePortion::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Any SwXRedlinePortion::GetPropertyValue( std::u16string_view rPropertyName, const SwRangeRedline& rRedline ) +{ + uno::Any aRet; + if(rPropertyName == UNO_NAME_REDLINE_AUTHOR) + aRet <<= rRedline.GetAuthorString(); + else if(rPropertyName == UNO_NAME_REDLINE_DATE_TIME) + { + aRet <<= rRedline.GetTimeStamp().GetUNODateTime(); + } + else if (rPropertyName == UNO_NAME_REDLINE_MOVED_ID) + aRet <<= rRedline.GetMovedID(); + else if (rPropertyName == UNO_NAME_REDLINE_COMMENT) + aRet <<= rRedline.GetComment(); + else if(rPropertyName == UNO_NAME_REDLINE_DESCRIPTION) + aRet <<= const_cast<SwRangeRedline&>(rRedline).GetDescr(); + else if(rPropertyName == UNO_NAME_REDLINE_TYPE) + { + aRet <<= SwRedlineTypeToOUString(rRedline.GetType()); + } + else if(rPropertyName == UNO_NAME_REDLINE_SUCCESSOR_DATA) + { + if(rRedline.GetRedlineData().Next()) + aRet <<= lcl_GetSuccessorProperties(rRedline); + } + else if (rPropertyName == UNO_NAME_REDLINE_IDENTIFIER) + { + aRet <<= OUString::number( + sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(&rRedline) ) ); + } + else if (rPropertyName == UNO_NAME_IS_IN_HEADER_FOOTER) + { + aRet <<= rRedline.GetDoc().IsInHeaderFooter( rRedline.GetPoint()->GetNode() ); + } + else if (rPropertyName == UNO_NAME_MERGE_LAST_PARA) + { + aRet <<= !rRedline.IsDelLastPara(); + } + return aRet; +} + +uno::Sequence< beans::PropertyValue > SwXRedlinePortion::CreateRedlineProperties( + const SwRangeRedline& rRedline, bool bIsStart ) +{ + uno::Sequence< beans::PropertyValue > aRet(12); + const SwRedlineData* pNext = rRedline.GetRedlineData().Next(); + beans::PropertyValue* pRet = aRet.getArray(); + + sal_Int32 nPropIdx = 0; + pRet[nPropIdx].Name = UNO_NAME_REDLINE_AUTHOR; + pRet[nPropIdx++].Value <<= rRedline.GetAuthorString(); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_DATE_TIME; + pRet[nPropIdx++].Value <<= rRedline.GetTimeStamp().GetUNODateTime(); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_COMMENT; + pRet[nPropIdx++].Value <<= rRedline.GetComment(); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_DESCRIPTION; + pRet[nPropIdx++].Value <<= const_cast<SwRangeRedline&>(rRedline).GetDescr(); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_TYPE; + pRet[nPropIdx++].Value <<= SwRedlineTypeToOUString(rRedline.GetType()); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_IDENTIFIER; + pRet[nPropIdx++].Value <<= OUString::number( + sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(&rRedline) ) ); + pRet[nPropIdx].Name = UNO_NAME_IS_COLLAPSED; + pRet[nPropIdx++].Value <<= !rRedline.HasMark(); + + pRet[nPropIdx].Name = UNO_NAME_IS_START; + pRet[nPropIdx++].Value <<= bIsStart; + + pRet[nPropIdx].Name = UNO_NAME_MERGE_LAST_PARA; + pRet[nPropIdx++].Value <<= !rRedline.IsDelLastPara(); + + const SwNodeIndex* pNodeIdx = rRedline.GetContentIdx(); + if(pNodeIdx ) + { + if ( SwNodeOffset(1) < ( pNodeIdx->GetNode().EndOfSectionIndex() - pNodeIdx->GetNode().GetIndex() ) ) + { + uno::Reference<text::XText> xRet = new SwXRedlineText(&rRedline.GetDoc(), *pNodeIdx); + pRet[nPropIdx].Name = UNO_NAME_REDLINE_TEXT; + pRet[nPropIdx++].Value <<= xRet; + } + else { + OSL_FAIL("Empty section in redline portion! (end node immediately follows start node)"); + } + } + if(pNext) + { + pRet[nPropIdx].Name = UNO_NAME_REDLINE_SUCCESSOR_DATA; + pRet[nPropIdx++].Value <<= lcl_GetSuccessorProperties(rRedline); + } + aRet.realloc(nPropIdx); + return aRet; +} + +SwXRedline::SwXRedline(SwRangeRedline& rRedline, SwDoc& rDoc) : + SwXText(&rDoc, CursorType::Redline), + m_pDoc(&rDoc), + m_pRedline(&rRedline) +{ + StartListening(m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); +} + +SwXRedline::~SwXRedline() +{ +} + +uno::Reference< beans::XPropertySetInfo > SwXRedline::getPropertySetInfo( ) +{ + static uno::Reference< beans::XPropertySetInfo > xRef = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_REDLINE)->getPropertySetInfo(); + return xRef; +} + +void SwXRedline::setPropertyValue( const OUString& rPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(rPropertyName == UNO_NAME_REDLINE_AUTHOR) + { + OSL_FAIL("currently not available"); + } + else if(rPropertyName == UNO_NAME_REDLINE_DATE_TIME) + { + OSL_FAIL("currently not available"); + } + else if(rPropertyName == UNO_NAME_REDLINE_COMMENT) + { + OUString sTmp; aValue >>= sTmp; + m_pRedline->SetComment(sTmp); + } + else if(rPropertyName == UNO_NAME_REDLINE_DESCRIPTION) + { + SAL_WARN("sw.uno", "SwXRedline::setPropertyValue: can't set Description"); + } + else if(rPropertyName == UNO_NAME_REDLINE_TYPE) + { + OSL_FAIL("currently not available"); + OUString sTmp; aValue >>= sTmp; + if(sTmp.isEmpty()) + throw lang::IllegalArgumentException(); + } + else if(rPropertyName == UNO_NAME_REDLINE_SUCCESSOR_DATA) + { + OSL_FAIL("currently not available"); + } + else + { + throw lang::IllegalArgumentException(); + } +} + +uno::Any SwXRedline::getPropertyValue( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + uno::Any aRet; + bool bStart = rPropertyName == UNO_NAME_REDLINE_START; + if(bStart || + rPropertyName == UNO_NAME_REDLINE_END) + { + uno::Reference<XInterface> xRet; + SwNode* pNode = &m_pRedline->GetPointNode(); + if(!bStart && m_pRedline->HasMark()) + pNode = &m_pRedline->GetMarkNode(); + switch(pNode->GetNodeType()) + { + case SwNodeType::Section: + { + SwSectionNode* pSectNode = pNode->GetSectionNode(); + OSL_ENSURE(pSectNode, "No section node!"); + xRet = SwXTextSections::GetObject( *pSectNode->GetSection().GetFormat() ); + } + break; + case SwNodeType::Table : + { + SwTableNode* pTableNode = pNode->GetTableNode(); + OSL_ENSURE(pTableNode, "No table node!"); + SwTable& rTable = pTableNode->GetTable(); + SwFrameFormat* pTableFormat = rTable.GetFrameFormat(); + xRet = SwXTextTables::GetObject( *pTableFormat ); + } + break; + case SwNodeType::Text : + { + SwPosition* pPoint = nullptr; + if(bStart || !m_pRedline->HasMark()) + pPoint = m_pRedline->GetPoint(); + else + pPoint = m_pRedline->GetMark(); + const rtl::Reference<SwXTextRange> xRange = + SwXTextRange::CreateXTextRange(*m_pDoc, *pPoint, nullptr); + xRet = uno::Reference<text::XTextRange>(xRange); + } + break; + default: + OSL_FAIL("illegal node type"); + } + aRet <<= xRet; + } + else if(rPropertyName == UNO_NAME_REDLINE_TEXT) + { + const SwNodeIndex* pNodeIdx = m_pRedline->GetContentIdx(); + if( pNodeIdx ) + { + if ( SwNodeOffset(1) < ( pNodeIdx->GetNode().EndOfSectionIndex() - pNodeIdx->GetNode().GetIndex() ) ) + { + uno::Reference<text::XText> xRet = new SwXRedlineText(m_pDoc, *pNodeIdx); + aRet <<= xRet; + } + else { + OSL_FAIL("Empty section in redline portion! (end node immediately follows start node)"); + } + } + } + else + aRet = SwXRedlinePortion::GetPropertyValue(rPropertyName, *m_pRedline); + return aRet; +} + +void SwXRedline::addPropertyChangeListener( + const OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ +} + +void SwXRedline::removePropertyChangeListener( + const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ +} + +void SwXRedline::addVetoableChangeListener( + const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + +void SwXRedline::removeVetoableChangeListener( + const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + +void SwXRedline::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pDoc = nullptr; + m_pRedline = nullptr; + } else if(auto pHint = dynamic_cast<const sw::FindRedlineHint*>(&rHint)) { + if(!*pHint->m_ppXRedline && &pHint->m_rRedline == GetRedline()) + *pHint->m_ppXRedline = this; + } +} + +uno::Reference< container::XEnumeration > SwXRedline::createEnumeration() +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + + const SwNodeIndex* pNodeIndex = m_pRedline->GetContentIdx(); + if(!pNodeIndex) + return nullptr; + SwPaM aPam(*pNodeIndex); + aPam.Move(fnMoveForward, GoInNode); + auto pUnoCursor(GetDoc()->CreateUnoCursor(*aPam.Start())); + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Redline); +} + +uno::Type SwXRedline::getElementType( ) +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SwXRedline::hasElements( ) +{ + if(!m_pDoc) + throw uno::RuntimeException(); + return nullptr != m_pRedline->GetContentIdx(); +} + +rtl::Reference< SwXTextCursor > SwXRedline::createXTextCursor() +{ + if(!m_pDoc) + throw uno::RuntimeException(); + + const SwNodeIndex* pNodeIndex = m_pRedline->GetContentIdx(); + if(!pNodeIndex) + { + throw uno::RuntimeException(); + } + + SwPosition aPos(*pNodeIndex); + rtl::Reference<SwXTextCursor> pXCursor = + new SwXTextCursor(*m_pDoc, this, CursorType::Redline, aPos); + auto& rUnoCursor(pXCursor->GetCursor()); + rUnoCursor.Move(fnMoveForward, GoInNode); + + // is here a table? + SwTableNode* pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + while( pTableNode ) + { + rUnoCursor.GetPoint()->Assign( *pTableNode->EndOfSectionNode() ); + SwContentNode* pCont = GetDoc()->GetNodes().GoNext(rUnoCursor.GetPoint()); + pTableNode = pCont->FindTableNode(); + } + + return pXCursor; +} + +rtl::Reference< SwXTextCursor > SwXRedline::createXTextCursorByRange( + const uno::Reference< text::XTextRange > & /*aTextPosition*/) +{ + throw uno::RuntimeException(); +} + +uno::Any SwXRedline::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet = SwXText::queryInterface(rType); + if(!aRet.hasValue()) + { + aRet = SwXRedlineBaseClass::queryInterface(rType); + } + return aRet; +} + +uno::Sequence<uno::Type> SwXRedline::getTypes() +{ + return comphelper::concatSequences( + SwXText::getTypes(), + SwXRedlineBaseClass::getTypes() + ); +} + +uno::Sequence<sal_Int8> SwXRedline::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoredlines.cxx b/sw/source/core/unocore/unoredlines.cxx new file mode 100644 index 0000000000..315513632d --- /dev/null +++ b/sw/source/core/unocore/unoredlines.cxx @@ -0,0 +1,162 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <cppuhelper/supportsservice.hxx> + +#include <vcl/svapp.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> + +#include <unoredlines.hxx> +#include <unoredline.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <docary.hxx> +#include <redline.hxx> + +using namespace ::com::sun::star; + +SwXRedlines::SwXRedlines(SwDoc* _pDoc) : + SwUnoCollection(_pDoc) +{ +} + +SwXRedlines::~SwXRedlines() +{ +} + +sal_Int32 SwXRedlines::getCount( ) +{ + SolarMutexGuard aGuard; + const SwRedlineTable& rRedTable = GetDoc().getIDocumentRedlineAccess().GetRedlineTable(); + return rRedTable.size(); +} + +uno::Any SwXRedlines::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + auto& rDoc = GetDoc(); + const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + if ((nIndex < 0) || (rRedTable.size() <= o3tl::make_unsigned(nIndex))) + throw lang::IndexOutOfBoundsException(); + + uno::Reference<beans::XPropertySet> xRet = SwXRedlines::GetObject(*rRedTable[nIndex], rDoc); + return uno::Any(xRet); +} + +uno::Reference< container::XEnumeration > SwXRedlines::createEnumeration() +{ + SolarMutexGuard aGuard; + return uno::Reference< container::XEnumeration >(new SwXRedlineEnumeration(GetDoc())); +} + +uno::Type SwXRedlines::getElementType( ) +{ + return cppu::UnoType<beans::XPropertySet>::get(); +} + +sal_Bool SwXRedlines::hasElements( ) +{ + SolarMutexGuard aGuard; + const SwRedlineTable& rRedTable = GetDoc().getIDocumentRedlineAccess().GetRedlineTable(); + return !rRedTable.empty(); +} + +OUString SwXRedlines::getImplementationName() +{ + return "SwXRedlines"; +} + +sal_Bool SwXRedlines::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence< OUString > SwXRedlines::getSupportedServiceNames() +{ + OSL_FAIL("not implemented"); + return uno::Sequence< OUString >(); +} + +beans::XPropertySet* SwXRedlines::GetObject( SwRangeRedline& rRedline, SwDoc& rDoc ) +{ + SwXRedline* pXRedline(nullptr); + sw::FindRedlineHint aHint(rRedline, &pXRedline); + rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier().Broadcast(aHint); + return pXRedline ? pXRedline : new SwXRedline(rRedline, rDoc); +} + +SwXRedlineEnumeration::SwXRedlineEnumeration(SwDoc& rDoc) : + m_pDoc(&rDoc), + m_nCurrentIndex(0) +{ + StartListening(m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); +} + +SwXRedlineEnumeration::~SwXRedlineEnumeration() +{ +} + +sal_Bool SwXRedlineEnumeration::hasMoreElements() +{ + if(!m_pDoc) + throw uno::RuntimeException(); + return m_pDoc->getIDocumentRedlineAccess().GetRedlineTable().size() > m_nCurrentIndex; +} + +uno::Any SwXRedlineEnumeration::nextElement() +{ + if(!m_pDoc) + throw uno::RuntimeException(); + const SwRedlineTable& rRedTable = m_pDoc->getIDocumentRedlineAccess().GetRedlineTable(); + if( rRedTable.size() <= m_nCurrentIndex ) + throw container::NoSuchElementException(); + uno::Reference <beans::XPropertySet> xRet = SwXRedlines::GetObject( *rRedTable[m_nCurrentIndex++], *m_pDoc ); + uno::Any aRet; + aRet <<= xRet; + return aRet; +} + +OUString SwXRedlineEnumeration::getImplementationName() +{ + return "SwXRedlineEnumeration"; +} + +sal_Bool SwXRedlineEnumeration::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence< OUString > SwXRedlineEnumeration::getSupportedServiceNames() +{ + return uno::Sequence< OUString >(); +} + +void SwXRedlineEnumeration::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pDoc = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unorefmk.cxx b/sw/source/core/unocore/unorefmk.cxx new file mode 100644 index 0000000000..43b0690ecb --- /dev/null +++ b/sw/source/core/unocore/unorefmk.cxx @@ -0,0 +1,1475 @@ +/* -*- 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 <memory> +#include <utility> + +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <sal/config.h> +#include <svl/listener.hxx> +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include <unotextrange.hxx> +#include <unorefmark.hxx> +#include <unotextcursor.hxx> +#include <unomap.hxx> +#include <unocrsrhelper.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <fmtrfmrk.hxx> +#include <txtrfmrk.hxx> +#include <unometa.hxx> +#include <unotext.hxx> +#include <unoport.hxx> +#include <txtatr.hxx> +#include <fmtmeta.hxx> +#include <docsh.hxx> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/rdf/Statement.hpp> +#include <com/sun/star/rdf/URI.hpp> +#include <com/sun/star/rdf/URIs.hpp> +#include <com/sun/star/rdf/XLiteral.hpp> +#include <com/sun/star/rdf/XRepositorySupplier.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +using namespace ::com::sun::star; + +class SwXReferenceMark::Impl + : public SvtListener +{ +public: + unotools::WeakReference<SwXReferenceMark> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + bool m_bIsDescriptor; + SwDoc* m_pDoc; + const SwFormatRefMark* m_pMarkFormat; + OUString m_sMarkName; + + Impl(SwDoc* const pDoc, SwFormatRefMark* const pRefMark) + : m_bIsDescriptor(nullptr == pRefMark) + , m_pDoc(pDoc) + , m_pMarkFormat(pRefMark) + { + if (pRefMark) + { + StartListening(pRefMark->GetNotifier()); + m_sMarkName = pRefMark->GetRefName(); + } + } + + bool IsValid() const { return m_pMarkFormat; } + void InsertRefMark( SwPaM & rPam, SwXTextCursor const*const pCursor ); + void Invalidate(); +protected: + virtual void Notify(const SfxHint&) override; + +}; + +void SwXReferenceMark::Impl::Invalidate() +{ + EndListeningAll(); + m_pDoc = nullptr; + m_pMarkFormat = nullptr; + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +void SwXReferenceMark::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + Invalidate(); +} + +SwXReferenceMark::SwXReferenceMark( + SwDoc *const pDoc, SwFormatRefMark *const pRefMark) + : m_pImpl( new SwXReferenceMark::Impl(pDoc, pRefMark) ) +{ +} + +SwXReferenceMark::~SwXReferenceMark() +{ +} + +rtl::Reference<SwXReferenceMark> +SwXReferenceMark::CreateXReferenceMark( + SwDoc & rDoc, SwFormatRefMark *const pMarkFormat) +{ + // i#105557: do not iterate over the registered clients: race condition + rtl::Reference<SwXReferenceMark> xMark; + if (pMarkFormat) + { + xMark = pMarkFormat->GetXRefMark(); + } + if (!xMark.is()) + { + xMark = new SwXReferenceMark(&rDoc, pMarkFormat); + if (pMarkFormat) + { + pMarkFormat->SetXRefMark(xMark); + } + // need a permanent Reference to initialize m_wThis + xMark->m_pImpl->m_wThis = xMark.get(); + } + return xMark; +} + +OUString SAL_CALL SwXReferenceMark::getImplementationName() +{ + return "SwXReferenceMark"; +} + +sal_Bool SAL_CALL +SwXReferenceMark::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXReferenceMark::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.ReferenceMark" + }; +} + +namespace { + +template<typename T> struct NotContainedIn +{ + std::vector<T> const& m_rVector; + explicit NotContainedIn(std::vector<T> const& rVector) + : m_rVector(rVector) { } + bool operator() (T const& rT) { + return std::find(m_rVector.begin(), m_rVector.end(), rT) + == m_rVector.end(); + } +}; + +} + +void SwXReferenceMark::Impl::InsertRefMark(SwPaM& rPam, + SwXTextCursor const*const pCursor) +{ + //! in some cases when this function is called the pDoc pointer member may have become + //! invalid/deleted thus we obtain the document pointer from rPaM where it should always + //! be valid. + SwDoc& rDoc2 = rPam.GetDoc(); + + UnoActionContext aCont(&rDoc2); + SwFormatRefMark aRefMark(m_sMarkName); + bool bMark = *rPam.GetPoint() != *rPam.GetMark(); + + const bool bForceExpandHints( !bMark && pCursor && pCursor->IsAtEndOfMeta() ); + const SetAttrMode nInsertFlags = bForceExpandHints + ? ( SetAttrMode::FORCEHINTEXPAND + | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND; + + std::vector<SwTextAttr *> oldMarks; + if (bMark) + { + oldMarks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK); + } + + rDoc2.getIDocumentContentOperations().InsertPoolItem( rPam, aRefMark, nInsertFlags ); + + if( bMark && *rPam.GetPoint() > *rPam.GetMark()) + { + rPam.Exchange(); + } + + // aRefMark was copied into the document pool; now retrieve real format... + SwTextAttr * pTextAttr(nullptr); + if (bMark) + { + // #i107672# + // ensure that we do not retrieve a different mark at the same position + std::vector<SwTextAttr *> const newMarks( + rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK)); + std::vector<SwTextAttr *>::const_iterator const iter( + std::find_if(newMarks.begin(), newMarks.end(), + NotContainedIn<SwTextAttr *>(oldMarks))); + assert(newMarks.end() != iter); + if (newMarks.end() != iter) + { + pTextAttr = *iter; + } + } + else + { + SwTextNode *pTextNd = rPam.GetPointNode().GetTextNode(); + assert(pTextNd); + pTextAttr = pTextNd ? rPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt( + rPam.GetPoint()->GetContentIndex() - 1, RES_TXTATR_REFMARK) : nullptr; + } + + if (!pTextAttr) + { + throw uno::RuntimeException( + "SwXReferenceMark::InsertRefMark(): cannot insert attribute", nullptr); + } + + m_pMarkFormat = &pTextAttr->GetRefMark(); + EndListeningAll(); + StartListening(const_cast<SwFormatRefMark*>(m_pMarkFormat)->GetNotifier()); +} + +void SAL_CALL +SwXReferenceMark::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + SwDoc *const pDocument = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDocument) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pDocument); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + m_pImpl->InsertRefMark(aPam, dynamic_cast<SwXTextCursor*>(pCursor)); + m_pImpl->m_bIsDescriptor = false; + m_pImpl->m_pDoc = pDocument; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXReferenceMark::getAnchor() +{ + SolarMutexGuard aGuard; + + if (m_pImpl->IsValid()) + { + SwFormatRefMark const*const pNewMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat)) + { + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + std::optional<SwPaM> pPam; + if ( pTextMark->End() ) + pPam.emplace( rTextNode, *pTextMark->End(), + rTextNode, pTextMark->GetStart()); + else + pPam.emplace( rTextNode, pTextMark->GetStart()); + + return SwXTextRange::CreateXTextRange( + *m_pImpl->m_pDoc, *pPam->Start(), pPam->End()); + } + } + } + return nullptr; +} + +void SAL_CALL SwXReferenceMark::dispose() +{ + SolarMutexGuard aGuard; + if (m_pImpl->IsValid()) + { + SwFormatRefMark const*const pNewMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat)) + { + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + const sal_Int32 nStt = pTextMark->GetStart(); + const sal_Int32 nEnd = pTextMark->End() + ? *pTextMark->End() + : nStt + 1; + + SwPaM aPam( rTextNode, nStt, rTextNode, nEnd ); + m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin( aPam ); + } + } + } + else if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->Invalidate(); + } +} + +void SAL_CALL SwXReferenceMark::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXReferenceMark::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +OUString SAL_CALL SwXReferenceMark::getName() +{ + SolarMutexGuard aGuard; + if (!m_pImpl->IsValid() || + !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName)) + { + throw uno::RuntimeException(); + } + return m_pImpl->m_sMarkName; +} + +void SAL_CALL SwXReferenceMark::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_sMarkName = rName; + } + else + { + if (!m_pImpl->IsValid() + || !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName) + || m_pImpl->m_pDoc->GetRefMark(rName)) + { + throw uno::RuntimeException(); + } + SwFormatRefMark const*const pCurMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if ((rName != m_pImpl->m_sMarkName) + && pCurMark && SfxPoolItem::areSame(pCurMark, m_pImpl->m_pMarkFormat)) + { + const UnoActionContext aCont(m_pImpl->m_pDoc); + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + const sal_Int32 nStt = pTextMark->GetStart(); + const sal_Int32 nEnd = pTextMark->End() + ? *pTextMark->End() + : nStt + 1; + + SwPaM aPam( rTextNode, nStt, rTextNode, nEnd ); + // deletes the m_pImpl->m_pDoc member in the SwXReferenceMark! + m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin( aPam ); + // The aPam will keep the correct and functional doc though + + m_pImpl->m_sMarkName = rName; + //create a new one + m_pImpl->InsertRefMark( aPam, nullptr ); + m_pImpl->m_pDoc = &aPam.GetDoc(); + } + } + } +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXReferenceMark::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH_EXTENSIONS) + ->getPropertySetInfo(); + return xRef; +} + +void SAL_CALL SwXReferenceMark::setPropertyValue( + const OUString& /*rPropertyName*/, const uno::Any& /*rValue*/ ) +{ + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL +SwXReferenceMark::getPropertyValue(const OUString& rPropertyName) +{ + // does not seem to need SolarMutex + uno::Any aRet; + if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + throw beans::UnknownPropertyException(rPropertyName); + } + return aRet; +} + +void SAL_CALL SwXReferenceMark::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::removeVetoableChangeListener(): not implemented"); +} + +namespace { + +class SwXMetaText : public cppu::OWeakObject, public SwXText +{ +private: + SwXMeta & m_rMeta; + + virtual void PrepareForAttach(uno::Reference< text::XTextRange > & xRange, + const SwPaM & rPam) override; + + virtual bool CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) override; + +protected: + virtual const SwStartNode *GetStartNode() const override; + +public: + SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta); + + /// make available for SwXMeta + using SwXText::Invalidate; + + // XInterface + virtual void SAL_CALL acquire() noexcept override { cppu::OWeakObject::acquire(); } + virtual void SAL_CALL release() noexcept override { cppu::OWeakObject::release(); } + + // XTypeProvider + virtual uno::Sequence< sal_Int8 > SAL_CALL + getImplementationId() override; + + // XText + virtual rtl::Reference< SwXTextCursor > createXTextCursor() override; + virtual rtl::Reference< SwXTextCursor > createXTextCursorByRange( + const ::css::uno::Reference< ::css::text::XTextRange >& aTextPosition ) override; +}; + +} + +SwXMetaText::SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta) + : SwXText(&rDoc, CursorType::Meta) + , m_rMeta(rMeta) +{ +} + +const SwStartNode *SwXMetaText::GetStartNode() const +{ + SwXText const * const pParent = m_rMeta.GetParentText().get(); + return pParent ? pParent->GetStartNode() : nullptr; +} + +void SwXMetaText::PrepareForAttach( uno::Reference<text::XTextRange> & xRange, + const SwPaM & rPam) +{ + // create a new cursor to prevent modifying SwXTextRange + xRange = static_cast<text::XWordCursor*>( + new SwXTextCursor(*GetDoc(), &m_rMeta, CursorType::Meta, *rPam.GetPoint(), + (rPam.HasMark()) ? rPam.GetMark() : nullptr)); +} + +bool SwXMetaText::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) +{ + return m_rMeta.CheckForOwnMemberMeta(rPam, bAbsorb); +} + +rtl::Reference< SwXTextCursor > SwXMetaText::createXTextCursor() +{ + rtl::Reference< SwXTextCursor > xRet; + if (IsValid()) + { + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess( + m_rMeta.SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + if (bSuccess) + { + SwPosition aPos(*pTextNode, nMetaStart); + xRet = new SwXTextCursor(*GetDoc(), &m_rMeta, CursorType::Meta, aPos); + } + } + return xRet; +} + +uno::Sequence<sal_Int8> SAL_CALL +SwXMetaText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XText + +rtl::Reference< SwXTextCursor > +SwXMetaText::createXTextCursorByRange( + const uno::Reference<text::XTextRange> & xTextPosition) +{ + const rtl::Reference< SwXTextCursor > xCursor( createXTextCursor() ); + xCursor->gotoRange(xTextPosition, false); + return xCursor; +} + +/** + * the Meta has a cached list of text portions for its contents + * this list is created by SwXTextPortionEnumeration + * the Meta listens at the SwTextNode and throws away the cache when it changes + * + * This inner part of SwXMeta is deleted with a locked SolarMutex. + */ +class SwXMeta::Impl : public SvtListener +{ +public: + unotools::WeakReference<SwXMeta> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + std::unique_ptr<const TextRangeList_t> m_pTextPortions; + // 3 possible states: not attached, attached, disposed + bool m_bIsDisposed; + bool m_bIsDescriptor; + css::uno::Reference<SwXText> m_xParentText; + rtl::Reference<SwXMetaText> m_xText; + sw::Meta* m_pMeta; + + Impl(SwXMeta& rThis, SwDoc& rDoc, + ::sw::Meta* const pMeta, + css::uno::Reference<SwXText> xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : m_pTextPortions(std::move(pPortions)) + , m_bIsDisposed(false) + , m_bIsDescriptor(nullptr == pMeta) + , m_xParentText(std::move(xParentText)) + , m_xText(new SwXMetaText(rDoc, rThis)) + , m_pMeta(pMeta) + { + !m_bIsDescriptor && StartListening(m_pMeta->GetNotifier()); + } + + inline const ::sw::Meta* GetMeta() const; + // only for SwXMetaField! + inline const ::sw::MetaField* GetMetaField() const; +protected: + virtual void Notify(const SfxHint& rHint) override; + +}; + +inline const ::sw::Meta* SwXMeta::Impl::GetMeta() const +{ + return m_pMeta; +} + +// sw::BroadcastingModify +void SwXMeta::Impl::Notify(const SfxHint& rHint) +{ + m_pTextPortions.reset(); // throw away cache (SwTextNode changed) + if(rHint.GetId() != SfxHintId::Dying && rHint.GetId() != SfxHintId::Deinitializing) + return; + + m_bIsDisposed = true; + m_pMeta = nullptr; + m_xText->Invalidate(); + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +css::uno::Reference<SwXText> const & SwXMeta::GetParentText() const +{ + return m_pImpl->m_xParentText; +} + +SwXMeta::SwXMeta(SwDoc *const pDoc, ::sw::Meta *const pMeta, + css::uno::Reference<SwXText> const& xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : m_pImpl( new SwXMeta::Impl(*this, *pDoc, pMeta, xParentText, std::move(pPortions)) ) +{ +} + +SwXMeta::SwXMeta(SwDoc *const pDoc) + : m_pImpl( new SwXMeta::Impl(*this, *pDoc, nullptr, nullptr, nullptr) ) +{ +} + +SwXMeta::~SwXMeta() +{ +} + +rtl::Reference<SwXMeta> +SwXMeta::CreateXMeta(SwDoc & rDoc, bool const isField) +{ + // this is why the constructor is private: need to acquire pXMeta here + rtl::Reference<SwXMeta> xMeta(isField + ? new SwXMetaField(& rDoc) : new SwXMeta(& rDoc)); + // need a permanent Reference to initialize m_wThis + xMeta->m_pImpl->m_wThis = xMeta.get(); + return xMeta; +} + +rtl::Reference<SwXMeta> +SwXMeta::CreateXMeta(::sw::Meta & rMeta, + css::uno::Reference<SwXText> i_xParent, + std::unique_ptr<TextRangeList_t const> && pPortions) +{ + // re-use existing SwXMeta + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXMeta> xMeta(rMeta.GetXMeta()); + if (xMeta.is()) + { + if (pPortions) // set cache in the XMeta to the given portions + { + // NB: the meta must always be created with the complete content + // if SwXTextPortionEnumeration is created for a selection, + // it must be checked that the Meta is contained in the selection! + xMeta->m_pImpl->m_pTextPortions = std::move(pPortions); + // ??? is this necessary? + if (xMeta->m_pImpl->m_xParentText.get() != i_xParent.get()) + { + SAL_WARN("sw.uno", "SwXMeta with different parent?"); + xMeta->m_pImpl->m_xParentText = i_xParent; + } + } + return xMeta; + } + + // create new SwXMeta + SwTextNode * const pTextNode( rMeta.GetTextNode() ); + SAL_WARN_IF(!pTextNode, "sw.uno", "CreateXMeta: no text node?"); + if (!pTextNode) { return nullptr; } + css::uno::Reference<SwXText> xParentText(i_xParent); + if (!xParentText.is()) + { + SwTextMeta * const pTextAttr( rMeta.GetTextAttr() ); + SAL_WARN_IF(!pTextAttr, "sw.uno", "CreateXMeta: no text attr?"); + if (!pTextAttr) { return nullptr; } + const SwPosition aPos(*pTextNode, pTextAttr->GetStart()); + xParentText = ::sw::CreateParentXText(pTextNode->GetDoc(), aPos); + } + if (!xParentText.is()) { return nullptr; } + // this is why the constructor is private: need to acquire pXMeta here + xMeta = (RES_TXTATR_META == rMeta.GetFormatMeta()->Which()) + ? new SwXMeta (&pTextNode->GetDoc(), &rMeta, xParentText, + std::move(pPortions)) + : new SwXMetaField(&pTextNode->GetDoc(), &rMeta, xParentText, + std::move(pPortions)); + // in order to initialize the weak pointer cache in the core object + rMeta.SetXMeta(xMeta); + // need a permanent Reference to initialize m_wThis + xMeta->m_pImpl->m_wThis = xMeta.get(); + return xMeta; +} + +bool SwXMeta::SetContentRange( + SwTextNode *& rpNode, sal_Int32 & rStart, sal_Int32 & rEnd ) const +{ + ::sw::Meta const * const pMeta( m_pImpl->GetMeta() ); + if (pMeta) + { + SwTextMeta const * const pTextAttr( pMeta->GetTextAttr() ); + if (pTextAttr) + { + rpNode = pMeta->GetTextNode(); + if (rpNode) + { + // rStart points at the first position _within_ the meta! + rStart = pTextAttr->GetStart() + 1; + rEnd = *pTextAttr->End(); + return true; + } + } + } + return false; +} + +bool SwXMeta::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) +{ + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess( SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + throw lang::DisposedException(); + + SwPosition const * const pStartPos( rPam.Start() ); + if (&pStartPos->GetNode() != pTextNode) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but start " + "of text range not in same paragraph as text content", + nullptr, 0); + } + bool bForceExpandHints(false); + const sal_Int32 nStartPos(pStartPos->GetContentIndex()); + // not <= but < because nMetaStart is behind dummy char! + // not >= but > because == means insert at end! + if ((nStartPos < nMetaStart) || (nStartPos > nMetaEnd)) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but start " + "of text range not inside text content", + nullptr, 0); + } + else if (nStartPos == nMetaEnd) + { + bForceExpandHints = true; + } + if (rPam.HasMark() && bAbsorb) + { + SwPosition const * const pEndPos( rPam.End() ); + if (&pEndPos->GetNode() != pTextNode) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but end " + "of text range not in same paragraph as text content", + nullptr, 0); + } + const sal_Int32 nEndPos(pEndPos->GetContentIndex()); + // not <= but < because nMetaStart is behind dummy char! + // not >= but > because == means insert at end! + if ((nEndPos < nMetaStart) || (nEndPos > nMetaEnd)) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but end " + "of text range not inside text content", + nullptr, 0); + } + else if (nEndPos == nMetaEnd) + { + bForceExpandHints = true; + } + } + return bForceExpandHints; +} + +// XServiceInfo +OUString SAL_CALL +SwXMeta::getImplementationName() +{ + return "SwXMeta"; +} + +sal_Bool SAL_CALL +SwXMeta::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXMeta::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.InContentMetadata" + }; +} + +// XComponent +void SAL_CALL +SwXMeta::addEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL +SwXMeta::removeEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +void SAL_CALL +SwXMeta::dispose() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pTextPortions.reset(); + lang::EventObject const ev(getXWeak()); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard, ev); + m_pImpl->m_bIsDisposed = true; + m_pImpl->m_xText->Invalidate(); + } + else if (!m_pImpl->m_bIsDisposed) + { + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (bSuccess) + { + // -1 because of CH_TXTATR + SwPaM aPam( *pTextNode, nMetaStart - 1, *pTextNode, nMetaEnd ); + SwDoc& rDoc( pTextNode->GetDoc() ); + rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); + + // removal should call Modify and do the dispose + assert(m_pImpl->m_bIsDisposed); + } + } +} + +void +SwXMeta::AttachImpl(const uno::Reference< text::XTextRange > & i_xTextRange, + const sal_uInt16 i_nWhich) +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "SwXMeta::attach(): already attached", + getXWeak()); + } + + SwXTextRange *const pRange(dynamic_cast<SwXTextRange*>(i_xTextRange.get())); + OTextCursorHelper *const pCursor(dynamic_cast<OTextCursorHelper*>(i_xTextRange.get())); + if (!pRange && !pCursor) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): argument not supported type", + getXWeak(), 0); + } + + SwDoc * const pDoc( + pRange ? &pRange->GetDoc() : pCursor->GetDoc()); + if (!pDoc) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): argument has no SwDoc", + getXWeak(), 0); + } + + SwUnoInternalPaM aPam(*pDoc); + ::sw::XTextRangeToSwPaM(aPam, i_xTextRange); + + UnoActionContext aContext(pDoc); + + SwXTextCursor const*const pTextCursor( + dynamic_cast<SwXTextCursor*>(pCursor)); + const bool bForceExpandHints(pTextCursor && pTextCursor->IsAtEndOfMeta()); + const SetAttrMode nInsertFlags( bForceExpandHints + ? ( SetAttrMode::FORCEHINTEXPAND + | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND ); + + const std::shared_ptr< ::sw::Meta> pMeta( (RES_TXTATR_META == i_nWhich) + ? std::make_shared< ::sw::Meta>( nullptr ) + : std::shared_ptr< ::sw::Meta>( + pDoc->GetMetaFieldManager().makeMetaField()) ); + SwFormatMeta meta(pMeta, i_nWhich); // this is cloned by Insert! + const bool bSuccess( pDoc->getIDocumentContentOperations().InsertPoolItem( aPam, meta, nInsertFlags ) ); + SwTextAttr * const pTextAttr( pMeta->GetTextAttr() ); + if (!bSuccess) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): cannot create meta: range invalid?", + getXWeak(), 1); + } + if (!pTextAttr) + { + OSL_FAIL("meta inserted, but has no text attribute?"); + throw uno::RuntimeException( + "SwXMeta::attach(): cannot create meta", + getXWeak()); + } + + m_pImpl->EndListeningAll(); + m_pImpl->m_pMeta = pMeta.get(); + m_pImpl->StartListening(pMeta->GetNotifier()); + pMeta->SetXMeta(this); + + m_pImpl->m_xParentText = ::sw::CreateParentXText(*pDoc, *aPam.GetPoint()); + + m_pImpl->m_bIsDescriptor = false; +} + +// XTextContent +void SAL_CALL +SwXMeta::attach(const uno::Reference< text::XTextRange > & i_xTextRange) +{ + return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_META); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getAnchor() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "SwXMeta::getAnchor(): not inserted", + getXWeak()); + } + + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + { + throw lang::DisposedException( + "SwXMeta::getAnchor(): not attached", + getXWeak()); + } + + const SwPosition start(*pTextNode, nMetaStart - 1); // -1 due to CH_TXTATR + const SwPosition end(*pTextNode, nMetaEnd); + return SwXTextRange::CreateXTextRange(pTextNode->GetDoc(), start, &end); +} + +// XTextRange +uno::Reference< text::XText > SAL_CALL +SwXMeta::getText() +{ + return this; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getStart() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getEnd() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getEnd(); +} + +OUString SAL_CALL +SwXMeta::getString() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getString(); +} + +void SAL_CALL +SwXMeta::setString(const OUString& rString) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->setString(rString); +} + +// XSimpleText +uno::Reference< text::XTextCursor > SAL_CALL +SwXMeta::createTextCursor() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursor(); +} + +uno::Reference< text::XTextCursor > SAL_CALL +SwXMeta::createTextCursorByRange( + const uno::Reference<text::XTextRange> & xTextPosition) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursorByRange(xTextPosition); +} + +void SAL_CALL +SwXMeta::insertString(const uno::Reference<text::XTextRange> & xRange, + const OUString& rString, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertString(xRange, rString, bAbsorb); +} + +void SAL_CALL +SwXMeta::insertControlCharacter(const uno::Reference<text::XTextRange> & xRange, + sal_Int16 nControlCharacter, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertControlCharacter(xRange, nControlCharacter, + bAbsorb); +} + +// XText +void SAL_CALL +SwXMeta::insertTextContent( const uno::Reference<text::XTextRange> & xRange, + const uno::Reference<text::XTextContent> & xContent, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertTextContent(xRange, xContent, bAbsorb); +} + +void SAL_CALL +SwXMeta::removeTextContent( + const uno::Reference< text::XTextContent > & xContent) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->removeTextContent(xContent); +} + +// XChild +uno::Reference< uno::XInterface > SAL_CALL +SwXMeta::getParent() +{ + SolarMutexGuard g; + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + bool const bSuccess( SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) { throw lang::DisposedException(); } + // in order to prevent getting this meta, subtract 1 from nMetaStart; + // so we get the index of the dummy character, and we exclude it + // by calling GetTextAttrAt(_, _, PARENT) in GetNestedTextContent + uno::Reference<text::XTextContent> const xRet( + SwUnoCursorHelper::GetNestedTextContent(*pTextNode, nMetaStart - 1, + true) ); + return xRet; +} + +void SAL_CALL +SwXMeta::setParent(uno::Reference< uno::XInterface > const& /*xParent*/) +{ + throw lang::NoSupportException("setting parent not supported", *this); +} + +// XElementAccess +uno::Type SAL_CALL +SwXMeta::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXMeta::hasElements() +{ + SolarMutexGuard g; + return m_pImpl->m_pMeta != nullptr; +} + +// XEnumerationAccess +uno::Reference< container::XEnumeration > SAL_CALL +SwXMeta::createEnumeration() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "createEnumeration(): not inserted", + getXWeak()); + } + + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + throw lang::DisposedException(); + + SwPaM aPam(*pTextNode, nMetaStart); + + if (!m_pImpl->m_pTextPortions) + { + return new SwXTextPortionEnumeration( + aPam, GetParentText(), nMetaStart, nMetaEnd); + } + else // cached! + { + return new SwXTextPortionEnumeration(aPam, std::deque(*m_pImpl->m_pTextPortions)); + } +} + +// MetadatableMixin +::sfx2::Metadatable* SwXMeta::GetCoreObject() +{ + return const_cast< ::sw::Meta * >(m_pImpl->GetMeta()); +} + +uno::Reference<frame::XModel> SwXMeta::GetModel() +{ + ::sw::Meta const * const pMeta( m_pImpl->GetMeta() ); + if (pMeta) + { + SwTextNode const * const pTextNode( pMeta->GetTextNode() ); + if (pTextNode) + { + SwDocShell const * const pShell(pTextNode->GetDoc().GetDocShell()); + return pShell ? pShell->GetModel() : nullptr; + } + } + return nullptr; +} + +inline const ::sw::MetaField* SwXMeta::Impl::GetMetaField() const +{ + return dynamic_cast<sw::MetaField*>(m_pMeta); +} + +SwXMetaField::SwXMetaField(SwDoc *const pDoc, ::sw::Meta *const pMeta, + css::uno::Reference<SwXText> const& xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : SwXMetaField_Base(pDoc, pMeta, xParentText, std::move(pPortions)) +{ + assert(dynamic_cast< ::sw::MetaField* >(pMeta) && "SwXMetaField created for wrong hint!"); +} + +SwXMetaField::SwXMetaField(SwDoc *const pDoc) + : SwXMetaField_Base(pDoc) +{ +} + +SwXMetaField::~SwXMetaField() +{ +} + +// XServiceInfo +OUString SAL_CALL +SwXMetaField::getImplementationName() +{ + return "SwXMetaField"; +} + +sal_Bool SAL_CALL +SwXMetaField::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXMetaField::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.TextField", + "com.sun.star.text.textfield.MetadataField" + }; +} + +// XComponent +void SAL_CALL +SwXMetaField::addEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + return SwXMeta::addEventListener(xListener); +} + +void SAL_CALL +SwXMetaField::removeEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + return SwXMeta::removeEventListener(xListener); +} + +void SAL_CALL +SwXMetaField::dispose() +{ + return SwXMeta::dispose(); +} + +// XTextContent +void SAL_CALL +SwXMetaField::attach(const uno::Reference< text::XTextRange > & i_xTextRange) +{ + return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_METAFIELD); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMetaField::getAnchor() +{ + return SwXMeta::getAnchor(); +} + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXMetaField::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef( + aSwMapProvider.GetPropertySet(PROPERTY_MAP_METAFIELD) + ->getPropertySetInfo() ); + return xRef; +} + +void SAL_CALL +SwXMetaField::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard g; + + ::sw::MetaField * const pMeta( + const_cast< ::sw::MetaField * >(m_pImpl->GetMetaField()) ); + if (!pMeta) + throw lang::DisposedException(); + + if ( rPropertyName == "NumberFormat" ) + { + sal_Int32 nNumberFormat(0); + if (rValue >>= nNumberFormat) + { + pMeta->SetNumberFormat(static_cast<sal_uInt32>(nNumberFormat)); + } + } + else if ( rPropertyName == "IsFixedLanguage" ) + { + bool b(false); + if (rValue >>= b) + { + pMeta->SetIsFixedLanguage(b); + } + } + else + { + throw beans::UnknownPropertyException(rPropertyName); + } +} + +uno::Any SAL_CALL +SwXMetaField::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + ::sw::MetaField const * const pMeta( m_pImpl->GetMetaField() ); + if (!pMeta) + throw lang::DisposedException(); + + uno::Any any; + + if ( rPropertyName == "NumberFormat" ) + { + const OUString text( getPresentation(false) ); + any <<= static_cast<sal_Int32>(pMeta->GetNumberFormat(text)); + } + else if ( rPropertyName == "IsFixedLanguage" ) + { + any <<= pMeta->IsFixedLanguage(); + } + else + { + throw beans::UnknownPropertyException(rPropertyName); + } + + return any; +} + +void SAL_CALL +SwXMetaField::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::removeVetoableChangeListener(): not implemented"); +} + +static uno::Reference<rdf::XURI> const& +lcl_getURI(const sal_Int16 eKnown) +{ + static uno::Reference< uno::XComponentContext > xContext( + ::comphelper::getProcessComponentContext()); + static uno::Reference< rdf::XURI > xOdfPrefix( + rdf::URI::createKnown(xContext, rdf::URIs::ODF_PREFIX), + uno::UNO_SET_THROW); + static uno::Reference< rdf::XURI > xOdfSuffix( + rdf::URI::createKnown(xContext, rdf::URIs::ODF_SUFFIX), + uno::UNO_SET_THROW); + static uno::Reference< rdf::XURI > xOdfShading( + rdf::URI::createKnown(xContext, rdf::URIs::LO_EXT_SHADING), + uno::UNO_SET_THROW); + switch (eKnown) + { + case rdf::URIs::ODF_PREFIX: + return xOdfPrefix; + case rdf::URIs::ODF_SUFFIX: + return xOdfSuffix; + default: + return xOdfShading; + } +} + +static OUString +lcl_getPrefixOrSuffix( + uno::Reference<rdf::XRepository> const & xRepository, + uno::Reference<rdf::XResource> const & xMetaField, + uno::Reference<rdf::XURI> const & xPredicate) +{ + const uno::Reference<container::XEnumeration> xEnum( + xRepository->getStatements(xMetaField, xPredicate, nullptr), + uno::UNO_SET_THROW); + while (xEnum->hasMoreElements()) { + rdf::Statement stmt; + if (!(xEnum->nextElement() >>= stmt)) { + throw uno::RuntimeException(); + } + const uno::Reference<rdf::XLiteral> xObject(stmt.Object, + uno::UNO_QUERY); + if (!xObject.is()) continue; + if (xEnum->hasMoreElements()) { + SAL_INFO("sw.uno", "ignoring other odf:Prefix/odf:Suffix statements"); + } + return xObject->getValue(); + } + return OUString(); +} + +void +getPrefixAndSuffix( + const uno::Reference<frame::XModel>& xModel, + const uno::Reference<rdf::XMetadatable>& xMetaField, + OUString *const o_pPrefix, OUString *const o_pSuffix, OUString *const o_pShadingColor) +{ + try { + const uno::Reference<rdf::XRepositorySupplier> xRS( + xModel, uno::UNO_QUERY_THROW); + const uno::Reference<rdf::XRepository> xRepo( + xRS->getRDFRepository(), uno::UNO_SET_THROW); + const uno::Reference<rdf::XResource> xMeta( + xMetaField, uno::UNO_QUERY_THROW); + if (o_pPrefix) + { + *o_pPrefix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::ODF_PREFIX)); + } + if (o_pSuffix) + { + *o_pSuffix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::ODF_SUFFIX)); + } + if (o_pShadingColor) + { + *o_pShadingColor = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::LO_EXT_SHADING)); + } + } catch (uno::RuntimeException &) { + throw; + } catch (const uno::Exception &) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("getPrefixAndSuffix: exception", nullptr, anyEx); + } +} + +// XTextField +OUString SAL_CALL +SwXMetaField::getPresentation(sal_Bool bShowCommand) +{ + SolarMutexGuard g; + + if (bShowCommand) + { +//FIXME ? + return OUString(); + } + else + { + // getString should check if this is invalid + const OUString content( getString() ); + OUString prefix; + OUString suffix; + getPrefixAndSuffix(GetModel(), this, &prefix, &suffix, nullptr); + return prefix + content + suffix; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unosect.cxx b/sw/source/core/unocore/unosect.cxx new file mode 100644 index 0000000000..4439862002 --- /dev/null +++ b/sw/source/core/unocore/unosect.cxx @@ -0,0 +1,1730 @@ +/* -*- 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 <memory> +#include <unosection.hxx> +#include <unotext.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/text/SectionFileLink.hpp> + +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <cmdid.h> +#include <hintids.hxx> +#include <svl/urihelper.hxx> +#include <svl/listener.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <sfx2/linkmgr.hxx> +#include <sfx2/lnkbase.hxx> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <fmtclds.hxx> +#include <unotextrange.hxx> +#include <TextCursorHelper.hxx> +#include <unoport.hxx> +#include <redline.hxx> +#include <unomap.hxx> +#include <section.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docsh.hxx> +#include <sfx2/docfile.hxx> +#include <docary.hxx> +#include <swundo.hxx> +#include <tox.hxx> +#include <unoidx.hxx> +#include <doctxm.hxx> +#include <fmtftntx.hxx> +#include <fmtclbl.hxx> +#include <editeng/frmdiritem.hxx> +#include <fmtcntnt.hxx> +#include <editeng/lrspitem.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <o3tl/string_view.hxx> + +using namespace ::com::sun::star; + +namespace { + +struct SwTextSectionProperties_Impl +{ + uno::Sequence<sal_Int8> m_Password; + OUString m_sCondition; + OUString m_sLinkFileName; + OUString m_sSectionFilter; + OUString m_sSectionRegion; + + std::unique_ptr<SwFormatCol> m_pColItem; + std::unique_ptr<SvxBrushItem> m_pBrushItem; + std::unique_ptr<SwFormatFootnoteAtTextEnd> m_pFootnoteItem; + std::unique_ptr<SwFormatEndAtTextEnd> m_pEndItem; + std::unique_ptr<SvXMLAttrContainerItem> m_pXMLAttr; + std::unique_ptr<SwFormatNoBalancedColumns> m_pNoBalanceItem; + std::unique_ptr<SvxFrameDirectionItem> m_pFrameDirItem; + std::unique_ptr<SvxLRSpaceItem> m_pLRSpaceItem; + + bool m_bDDE; + bool m_bHidden; + bool m_bCondHidden; + bool m_bProtect; + bool m_bEditInReadonly; + bool m_bUpdateType; + + SwTextSectionProperties_Impl() + : m_bDDE(false) + , m_bHidden(false) + , m_bCondHidden(false) + , m_bProtect(false) + , m_bEditInReadonly(false) + , m_bUpdateType(true) + { + } + +}; + +} + +class SwXTextSection::Impl + : public SvtListener +{ +public: + SwXTextSection & m_rThis; + unotools::WeakReference<SwXTextSection> m_wThis; + const SfxItemPropertySet & m_rPropSet; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + const bool m_bIndexHeader; + bool m_bIsDescriptor; + OUString m_sName; + std::unique_ptr<SwTextSectionProperties_Impl> m_pProps; + SwSectionFormat* m_pFormat; + + Impl( SwXTextSection& rThis, + SwSectionFormat* const pFormat, const bool bIndexHeader) + : m_rThis(rThis) + , m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_SECTION)) + , m_bIndexHeader(bIndexHeader) + , m_bIsDescriptor(nullptr == pFormat) + , m_pProps(pFormat ? nullptr : new SwTextSectionProperties_Impl()) + , m_pFormat(pFormat) + { + if(m_pFormat) + StartListening(m_pFormat->GetNotifier()); + } + + void Attach(SwSectionFormat* pFormat) + { + EndListeningAll(); + StartListening(pFormat->GetNotifier()); + m_pFormat = pFormat; + } + + SwSectionFormat* GetSectionFormat() const + { return m_pFormat; } + + SwSectionFormat & GetSectionFormatOrThrow() const { + SwSectionFormat *const pFormat( GetSectionFormat() ); + if (!pFormat) { + throw uno::RuntimeException("SwXTextSection: disposed or invalid", nullptr); + } + return *pFormat; + } + + /// @throws beans::UnknownPropertyException + /// @throws beans::PropertyVetoException, + /// @throws lang::IllegalArgumentException + /// @throws lang::WrappedTargetException, + /// @throws uno::RuntimeException + void SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& aValues); + /// @throws beans::UnknownPropertyException + /// @throws lang::WrappedTargetException, + /// @throws uno::RuntimeException + uno::Sequence< uno::Any > + GetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames); + virtual void Notify(const SfxHint& rHint) override; +}; + +void SwXTextSection::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pFormat = nullptr; + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); + } +} + +SwSectionFormat * SwXTextSection::GetFormat() const +{ + return m_pImpl->GetSectionFormat(); +} + +rtl::Reference< SwXTextSection > +SwXTextSection::CreateXTextSection( + SwSectionFormat *const pFormat, const bool bIndexHeader) +{ + // re-use existing SwXTextSection + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference< SwXTextSection > xSection; + if (pFormat) + { + xSection = pFormat->GetXTextSection(); + } + if ( !xSection.is() ) + { + rtl::Reference<SwXTextSection> pNew = new SwXTextSection(pFormat, bIndexHeader); + xSection = pNew; + if (pFormat) + { + pFormat->SetXTextSection(xSection); + } + // need a permanent Reference to initialize m_wThis + pNew->m_pImpl->m_wThis = xSection.get(); + } + return xSection; +} + +SwXTextSection::SwXTextSection( + SwSectionFormat *const pFormat, const bool bIndexHeader) + : m_pImpl( new SwXTextSection::Impl(*this, pFormat, bIndexHeader) ) +{ +} + +SwXTextSection::~SwXTextSection() +{ +} + +uno::Reference< text::XTextSection > SAL_CALL +SwXTextSection::getParentSection() +{ + SolarMutexGuard aGuard; + + SwSectionFormat & rSectionFormat( m_pImpl->GetSectionFormatOrThrow() ); + + SwSectionFormat *const pParentFormat = rSectionFormat.GetParent(); + const uno::Reference< text::XTextSection > xRet = + pParentFormat ? CreateXTextSection(pParentFormat) : nullptr; + return xRet; +} + +uno::Sequence< uno::Reference< text::XTextSection > > SAL_CALL +SwXTextSection::getChildSections() +{ + SolarMutexGuard aGuard; + + SwSectionFormat & rSectionFormat( m_pImpl->GetSectionFormatOrThrow() ); + + SwSections aChildren; + rSectionFormat.GetChildSections(aChildren, SectionSort::Not, false); + uno::Sequence<uno::Reference<text::XTextSection> > aSeq(aChildren.size()); + uno::Reference< text::XTextSection > * pArray = aSeq.getArray(); + for (size_t i = 0; i < aChildren.size(); ++i) + { + SwSectionFormat *const pChild = aChildren[i]->GetFormat(); + pArray[i] = CreateXTextSection(pChild); + } + return aSeq; +} + +void SAL_CALL +SwXTextSection::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard g; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwDoc *const pDoc = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDoc) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pDoc); + // this has to return true now + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + UnoActionContext aCont(pDoc); + pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSSECTION, nullptr ); + + if (m_pImpl->m_sName.isEmpty()) + { + m_pImpl->m_sName = "TextSection"; + } + SectionType eType(SectionType::FileLink); + if( m_pImpl->m_pProps->m_bDDE ) + eType = SectionType::DdeLink; + else if( m_pImpl->m_pProps->m_sLinkFileName.isEmpty() && m_pImpl->m_pProps->m_sSectionRegion.isEmpty() ) + eType = SectionType::Content; + // index header section? + if (m_pImpl->m_bIndexHeader) + { + // caller wants an index header section, but will only + // give him one if a) we are inside an index, and b) said + // index doesn't yet have a header section. + const SwTOXBase* pBase = SwDoc::GetCurTOX(*aPam.Start()); + + // are we inside an index? + if (pBase) + { + // get all child sections + SwSections aSectionsArr; + static_cast<const SwTOXBaseSection*>(pBase)->GetFormat()-> + GetChildSections(aSectionsArr); + + // and search for current header section + const size_t nCount = aSectionsArr.size(); + bool bHeaderPresent = false; + for(size_t i = 0; i < nCount; ++i) + { + if (aSectionsArr[i]->GetType() == SectionType::ToxHeader) + bHeaderPresent = true; + } + if (! bHeaderPresent) + { + eType = SectionType::ToxHeader; + } + } + } + + SwSectionData aSect(eType, pDoc->GetUniqueSectionName(&m_pImpl->m_sName)); + aSect.SetCondition(m_pImpl->m_pProps->m_sCondition); + aSect.SetLinkFileName(m_pImpl->m_pProps->m_sLinkFileName + + OUStringChar(sfx2::cTokenSeparator) + + m_pImpl->m_pProps->m_sSectionFilter + + OUStringChar(sfx2::cTokenSeparator) + + m_pImpl->m_pProps->m_sSectionRegion); + + aSect.SetHidden(m_pImpl->m_pProps->m_bHidden); + aSect.SetProtectFlag(m_pImpl->m_pProps->m_bProtect); + aSect.SetEditInReadonlyFlag(m_pImpl->m_pProps->m_bEditInReadonly); + + SfxItemSetFixed< + RES_LR_SPACE, RES_LR_SPACE, + RES_BACKGROUND, RES_BACKGROUND, + RES_COL, RES_COL, + RES_FTN_AT_TXTEND, RES_FRAMEDIR, + RES_UNKNOWNATR_CONTAINER,RES_UNKNOWNATR_CONTAINER> + aSet(pDoc->GetAttrPool()); + if (m_pImpl->m_pProps->m_pBrushItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pBrushItem); + } + if (m_pImpl->m_pProps->m_pColItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pColItem); + } + if (m_pImpl->m_pProps->m_pFootnoteItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pFootnoteItem); + } + if (m_pImpl->m_pProps->m_pEndItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pEndItem); + } + if (m_pImpl->m_pProps->m_pXMLAttr) + { + aSet.Put(*m_pImpl->m_pProps->m_pXMLAttr); + } + if (m_pImpl->m_pProps->m_pNoBalanceItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pNoBalanceItem); + } + if (m_pImpl->m_pProps->m_pFrameDirItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pFrameDirItem); + } + if (m_pImpl->m_pProps->m_pLRSpaceItem) + { + aSet.Put(*m_pImpl->m_pProps->m_pLRSpaceItem); + } + // section password + if (m_pImpl->m_pProps->m_Password.hasElements()) + { + aSect.SetPassword(m_pImpl->m_pProps->m_Password); + } + + SwSection *const pRet = + pDoc->InsertSwSection( aPam, aSect, nullptr, aSet.Count() ? &aSet : nullptr ); + if (!pRet) // fdo#42450 text range could partially overlap existing section + { + // shouldn't have created an undo object yet + pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSSECTION, nullptr ); + throw lang::IllegalArgumentException( + "SwXTextSection::attach(): invalid TextRange", + getXWeak(), 0); + } + m_pImpl->Attach(pRet->GetFormat()); + pRet->GetFormat()->SetXObject(getXWeak()); + + // XML import must hide sections depending on their old + // condition status + if (!m_pImpl->m_pProps->m_sCondition.isEmpty()) + { + pRet->SetCondHidden(m_pImpl->m_pProps->m_bCondHidden); + } + + // set update type if DDE link (and connect, if necessary) + if (m_pImpl->m_pProps->m_bDDE) + { + if (! pRet->IsConnected()) + { + pRet->CreateLink(LinkCreateType::Connect); + } + pRet->SetUpdateType( m_pImpl->m_pProps->m_bUpdateType ? + SfxLinkUpdateMode::ALWAYS : SfxLinkUpdateMode::ONCALL ); + } + + // end the Undo bracketing here + pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSSECTION, nullptr ); + m_pImpl->m_pProps.reset(); + m_pImpl->m_bIsDescriptor = false; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXTextSection::getAnchor() +{ + SolarMutexGuard aGuard; + + rtl::Reference<SwXTextRange> xRet; + SwSectionFormat *const pSectFormat = m_pImpl->GetSectionFormat(); + if(pSectFormat) + { + const SwNodeIndex* pIdx; + if( nullptr != ( pSectFormat->GetSection() ) && + nullptr != ( pIdx = pSectFormat->GetContent().GetContentIdx() ) && + pIdx->GetNode().GetNodes().IsDocNodes() ) + { + bool isMoveIntoTable(false); + SwPaM aPaM(*pIdx); + aPaM.Move( fnMoveForward, GoInContent ); + assert(pIdx->GetNode().IsSectionNode()); + if (aPaM.GetPoint()->GetNode().FindTableNode() != pIdx->GetNode().FindTableNode() + || aPaM.GetPoint()->GetNode().FindSectionNode() != &pIdx->GetNode()) + { + isMoveIntoTable = true; + } + + const SwEndNode* pEndNode = pIdx->GetNode().EndOfSectionNode(); + SwPaM aEnd(*pEndNode); + aEnd.Move( fnMoveBackward, GoInContent ); + if (aEnd.GetPoint()->GetNode().FindTableNode() != pIdx->GetNode().FindTableNode() + || aEnd.GetPoint()->GetNode().FindSectionNode() != &pIdx->GetNode()) + { + isMoveIntoTable = true; + } + if (isMoveIntoTable) + { + css::uno::Reference<SwXText> const xParentText = + ::sw::CreateParentXText(*pSectFormat->GetDoc(), SwPosition(*pIdx)); + xRet = new SwXTextRange(*pSectFormat); + } + else // for compatibility, keep the old way in this case + { + xRet = SwXTextRange::CreateXTextRange(*pSectFormat->GetDoc(), + *aPaM.Start(), aEnd.Start()); + } + } + } + return xRet; +} + +void SAL_CALL SwXTextSection::dispose() +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pSectFormat = m_pImpl->GetSectionFormat(); + if (pSectFormat) + { + pSectFormat->GetDoc()->DelSectionFormat( pSectFormat ); + } +} + +void SAL_CALL SwXTextSection::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXTextSection::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXTextSection::getPropertySetInfo() +{ + SolarMutexGuard g; + return m_pImpl->m_rPropSet.getPropertySetInfo(); +} + +static void +lcl_UpdateLinkType(SwSection & rSection, bool const bLinkUpdateAlways) +{ + if (rSection.GetType() == SectionType::DdeLink) + { + // set update type; needs an established link + if (!rSection.IsConnected()) + { + rSection.CreateLink(LinkCreateType::Connect); + } + rSection.SetUpdateType( bLinkUpdateAlways + ? SfxLinkUpdateMode::ALWAYS : SfxLinkUpdateMode::ONCALL ); + } +} + +static void +lcl_UpdateSection(SwSectionFormat *const pFormat, + std::unique_ptr<SwSectionData> const& pSectionData, + std::optional<SfxItemSet> const& oItemSet, + bool const bLinkModeChanged, bool const bLinkUpdateAlways = true) +{ + if (!pFormat) + return; + + SwSection & rSection = *pFormat->GetSection(); + SwDoc *const pDoc = pFormat->GetDoc(); + SwSectionFormats const& rFormats = pDoc->GetSections(); + UnoActionContext aContext(pDoc); + for (size_t i = 0; i < rFormats.size(); ++i) + { + if (rFormats[i]->GetSection()->GetSectionName() + == rSection.GetSectionName()) + { + pDoc->UpdateSection(i, *pSectionData, oItemSet ? &*oItemSet : nullptr, + pDoc->IsInReading()); + { + // temporarily remove actions to allow cursor update + // TODO: why? no table cursor here! + UnoActionRemoveContext aRemoveContext( pDoc ); + } + + if (bLinkModeChanged) + { + lcl_UpdateLinkType(rSection, bLinkUpdateAlways); + } + // section found and processed: break from loop + break; + } + } +} + +void SwXTextSection::Impl::SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues) +{ + if(rPropertyNames.getLength() != rValues.getLength()) + { + throw lang::IllegalArgumentException(); + } + SwSectionFormat *const pFormat = GetSectionFormat(); + if (!pFormat && !m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + std::unique_ptr<SwSectionData> const pSectionData( + pFormat ? new SwSectionData(*pFormat->GetSection()) : nullptr); + + OUString const*const pPropertyNames = rPropertyNames.getConstArray(); + uno::Any const*const pValues = rValues.getConstArray(); + std::optional<SfxItemSet> oItemSet; + bool bLinkModeChanged = false; + bool bLinkMode = false; + + for (sal_Int32 nProperty = 0; nProperty < rPropertyNames.getLength(); + nProperty++) + { + SfxItemPropertyMapEntry const*const pEntry = + m_rPropSet.getPropertyMap().getByName(pPropertyNames[nProperty]); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + pPropertyNames[nProperty], + m_rThis.getXWeak()); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException( + "Property is read-only: " + pPropertyNames[nProperty], + m_rThis.getXWeak()); + } + switch (pEntry->nWID) + { + case WID_SECT_CONDITION: + { + OUString uTmp; + pValues[nProperty] >>= uTmp; + if (m_bIsDescriptor) + { + m_pProps->m_sCondition = uTmp; + } + else + { + pSectionData->SetCondition(uTmp); + } + } + break; + case WID_SECT_DDE_TYPE: + case WID_SECT_DDE_FILE: + case WID_SECT_DDE_ELEMENT: + { + OUString sTmp; + pValues[nProperty] >>= sTmp; + if (m_bIsDescriptor) + { + if (!m_pProps->m_bDDE) + { + m_pProps->m_sLinkFileName = + OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator); + m_pProps->m_bDDE = true; + } + m_pProps->m_sLinkFileName = comphelper::string::setToken( + m_pProps->m_sLinkFileName, + pEntry->nWID - WID_SECT_DDE_TYPE, sfx2::cTokenSeparator, sTmp); + } + else + { + OUString sLinkFileName(pSectionData->GetLinkFileName()); + if (pSectionData->GetType() != SectionType::DdeLink) + { + sLinkFileName = OUStringChar(sfx2::cTokenSeparator) + OUStringChar(sfx2::cTokenSeparator); + pSectionData->SetType(SectionType::DdeLink); + } + sLinkFileName = comphelper::string::setToken(sLinkFileName, + pEntry->nWID - WID_SECT_DDE_TYPE, + sfx2::cTokenSeparator, sTmp); + pSectionData->SetLinkFileName(sLinkFileName); + } + } + break; + case WID_SECT_DDE_AUTOUPDATE: + { + bool bVal(false); + if (!(pValues[nProperty] >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bUpdateType = bVal; + } + else + { + bLinkModeChanged = true; + bLinkMode = bVal; + } + } + break; + case WID_SECT_LINK: + { + text::SectionFileLink aLink; + if (!(pValues[nProperty] >>= aLink)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bDDE = false; + m_pProps->m_sLinkFileName = aLink.FileURL; + m_pProps->m_sSectionFilter = aLink.FilterName; + } + else + { + if (pSectionData->GetType() != SectionType::FileLink && + !aLink.FileURL.isEmpty()) + { + pSectionData->SetType(SectionType::FileLink); + } + const OUString sTmp(!aLink.FileURL.isEmpty() + ? URIHelper::SmartRel2Abs( + pFormat->GetDoc()->GetDocShell()->GetMedium()->GetURLObject(), + aLink.FileURL, URIHelper::GetMaybeFileHdl()) + : OUString()); + const OUString sFileName( + sTmp + OUStringChar(sfx2::cTokenSeparator) + + aLink.FilterName + OUStringChar(sfx2::cTokenSeparator) + + o3tl::getToken(pSectionData->GetLinkFileName(), 2, sfx2::cTokenSeparator)); + pSectionData->SetLinkFileName(sFileName); + if (sFileName.getLength() < 3) + { + pSectionData->SetType(SectionType::Content); + } + } + } + break; + case WID_SECT_REGION: + { + OUString sLink; + pValues[nProperty] >>= sLink; + if (m_bIsDescriptor) + { + m_pProps->m_bDDE = false; + m_pProps->m_sSectionRegion = sLink; + } + else + { + if (pSectionData->GetType() != SectionType::FileLink && + !sLink.isEmpty()) + { + pSectionData->SetType(SectionType::FileLink); + } + OUString sSectLink(pSectionData->GetLinkFileName()); + for (sal_Int32 i = comphelper::string::getTokenCount(sSectLink, sfx2::cTokenSeparator); + i < 3; ++i) + { + sSectLink += OUStringChar(sfx2::cTokenSeparator); + } + sSectLink = comphelper::string::setToken(sSectLink, 2, sfx2::cTokenSeparator, sLink); + pSectionData->SetLinkFileName(sSectLink); + if (sSectLink.getLength() < 3) + { + pSectionData->SetType(SectionType::Content); + } + } + } + break; + case WID_SECT_VISIBLE: + { + bool bVal(false); + if (!(pValues[nProperty] >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bHidden = !bVal; + } + else + { + pSectionData->SetHidden(!bVal); + } + } + break; + case WID_SECT_CURRENTLY_VISIBLE: + { + bool bVal(false); + if (!(pValues[nProperty] >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bCondHidden = !bVal; + } + else + { + if (!pSectionData->GetCondition().isEmpty()) + { + pSectionData->SetCondHidden(!bVal); + } + } + } + break; + case WID_SECT_PROTECTED: + { + bool bVal(false); + if (!(pValues[nProperty] >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bProtect = bVal; + } + else + { + pSectionData->SetProtectFlag(bVal); + } + } + break; + case WID_SECT_EDIT_IN_READONLY: + { + bool bVal(false); + if (!(pValues[nProperty] >>= bVal)) + { + throw lang::IllegalArgumentException(); + } + if (m_bIsDescriptor) + { + m_pProps->m_bEditInReadonly = bVal; + } + else + { + pSectionData->SetEditInReadonlyFlag(bVal); + } + } + break; + case WID_SECT_PASSWORD: + { + uno::Sequence<sal_Int8> aSeq; + pValues[nProperty] >>= aSeq; + if (m_bIsDescriptor) + { + m_pProps->m_Password = aSeq; + } + else + { + pSectionData->SetPassword(aSeq); + } + } + break; + default: + { + if (pFormat) + { + const SfxItemSet& rOldAttrSet = pFormat->GetAttrSet(); + oItemSet.emplace(*rOldAttrSet.GetPool(), pEntry->nWID, pEntry->nWID); + oItemSet->Put(rOldAttrSet); + m_rPropSet.setPropertyValue(*pEntry, + pValues[nProperty], *oItemSet); + } + else + { + SfxPoolItem* pPutItem = nullptr; + if (RES_COL == pEntry->nWID) + { + if (!m_pProps->m_pColItem) + { + m_pProps->m_pColItem.reset(new SwFormatCol); + } + pPutItem = m_pProps->m_pColItem.get(); + } + else if (RES_BACKGROUND == pEntry->nWID) + { + if (!m_pProps->m_pBrushItem) + { + m_pProps->m_pBrushItem.reset( + new SvxBrushItem(RES_BACKGROUND)); + } + pPutItem = m_pProps->m_pBrushItem.get(); + } + else if (RES_FTN_AT_TXTEND == pEntry->nWID) + { + if (!m_pProps->m_pFootnoteItem) + { + m_pProps->m_pFootnoteItem.reset(new SwFormatFootnoteAtTextEnd); + } + pPutItem = m_pProps->m_pFootnoteItem.get(); + } + else if (RES_END_AT_TXTEND == pEntry->nWID) + { + if (!m_pProps->m_pEndItem) + { + m_pProps->m_pEndItem.reset(new SwFormatEndAtTextEnd); + } + pPutItem = m_pProps->m_pEndItem.get(); + } + else if (RES_UNKNOWNATR_CONTAINER== pEntry->nWID) + { + if (!m_pProps->m_pXMLAttr) + { + m_pProps->m_pXMLAttr.reset( + new SvXMLAttrContainerItem( + RES_UNKNOWNATR_CONTAINER)); + } + pPutItem = m_pProps->m_pXMLAttr.get(); + } + else if (RES_COLUMNBALANCE== pEntry->nWID) + { + if (!m_pProps->m_pNoBalanceItem) + { + m_pProps->m_pNoBalanceItem.reset( + new SwFormatNoBalancedColumns(true)); + } + pPutItem = m_pProps->m_pNoBalanceItem.get(); + } + else if (RES_FRAMEDIR == pEntry->nWID) + { + if (!m_pProps->m_pFrameDirItem) + { + m_pProps->m_pFrameDirItem.reset( + new SvxFrameDirectionItem( + SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR)); + } + pPutItem = m_pProps->m_pFrameDirItem.get(); + } + else if (RES_LR_SPACE == pEntry->nWID) + { + if (!m_pProps->m_pLRSpaceItem) + { + m_pProps->m_pLRSpaceItem.reset( + new SvxLRSpaceItem( RES_LR_SPACE )); + } + pPutItem = m_pProps->m_pLRSpaceItem.get(); + } + if (pPutItem) + { + pPutItem->PutValue(pValues[nProperty], + pEntry->nMemberId); + } + } + } + } + } + + lcl_UpdateSection(pFormat, pSectionData, oItemSet, bLinkModeChanged, + bLinkMode); +} + +void SAL_CALL +SwXTextSection::setPropertyValues( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues) +{ + SolarMutexGuard aGuard; + + // workaround for bad designed API + try + { + m_pImpl->SetPropertyValues_Impl( rPropertyNames, rValues ); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +void SwXTextSection::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + m_pImpl->SetPropertyValues_Impl( { rPropertyName } , { rValue } ); +} + +uno::Sequence< uno::Any > +SwXTextSection::Impl::GetPropertyValues_Impl( + const uno::Sequence< OUString > & rPropertyNames ) +{ + SwSectionFormat *const pFormat = GetSectionFormat(); + if (!pFormat && !m_bIsDescriptor) + { + throw uno::RuntimeException( "non-descriptor section without format"); + } + + uno::Sequence< uno::Any > aRet(rPropertyNames.getLength()); + uno::Any* pRet = aRet.getArray(); + SwSection *const pSect = pFormat ? pFormat->GetSection() : nullptr; + const OUString* pPropertyNames = rPropertyNames.getConstArray(); + + for (sal_Int32 nProperty = 0; nProperty < rPropertyNames.getLength(); + nProperty++) + { + SfxItemPropertyMapEntry const*const pEntry = + m_rPropSet.getPropertyMap().getByName(pPropertyNames[nProperty]); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + pPropertyNames[nProperty], + m_rThis.getXWeak()); + } + switch(pEntry->nWID) + { + case WID_SECT_CONDITION: + { + const OUString uTmp( m_bIsDescriptor + ? m_pProps->m_sCondition + : pSect->GetCondition()); + pRet[nProperty] <<= uTmp; + } + break; + case WID_SECT_DDE_TYPE: + case WID_SECT_DDE_FILE: + case WID_SECT_DDE_ELEMENT: + { + OUString sRet; + if (m_bIsDescriptor) + { + if (m_pProps->m_bDDE) + { + sRet = m_pProps->m_sLinkFileName; + } + } + else if (SectionType::DdeLink == pSect->GetType()) + { + sRet = pSect->GetLinkFileName(); + } + pRet[nProperty] <<= sRet.getToken(pEntry->nWID - WID_SECT_DDE_TYPE, + sfx2::cTokenSeparator); + } + break; + case WID_SECT_DDE_AUTOUPDATE: + { + // GetUpdateType() returns .._ALWAYS or .._ONCALL + if (pSect && pSect->IsLinkType() && pSect->IsConnected()) // #i73247# + { + const bool bTemp = + (pSect->GetUpdateType() == SfxLinkUpdateMode::ALWAYS); + pRet[nProperty] <<= bTemp; + } + } + break; + case WID_SECT_LINK : + { + text::SectionFileLink aLink; + if (m_bIsDescriptor) + { + if (!m_pProps->m_bDDE) + { + aLink.FileURL = m_pProps->m_sLinkFileName; + aLink.FilterName = m_pProps->m_sSectionFilter; + } + } + else if (SectionType::FileLink == pSect->GetType()) + { + const OUString& sRet( pSect->GetLinkFileName() ); + sal_Int32 nIndex(0); + aLink.FileURL = + sRet.getToken(0, sfx2::cTokenSeparator, nIndex); + aLink.FilterName = + sRet.getToken(0, sfx2::cTokenSeparator, nIndex); + } + pRet[nProperty] <<= aLink; + } + break; + case WID_SECT_REGION : + { + OUString sRet; + if (m_bIsDescriptor) + { + sRet = m_pProps->m_sSectionRegion; + } + else if (SectionType::FileLink == pSect->GetType()) + { + sRet = pSect->GetLinkFileName().getToken(2, + sfx2::cTokenSeparator); + } + pRet[nProperty] <<= sRet; + } + break; + case WID_SECT_VISIBLE : + { + const bool bTemp = m_bIsDescriptor + ? !m_pProps->m_bHidden : !pSect->IsHidden(); + pRet[nProperty] <<= bTemp; + } + break; + case WID_SECT_CURRENTLY_VISIBLE: + { + const bool bTemp = m_bIsDescriptor + ? !m_pProps->m_bCondHidden : !pSect->IsCondHidden(); + pRet[nProperty] <<= bTemp; + } + break; + case WID_SECT_PROTECTED: + { + const bool bTemp = m_bIsDescriptor + ? m_pProps->m_bProtect : pSect->IsProtect(); + pRet[nProperty] <<= bTemp; + } + break; + case WID_SECT_EDIT_IN_READONLY: + { + const bool bTemp = m_bIsDescriptor + ? m_pProps->m_bEditInReadonly : pSect->IsEditInReadonly(); + pRet[nProperty] <<= bTemp; + } + break; + case FN_PARAM_LINK_DISPLAY_NAME: + { + if (pFormat) + { + pRet[nProperty] <<= pFormat->GetSection()->GetSectionName(); + } + } + break; + case WID_SECT_DOCUMENT_INDEX: + { + // search enclosing index + SwSection* pEnclosingSection = pSect; + while ((pEnclosingSection != nullptr) && + (SectionType::ToxContent != pEnclosingSection->GetType())) + { + pEnclosingSection = pEnclosingSection->GetParent(); + } + SwTOXBaseSection* const pTOXBaseSect = pEnclosingSection ? + dynamic_cast<SwTOXBaseSection*>( pEnclosingSection ) : nullptr; + if (pTOXBaseSect) + { + // convert section to TOXBase and get SwXDocumentIndex + const uno::Reference<text::XDocumentIndex> xIndex = + SwXDocumentIndex::CreateXDocumentIndex( + *pTOXBaseSect->GetFormat()->GetDoc(), pTOXBaseSect); + pRet[nProperty] <<= xIndex; + } + // else: no enclosing index found -> empty return value + } + break; + case WID_SECT_IS_GLOBAL_DOC_SECTION: + { + const bool bRet = pFormat && (nullptr != pFormat->GetGlobalDocSection()); + pRet[nProperty] <<= bRet; + } + break; + case FN_UNO_ANCHOR_TYPES: + case FN_UNO_TEXT_WRAP: + case FN_UNO_ANCHOR_TYPE: + ::sw::GetDefaultTextContentValue( + pRet[nProperty], u"", pEntry->nWID); + break; + case FN_UNO_REDLINE_NODE_START: + case FN_UNO_REDLINE_NODE_END: + { + if (!pFormat) + break; // #i73247# + SwNode* pSectNode = pFormat->GetSectionNode(); + if (FN_UNO_REDLINE_NODE_END == pEntry->nWID) + { + pSectNode = pSectNode->EndOfSectionNode(); + } + const SwRedlineTable& rRedTable = + pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); + for (SwRangeRedline* pRedline : rRedTable) + { + const SwNode& rRedPointNode = pRedline->GetPointNode(); + const SwNode& rRedMarkNode = pRedline->GetMarkNode(); + if ((&rRedPointNode == pSectNode) || + (&rRedMarkNode == pSectNode)) + { + const SwNode& rStartOfRedline = + (SwNodeIndex(rRedPointNode) <= + SwNodeIndex(rRedMarkNode)) + ? rRedPointNode : rRedMarkNode; + const bool bIsStart = (&rStartOfRedline == pSectNode); + pRet[nProperty] <<= + SwXRedlinePortion::CreateRedlineProperties( + *pRedline, bIsStart); + break; + } + } + } + break; + case WID_SECT_PASSWORD: + { + pRet[nProperty] <<= m_bIsDescriptor + ? m_pProps->m_Password : pSect->GetPassword(); + } + break; + default: + { + if (pFormat) + { + m_rPropSet.getPropertyValue(*pEntry, + pFormat->GetAttrSet(), pRet[nProperty]); + } + else + { + const SfxPoolItem* pQueryItem = nullptr; + if (RES_COL == pEntry->nWID) + { + if (!m_pProps->m_pColItem) + { + m_pProps->m_pColItem.reset(new SwFormatCol); + } + pQueryItem = m_pProps->m_pColItem.get(); + } + else if (RES_BACKGROUND == pEntry->nWID) + { + if (!m_pProps->m_pBrushItem) + { + m_pProps->m_pBrushItem.reset( + new SvxBrushItem(RES_BACKGROUND)); + } + pQueryItem = m_pProps->m_pBrushItem.get(); + } + else if (RES_FTN_AT_TXTEND == pEntry->nWID) + { + if (!m_pProps->m_pFootnoteItem) + { + m_pProps->m_pFootnoteItem.reset(new SwFormatFootnoteAtTextEnd); + } + pQueryItem = m_pProps->m_pFootnoteItem.get(); + } + else if (RES_END_AT_TXTEND == pEntry->nWID) + { + if (!m_pProps->m_pEndItem) + { + m_pProps->m_pEndItem.reset(new SwFormatEndAtTextEnd); + } + pQueryItem = m_pProps->m_pEndItem.get(); + } + else if (RES_UNKNOWNATR_CONTAINER== pEntry->nWID) + { + if (!m_pProps->m_pXMLAttr) + { + m_pProps->m_pXMLAttr.reset( + new SvXMLAttrContainerItem); + } + pQueryItem = m_pProps->m_pXMLAttr.get(); + } + else if (RES_COLUMNBALANCE== pEntry->nWID) + { + if (!m_pProps->m_pNoBalanceItem) + { + m_pProps->m_pNoBalanceItem.reset( + new SwFormatNoBalancedColumns); + } + pQueryItem = m_pProps->m_pNoBalanceItem.get(); + } + else if (RES_FRAMEDIR == pEntry->nWID) + { + if (!m_pProps->m_pFrameDirItem) + { + m_pProps->m_pFrameDirItem.reset( + new SvxFrameDirectionItem( + SvxFrameDirection::Environment, RES_FRAMEDIR)); + } + pQueryItem = m_pProps->m_pFrameDirItem.get(); + } + else if (RES_LR_SPACE == pEntry->nWID) + { + if (!m_pProps->m_pLRSpaceItem) + { + m_pProps->m_pLRSpaceItem.reset( + new SvxLRSpaceItem( RES_LR_SPACE )); + } + pQueryItem = m_pProps->m_pLRSpaceItem.get(); + } + if (pQueryItem) + { + pQueryItem->QueryValue(pRet[nProperty], + pEntry->nMemberId); + } + } + } + } + } + return aRet; +} + +uno::Sequence< uno::Any > SAL_CALL +SwXTextSection::getPropertyValues( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Any > aValues; + + // workaround for bad designed API + try + { + aValues = m_pImpl->GetPropertyValues_Impl( rPropertyNames ); + } + catch (beans::UnknownPropertyException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch (lang::WrappedTargetException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + + return aValues; +} + +uno::Any SAL_CALL +SwXTextSection::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Sequence< OUString > aPropertyNames { rPropertyName }; + return m_pImpl->GetPropertyValues_Impl(aPropertyNames).getConstArray()[0]; +} + +void SAL_CALL SwXTextSection::addPropertiesChangeListener( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXTextSection::addPropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXTextSection::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXTextSection::removePropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXTextSection::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXTextSection::firePropertiesChangeEvent(): not implemented"); +} + +void SAL_CALL +SwXTextSection::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextSection::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextSection::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextSection::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextSection::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextSection::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXTextSection::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXTextSection::removeVetoableChangeListener(): not implemented"); +} + +beans::PropertyState SAL_CALL +SwXTextSection::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Sequence< OUString > aNames { rPropertyName }; + return getPropertyStates(aNames).getConstArray()[0]; +} + +uno::Sequence< beans::PropertyState > SAL_CALL +SwXTextSection::getPropertyStates( + const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pFormat = m_pImpl->GetSectionFormat(); + if (!pFormat && !m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + uno::Sequence< beans::PropertyState > aStates(rPropertyNames.getLength()); + beans::PropertyState *const pStates = aStates.getArray(); + const OUString* pNames = rPropertyNames.getConstArray(); + for (sal_Int32 i = 0; i < rPropertyNames.getLength(); i++) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName( pNames[i]); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + pNames[i], + getXWeak()); + } + switch (pEntry->nWID) + { + case WID_SECT_CONDITION: + case WID_SECT_DDE_TYPE: + case WID_SECT_DDE_FILE: + case WID_SECT_DDE_ELEMENT: + case WID_SECT_DDE_AUTOUPDATE: + case WID_SECT_LINK: + case WID_SECT_REGION : + case WID_SECT_VISIBLE: + case WID_SECT_PROTECTED: + case WID_SECT_EDIT_IN_READONLY: + case FN_PARAM_LINK_DISPLAY_NAME: + case FN_UNO_ANCHOR_TYPES: + case FN_UNO_TEXT_WRAP: + case FN_UNO_ANCHOR_TYPE: + pStates[i] = beans::PropertyState_DIRECT_VALUE; + break; + default: + { + if (pFormat) + { + pStates[i] = m_pImpl->m_rPropSet.getPropertyState( + pNames[i], pFormat->GetAttrSet()); + } + else + { + if (RES_COL == pEntry->nWID) + { + if (!m_pImpl->m_pProps->m_pColItem) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + } + else + { + if (!m_pImpl->m_pProps->m_pBrushItem) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + } + } + } + } + } + return aStates; +} + +void SAL_CALL +SwXTextSection::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pFormat = m_pImpl->GetSectionFormat(); + if (!pFormat && !m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw uno::RuntimeException( + "Property is read-only: " + rPropertyName, + getXWeak()); + } + + std::unique_ptr<SwSectionData> const pSectionData( + pFormat ? new SwSectionData(*pFormat->GetSection()) : nullptr); + + std::optional<SfxItemSet> oNewAttrSet; + bool bLinkModeChanged = false; + + switch (pEntry->nWID) + { + case WID_SECT_CONDITION: + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_sCondition.clear(); + } + else + { + pSectionData->SetCondition(OUString()); + } + } + break; + case WID_SECT_DDE_TYPE : + case WID_SECT_DDE_FILE : + case WID_SECT_DDE_ELEMENT : + case WID_SECT_LINK : + case WID_SECT_REGION : + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_bDDE = false; + m_pImpl->m_pProps->m_sLinkFileName.clear(); + m_pImpl->m_pProps->m_sSectionRegion.clear(); + m_pImpl->m_pProps->m_sSectionFilter.clear(); + } + else + { + pSectionData->SetType(SectionType::Content); + } + break; + case WID_SECT_DDE_AUTOUPDATE: + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_bUpdateType = true; + } + else + { + bLinkModeChanged = true; + } + break; + case WID_SECT_VISIBLE : + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_bHidden = false; + } + else + { + pSectionData->SetHidden(false); + } + } + break; + case WID_SECT_PROTECTED: + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_bProtect = false; + } + else + { + pSectionData->SetProtectFlag(false); + } + } + break; + case WID_SECT_EDIT_IN_READONLY: + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pProps->m_bEditInReadonly = false; + } + else + { + pSectionData->SetEditInReadonlyFlag(false); + } + } + break; + + case FN_UNO_ANCHOR_TYPES: + case FN_UNO_TEXT_WRAP: + case FN_UNO_ANCHOR_TYPE: + break; + default: + { + if (SfxItemPool::IsWhich(pEntry->nWID)) + { + if (pFormat) + { + const SfxItemSet& rOldAttrSet = pFormat->GetAttrSet(); + oNewAttrSet.emplace(*rOldAttrSet.GetPool(), pEntry->nWID, pEntry->nWID); + oNewAttrSet->ClearItem(pEntry->nWID); + } + else + { + if (RES_COL == pEntry->nWID) + { + m_pImpl->m_pProps->m_pColItem.reset(); + } + else if (RES_BACKGROUND == pEntry->nWID) + { + m_pImpl->m_pProps->m_pBrushItem.reset(); + } + } + } + } + } + + lcl_UpdateSection(pFormat, pSectionData, oNewAttrSet, bLinkModeChanged); +} + +uno::Any SAL_CALL +SwXTextSection::getPropertyDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + SwSectionFormat *const pFormat = m_pImpl->GetSectionFormat(); + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + + switch(pEntry->nWID) + { + case WID_SECT_CONDITION: + case WID_SECT_DDE_TYPE : + case WID_SECT_DDE_FILE : + case WID_SECT_DDE_ELEMENT : + case WID_SECT_REGION : + case FN_PARAM_LINK_DISPLAY_NAME: + aRet <<= OUString(); + break; + case WID_SECT_LINK : + aRet <<= text::SectionFileLink(); + break; + case WID_SECT_DDE_AUTOUPDATE: + case WID_SECT_VISIBLE : + aRet <<= true; + break; + case WID_SECT_PROTECTED: + case WID_SECT_EDIT_IN_READONLY: + aRet <<= false; + break; + case FN_UNO_ANCHOR_TYPES: + case FN_UNO_TEXT_WRAP: + case FN_UNO_ANCHOR_TYPE: + ::sw::GetDefaultTextContentValue(aRet, u"", pEntry->nWID); + break; + default: + if(pFormat && SfxItemPool::IsWhich(pEntry->nWID)) + { + SwDoc *const pDoc = pFormat->GetDoc(); + const SfxPoolItem& rDefItem = + pDoc->GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(aRet, pEntry->nMemberId); + } + } + return aRet; +} + +OUString SAL_CALL SwXTextSection::getName() +{ + SolarMutexGuard aGuard; + + OUString sRet; + SwSectionFormat const*const pFormat = m_pImpl->GetSectionFormat(); + if(pFormat) + { + sRet = pFormat->GetSection()->GetSectionName(); + } + else if (m_pImpl->m_bIsDescriptor) + { + sRet = m_pImpl->m_sName; + } + else + { + throw uno::RuntimeException(); + } + return sRet; +} + +void SAL_CALL SwXTextSection::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + + SwSectionFormat *const pFormat = m_pImpl->GetSectionFormat(); + if(pFormat) + { + SwSection *const pSect = pFormat->GetSection(); + SwSectionData aSection(*pSect); + aSection.SetSectionName(rName); + + const SwSectionFormats& rFormats = pFormat->GetDoc()->GetSections(); + size_t nApplyPos = SIZE_MAX; + for( size_t i = 0; i < rFormats.size(); ++i ) + { + if(rFormats[i]->GetSection() == pSect) + { + nApplyPos = i; + } + else if (rName == rFormats[i]->GetSection()->GetSectionName()) + { + throw uno::RuntimeException(); + } + } + if (nApplyPos != SIZE_MAX) + { + { + UnoActionContext aContext(pFormat->GetDoc()); + pFormat->GetDoc()->UpdateSection(nApplyPos, aSection); + } + { + // temporarily remove actions to allow cursor update + // TODO: why? no table cursor here! + UnoActionRemoveContext aRemoveContext( pFormat->GetDoc() ); + } + } + } + else if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_sName = rName; + } + else + { + throw uno::RuntimeException(); + } +} + +OUString SAL_CALL +SwXTextSection::getImplementationName() +{ + return "SwXTextSection"; +} + +sal_Bool SAL_CALL SwXTextSection::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXTextSection::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.TextSection", + "com.sun.star.document.LinkTarget" + }; +} + +// MetadatableMixin +::sfx2::Metadatable* SwXTextSection::GetCoreObject() +{ + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + return pSectionFormat; +} + +uno::Reference<frame::XModel> SwXTextSection::GetModel() +{ + SwSectionFormat *const pSectionFormat( m_pImpl->GetSectionFormat() ); + if (pSectionFormat) + { + SwDocShell const*const pShell( pSectionFormat->GetDoc()->GetDocShell() ); + return pShell ? pShell->GetModel() : nullptr; + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx new file mode 100644 index 0000000000..bfc4b00a34 --- /dev/null +++ b/sw/source/core/unocore/unosett.cxx @@ -0,0 +1,2126 @@ +/* -*- 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 <editeng/editids.hrc> +#include <swtypes.hxx> +#include <unomid.h> +#include <hintids.hxx> +#include <strings.hrc> +#include <poolfmt.hxx> +#include <fmtcol.hxx> +#include <unomap.hxx> +#include <unosett.hxx> +#include <unoprnms.hxx> +#include <ftninfo.hxx> +#include <doc.hxx> +#include <pagedesc.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <charfmt.hxx> +#include <lineinfo.hxx> +#include <docsh.hxx> +#include <docary.hxx> +#include <docstyle.hxx> +#include <editeng/brushitem.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/text/FootnoteNumbering.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/style/LineNumberPosition.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <o3tl/any.hxx> +#include <o3tl/enumarray.hxx> +#include <tools/UnitConversion.hxx> +#include <vcl/font.hxx> +#include <editeng/flstitem.hxx> +#include <vcl/metric.hxx> +#include <vcl/graph.hxx> +#include <vcl/GraphicLoader.hxx> +#include <sfx2/docfile.hxx> +#include <svtools/ctrltool.hxx> +#include <vcl/svapp.hxx> +#include <editeng/unofdesc.hxx> +#include <fmtornt.hxx> +#include <SwStyleNameMapper.hxx> +#include <com/sun/star/text/PositionAndSpaceMode.hpp> +#include <com/sun/star/text/LabelFollow.hpp> +#include <numrule.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/propertyvalue.hxx> +#include <svl/itemprop.hxx> +#include <svl/listener.hxx> +#include <paratr.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; + + +namespace +{ + SvtBroadcaster& GetPageDescNotifier(SwDoc* pDoc) + { + return pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier(); + } +} + +#define WID_PREFIX 0 +#define WID_SUFFIX 1 +#define WID_NUMBERING_TYPE 2 +#define WID_START_AT 3 +#define WID_FOOTNOTE_COUNTING 4 +#define WID_PARAGRAPH_STYLE 5 +#define WID_PAGE_STYLE 6 +#define WID_CHARACTER_STYLE 7 +#define WID_POSITION_END_OF_DOC 8 +#define WID_END_NOTICE 9 +#define WID_BEGIN_NOTICE 10 +#define WID_ANCHOR_CHARACTER_STYLE 11 +#define WID_NUM_ON 12 +#define WID_SEPARATOR_INTERVAL 13 +#define WID_NUMBER_POSITION 14 +#define WID_DISTANCE 15 +#define WID_INTERVAL 16 +#define WID_SEPARATOR_TEXT 17 +#define WID_COUNT_EMPTY_LINES 18 +#define WID_COUNT_LINES_IN_FRAMES 19 +#define WID_RESTART_AT_EACH_PAGE 20 + + +static const SfxItemPropertySet* GetFootnoteSet() +{ + static const SfxItemPropertyMapEntry aFootnoteMap_Impl[] = + { + { UNO_NAME_ANCHOR_CHAR_STYLE_NAME,WID_ANCHOR_CHARACTER_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_BEGIN_NOTICE, WID_BEGIN_NOTICE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_STYLE_NAME, WID_CHARACTER_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_END_NOTICE, WID_END_NOTICE , ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_FOOTNOTE_COUNTING, WID_FOOTNOTE_COUNTING, ::cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_NUMBERING_TYPE, WID_NUMBERING_TYPE, ::cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PAGE_STYLE_NAME, WID_PAGE_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PARA_STYLE_NAME, WID_PARAGRAPH_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_POSITION_END_OF_DOC, WID_POSITION_END_OF_DOC,cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PREFIX, WID_PREFIX, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_START_AT, WID_START_AT , ::cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SUFFIX, WID_SUFFIX, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + static const SfxItemPropertySet aFootnoteSet_Impl(aFootnoteMap_Impl); + return &aFootnoteSet_Impl; +} + +static const SfxItemPropertySet* GetEndnoteSet() +{ + static const SfxItemPropertyMapEntry aEndnoteMap_Impl[] = + { + { UNO_NAME_ANCHOR_CHAR_STYLE_NAME,WID_ANCHOR_CHARACTER_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_CHAR_STYLE_NAME, WID_CHARACTER_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_NUMBERING_TYPE, WID_NUMBERING_TYPE, ::cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PAGE_STYLE_NAME, WID_PAGE_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PARA_STYLE_NAME, WID_PARAGRAPH_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_PREFIX, WID_PREFIX, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_START_AT, WID_START_AT , ::cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_SUFFIX, WID_SUFFIX, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + }; + static const SfxItemPropertySet aEndnoteSet_Impl(aEndnoteMap_Impl); + return &aEndnoteSet_Impl; +} + +static const SfxItemPropertySet* GetNumberingRulesSet() +{ + static const SfxItemPropertyMapEntry aNumberingRulesMap_Impl[] = + { + { UNO_NAME_IS_ABSOLUTE_MARGINS, WID_IS_ABS_MARGINS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_AUTOMATIC, WID_IS_AUTOMATIC, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_IS_CONTINUOUS_NUMBERING, WID_CONTINUOUS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_NAME, WID_RULE_NAME , ::cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + { UNO_NAME_NUMBERING_IS_OUTLINE, WID_IS_OUTLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_DEFAULT_LIST_ID, WID_DEFAULT_LIST_ID, ::cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0}, + }; + static const SfxItemPropertySet aNumberingRulesSet_Impl( aNumberingRulesMap_Impl ); + return &aNumberingRulesSet_Impl; +} + +static const SfxItemPropertySet* GetLineNumberingSet() +{ + static const SfxItemPropertyMapEntry aLineNumberingMap_Impl[] = + { + { UNO_NAME_CHAR_STYLE_NAME, WID_CHARACTER_STYLE, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_COUNT_EMPTY_LINES, WID_COUNT_EMPTY_LINES , cppu::UnoType<bool>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_COUNT_LINES_IN_FRAMES, WID_COUNT_LINES_IN_FRAMES, cppu::UnoType<bool>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_DISTANCE, WID_DISTANCE , ::cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_IS_ON, WID_NUM_ON, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_INTERVAL, WID_INTERVAL , ::cppu::UnoType<sal_Int16>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_SEPARATOR_TEXT, WID_SEPARATOR_TEXT, ::cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + { UNO_NAME_NUMBER_POSITION, WID_NUMBER_POSITION, ::cppu::UnoType<sal_Int16>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_NUMBERING_TYPE, WID_NUMBERING_TYPE , ::cppu::UnoType<sal_Int16>::get(),PROPERTY_NONE, 0}, + { UNO_NAME_RESTART_AT_EACH_PAGE, WID_RESTART_AT_EACH_PAGE, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, + { UNO_NAME_SEPARATOR_INTERVAL, WID_SEPARATOR_INTERVAL, ::cppu::UnoType<sal_Int16>::get(),PROPERTY_NONE, 0}, + }; + static const SfxItemPropertySet aLineNumberingSet_Impl(aLineNumberingMap_Impl); + return &aLineNumberingSet_Impl; +} + +static SwCharFormat* lcl_getCharFormat(SwDoc* pDoc, const uno::Any& aValue) +{ + SwCharFormat* pRet = nullptr; + OUString uTmp; + aValue >>= uTmp; + OUString sCharFormat; + SwStyleNameMapper::FillUIName(uTmp, sCharFormat, SwGetPoolIdFromName::ChrFmt); + if (sCharFormat != SwResId(STR_POOLCHR_STANDARD)) + { + pRet = pDoc->FindCharFormatByName( sCharFormat ); + } + if(!pRet) + { + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(sCharFormat, SwGetPoolIdFromName::ChrFmt); + if(USHRT_MAX != nId) + pRet = pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( nId ); + } + return pRet; +} + +static SwTextFormatColl* lcl_GetParaStyle(SwDoc* pDoc, const uno::Any& aValue) +{ + OUString uTmp; + aValue >>= uTmp; + OUString sParaStyle; + SwStyleNameMapper::FillUIName(uTmp, sParaStyle, SwGetPoolIdFromName::TxtColl ); + SwTextFormatColl* pRet = pDoc->FindTextFormatCollByName( sParaStyle ); + if( !pRet ) + { + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( sParaStyle, SwGetPoolIdFromName::TxtColl ); + if( USHRT_MAX != nId ) + pRet = pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( nId ); + } + return pRet; +} + +static SwPageDesc* lcl_GetPageDesc(SwDoc* pDoc, const uno::Any& aValue) +{ + OUString uTmp; + aValue >>= uTmp; + OUString sPageDesc; + SwStyleNameMapper::FillUIName(uTmp, sPageDesc, SwGetPoolIdFromName::PageDesc ); + SwPageDesc* pRet = pDoc->FindPageDesc( sPageDesc ); + if(!pRet) + { + const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(sPageDesc, SwGetPoolIdFromName::PageDesc); + if(USHRT_MAX != nId) + pRet = pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( nId ); + } + return pRet; +} + +// Numbering +const o3tl::enumarray<SvxAdjust, sal_Int16> aSvxToUnoAdjust +{ + text::HoriOrientation::LEFT, //3 + text::HoriOrientation::RIGHT, //1 + sal_Int16(-1), + text::HoriOrientation::CENTER, //2 + sal_Int16(-1), + sal_Int16(-1) +}; + +OUString SwXFootnoteProperties::getImplementationName() +{ + return "SwXFootnoteProperties"; +} + +sal_Bool SwXFootnoteProperties::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXFootnoteProperties::getSupportedServiceNames() +{ + Sequence<OUString> aRet { "com.sun.star.text.FootnoteSettings" }; + return aRet; +} + +SwXFootnoteProperties::SwXFootnoteProperties(SwDoc* pDc) : + m_pDoc(pDc), + m_pPropertySet(GetFootnoteSet()) +{ +} + +SwXFootnoteProperties::~SwXFootnoteProperties() +{ + +} + +uno::Reference< beans::XPropertySetInfo > SwXFootnoteProperties::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef = m_pPropertySet->getPropertySetInfo(); + return aRef; +} + +void SwXFootnoteProperties::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nFlags & PropertyAttribute::READONLY) + throw PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + SwFootnoteInfo aFootnoteInfo(m_pDoc->GetFootnoteInfo()); + switch(pEntry->nWID) + { + case WID_PREFIX: + { + OUString uTmp; + aValue >>= uTmp; + aFootnoteInfo.SetPrefix(uTmp); + } + break; + case WID_SUFFIX: + { + OUString uTmp; + aValue >>= uTmp; + aFootnoteInfo.SetSuffix(uTmp); + } + break; + case WID_NUMBERING_TYPE: + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + if(!(nTmp >= 0 && + (nTmp <= SVX_NUM_ARABIC || + nTmp > SVX_NUM_BITMAP))) + throw lang::IllegalArgumentException(); + + aFootnoteInfo.m_aFormat.SetNumberingType(static_cast<SvxNumType>(nTmp)); + + } + break; + case WID_START_AT: + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + aFootnoteInfo.m_nFootnoteOffset = nTmp; + } + break; + case WID_FOOTNOTE_COUNTING: + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + switch(nTmp) + { + case FootnoteNumbering::PER_PAGE: + aFootnoteInfo.m_eNum = FTNNUM_PAGE; + break; + case FootnoteNumbering::PER_CHAPTER: + aFootnoteInfo.m_eNum = FTNNUM_CHAPTER; + break; + case FootnoteNumbering::PER_DOCUMENT: + aFootnoteInfo.m_eNum = FTNNUM_DOC; + break; + } + } + break; + case WID_PARAGRAPH_STYLE: + { + SwTextFormatColl* pColl = lcl_GetParaStyle(m_pDoc, aValue); + if(pColl) + aFootnoteInfo.SetFootnoteTextColl(*pColl); + } + break; + case WID_PAGE_STYLE: + { + SwPageDesc* pDesc = lcl_GetPageDesc(m_pDoc, aValue); + if(pDesc) + aFootnoteInfo.ChgPageDesc( pDesc ); + } + break; + case WID_ANCHOR_CHARACTER_STYLE: + case WID_CHARACTER_STYLE: + { + SwCharFormat* pFormat = lcl_getCharFormat(m_pDoc, aValue); + if(pFormat) + { + if(pEntry->nWID == WID_ANCHOR_CHARACTER_STYLE) + aFootnoteInfo.SetAnchorCharFormat(pFormat); + else + aFootnoteInfo.SetCharFormat(pFormat); + } + } + break; + case WID_POSITION_END_OF_DOC: + { + bool bVal = *o3tl::doAccess<bool>(aValue); + aFootnoteInfo.m_ePos = bVal ? FTNPOS_CHAPTER : FTNPOS_PAGE; + } + break; + case WID_END_NOTICE: + { + OUString uTmp; + aValue >>= uTmp; + aFootnoteInfo.m_aQuoVadis = uTmp; + } + break; + case WID_BEGIN_NOTICE: + { + OUString uTmp; + aValue >>= uTmp; + aFootnoteInfo.m_aErgoSum = uTmp; + } + break; + } + m_pDoc->SetFootnoteInfo(aFootnoteInfo); + + +} + +uno::Any SwXFootnoteProperties::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + if(!m_pDoc) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + const SwFootnoteInfo& rFootnoteInfo = m_pDoc->GetFootnoteInfo(); + switch(pEntry->nWID) + { + case WID_PREFIX: + { + aRet <<= rFootnoteInfo.GetPrefix(); + } + break; + case WID_SUFFIX: + { + aRet <<= rFootnoteInfo.GetSuffix(); + } + break; + case WID_NUMBERING_TYPE : + { + aRet <<= static_cast<sal_Int16>(rFootnoteInfo.m_aFormat.GetNumberingType()); + } + break; + case WID_START_AT: + aRet <<= static_cast<sal_Int16>(rFootnoteInfo.m_nFootnoteOffset); + break; + case WID_FOOTNOTE_COUNTING : + { + sal_Int16 nRet = 0; + switch(rFootnoteInfo.m_eNum) + { + case FTNNUM_PAGE: + nRet = FootnoteNumbering::PER_PAGE; + break; + case FTNNUM_CHAPTER: + nRet = FootnoteNumbering::PER_CHAPTER; + break; + case FTNNUM_DOC: + nRet = FootnoteNumbering::PER_DOCUMENT; + break; + } + aRet <<= nRet; + } + break; + case WID_PARAGRAPH_STYLE : + { + SwTextFormatColl* pColl = rFootnoteInfo.GetFootnoteTextColl(); + OUString aString; + if(pColl) + aString = pColl->GetName(); + SwStyleNameMapper::FillProgName(aString, aString, SwGetPoolIdFromName::TxtColl); + aRet <<= aString; + } + break; + case WID_PAGE_STYLE : + { + OUString aString; + if( rFootnoteInfo.KnowsPageDesc() ) + { + SwStyleNameMapper::FillProgName( + rFootnoteInfo.GetPageDesc( *m_pDoc )->GetName(), + aString, + SwGetPoolIdFromName::PageDesc); + } + aRet <<= aString; + } + break; + case WID_ANCHOR_CHARACTER_STYLE: + case WID_CHARACTER_STYLE: + { + OUString aString; + const SwCharFormat* pCharFormat = rFootnoteInfo.GetCurrentCharFormat(pEntry->nWID == WID_ANCHOR_CHARACTER_STYLE); + if( pCharFormat ) + { + SwStyleNameMapper::FillProgName( + pCharFormat->GetName(), + aString, + SwGetPoolIdFromName::ChrFmt); + } + aRet <<= aString; + } + break; + case WID_POSITION_END_OF_DOC: + aRet <<= FTNPOS_CHAPTER == rFootnoteInfo.m_ePos; + break; + case WID_END_NOTICE : + aRet <<= rFootnoteInfo.m_aQuoVadis; + break; + case WID_BEGIN_NOTICE : + aRet <<= rFootnoteInfo.m_aErgoSum; + break; + } + + + return aRet; +} + +void SwXFootnoteProperties::addPropertyChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFootnoteProperties::removePropertyChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFootnoteProperties::addVetoableChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXFootnoteProperties::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +OUString SwXEndnoteProperties::getImplementationName() +{ + return "SwXEndnoteProperties"; +} + +sal_Bool SwXEndnoteProperties::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXEndnoteProperties::getSupportedServiceNames() +{ + Sequence<OUString> aRet { "com.sun.star.text.FootnoteSettings" }; + return aRet; +} + +SwXEndnoteProperties::SwXEndnoteProperties(SwDoc* pDc) : + m_pDoc(pDc), + m_pPropertySet(GetEndnoteSet()) +{ +} + +SwXEndnoteProperties::~SwXEndnoteProperties() +{ +} + +uno::Reference< beans::XPropertySetInfo > SwXEndnoteProperties::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef = m_pPropertySet->getPropertySetInfo(); + return aRef; +} + +void SwXEndnoteProperties::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + return; + + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nFlags & PropertyAttribute::READONLY) + throw PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + SwEndNoteInfo aEndInfo(m_pDoc->GetEndNoteInfo()); + switch(pEntry->nWID) + { + case WID_PREFIX: + { + OUString uTmp; + aValue >>= uTmp; + aEndInfo.SetPrefix(uTmp); + } + break; + case WID_SUFFIX: + { + OUString uTmp; + aValue >>= uTmp; + aEndInfo.SetSuffix(uTmp); + } + break; + case WID_NUMBERING_TYPE : + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + aEndInfo.m_aFormat.SetNumberingType(static_cast<SvxNumType>(nTmp)); + } + break; + case WID_START_AT: + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + aEndInfo.m_nFootnoteOffset = nTmp; + } + break; + case WID_PARAGRAPH_STYLE : + { + SwTextFormatColl* pColl = lcl_GetParaStyle(m_pDoc, aValue); + if(pColl) + aEndInfo.SetFootnoteTextColl(*pColl); + } + break; + case WID_PAGE_STYLE : + { + SwPageDesc* pDesc = lcl_GetPageDesc(m_pDoc, aValue); + if(pDesc) + aEndInfo.ChgPageDesc( pDesc ); + } + break; + case WID_ANCHOR_CHARACTER_STYLE: + case WID_CHARACTER_STYLE : + { + SwCharFormat* pFormat = lcl_getCharFormat(m_pDoc, aValue); + if(pFormat) + { + if(pEntry->nWID == WID_ANCHOR_CHARACTER_STYLE) + aEndInfo.SetAnchorCharFormat(pFormat); + else + aEndInfo.SetCharFormat(pFormat); + } + } + break; + } + m_pDoc->SetEndNoteInfo(aEndInfo); +} + +uno::Any SwXEndnoteProperties::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + if(m_pDoc) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + const SwEndNoteInfo& rEndInfo = m_pDoc->GetEndNoteInfo(); + switch(pEntry->nWID) + { + case WID_PREFIX: + aRet <<= rEndInfo.GetPrefix(); + break; + case WID_SUFFIX: + aRet <<= rEndInfo.GetSuffix(); + break; + case WID_NUMBERING_TYPE : + aRet <<= static_cast<sal_Int16>(rEndInfo.m_aFormat.GetNumberingType()); + break; + case WID_START_AT: + aRet <<= static_cast<sal_Int16>(rEndInfo.m_nFootnoteOffset); + break; + case WID_PARAGRAPH_STYLE : + { + SwTextFormatColl* pColl = rEndInfo.GetFootnoteTextColl(); + OUString aString; + if(pColl) + aString = pColl->GetName(); + SwStyleNameMapper::FillProgName( + aString, + aString, + SwGetPoolIdFromName::TxtColl); + aRet <<= aString; + + } + break; + case WID_PAGE_STYLE : + { + OUString aString; + if( rEndInfo.KnowsPageDesc() ) + { + SwStyleNameMapper::FillProgName( + rEndInfo.GetPageDesc( *m_pDoc )->GetName(), + aString, + SwGetPoolIdFromName::PageDesc); + } + aRet <<= aString; + } + break; + case WID_ANCHOR_CHARACTER_STYLE: + case WID_CHARACTER_STYLE: + { + OUString aString; + const SwCharFormat* pCharFormat = rEndInfo.GetCurrentCharFormat( pEntry->nWID == WID_ANCHOR_CHARACTER_STYLE ); + if( pCharFormat ) + { + SwStyleNameMapper::FillProgName( + pCharFormat->GetName(), + aString, + SwGetPoolIdFromName::ChrFmt); + } + aRet <<= aString; + } + break; + } + + } + return aRet; +} + +void SwXEndnoteProperties::addPropertyChangeListener( + const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXEndnoteProperties::removePropertyChangeListener(const OUString& /*PropertyName*/, + const uno:: Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXEndnoteProperties::addVetoableChangeListener(const OUString& /*PropertyName*/, + const uno:: Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXEndnoteProperties::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno:: Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +OUString SwXLineNumberingProperties::getImplementationName() +{ + return "SwXLineNumberingProperties"; +} + +sal_Bool SwXLineNumberingProperties::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXLineNumberingProperties::getSupportedServiceNames() +{ + Sequence<OUString> aRet { "com.sun.star.text.LineNumberingProperties" }; + return aRet; +} + +SwXLineNumberingProperties::SwXLineNumberingProperties(SwDoc* pDc) : + m_pDoc(pDc), + m_pPropertySet(GetLineNumberingSet()) +{ +} + +SwXLineNumberingProperties::~SwXLineNumberingProperties() +{ +} + +uno::Reference< beans::XPropertySetInfo > SwXLineNumberingProperties::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef = m_pPropertySet->getPropertySetInfo(); + return aRef; +} + +void SwXLineNumberingProperties::setPropertyValue( + const OUString& rPropertyName, const Any& aValue) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nFlags & PropertyAttribute::READONLY) + throw PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + SwLineNumberInfo aFontMetric(m_pDoc->GetLineNumberInfo()); + switch(pEntry->nWID) + { + case WID_NUM_ON: + { + bool bVal = *o3tl::doAccess<bool>(aValue); + aFontMetric.SetPaintLineNumbers(bVal); + } + break; + case WID_CHARACTER_STYLE : + { + SwCharFormat* pFormat = lcl_getCharFormat(m_pDoc, aValue); + if(pFormat) + aFontMetric.SetCharFormat(pFormat); + } + break; + case WID_NUMBERING_TYPE : + { + SvxNumberType aNumType(aFontMetric.GetNumType()); + sal_Int16 nTmp = 0; + aValue >>= nTmp; + aNumType.SetNumberingType(static_cast<SvxNumType>(nTmp)); + aFontMetric.SetNumType(aNumType); + } + break; + case WID_NUMBER_POSITION : + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + switch(nTmp) + { + case style::LineNumberPosition::LEFT: + aFontMetric.SetPos(LINENUMBER_POS_LEFT); + break; + case style::LineNumberPosition::RIGHT : + aFontMetric.SetPos(LINENUMBER_POS_RIGHT); + break; + case style::LineNumberPosition::INSIDE: + aFontMetric.SetPos(LINENUMBER_POS_INSIDE); + break; + case style::LineNumberPosition::OUTSIDE: + aFontMetric.SetPos(LINENUMBER_POS_OUTSIDE); + break; + } + } + break; + case WID_DISTANCE : + { + sal_Int32 nVal = 0; + aValue >>= nVal; + sal_Int32 nTmp = o3tl::toTwips(nVal, o3tl::Length::mm100); + if (nTmp > SAL_MAX_UINT16) + nTmp = SAL_MAX_UINT16; + aFontMetric.SetPosFromLeft(nTmp); + } + break; + case WID_INTERVAL : + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + if( nTmp > 0) + aFontMetric.SetCountBy(nTmp); + } + break; + case WID_SEPARATOR_TEXT : + { + OUString uTmp; + aValue >>= uTmp; + aFontMetric.SetDivider(uTmp); + } + break; + case WID_SEPARATOR_INTERVAL: + { + sal_Int16 nTmp = 0; + aValue >>= nTmp; + if( nTmp >= 0) + aFontMetric.SetDividerCountBy(nTmp); + } + break; + case WID_COUNT_EMPTY_LINES : + { + bool bVal = *o3tl::doAccess<bool>(aValue); + aFontMetric.SetCountBlankLines(bVal); + } + break; + case WID_COUNT_LINES_IN_FRAMES : + { + bool bVal = *o3tl::doAccess<bool>(aValue); + aFontMetric.SetCountInFlys(bVal); + } + break; + case WID_RESTART_AT_EACH_PAGE : + { + bool bVal = *o3tl::doAccess<bool>(aValue); + aFontMetric.SetRestartEachPage(bVal); + } + break; + } + m_pDoc->SetLineNumberInfo(aFontMetric); +} + +Any SwXLineNumberingProperties::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + Any aRet; + if(!m_pDoc) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName ); + if(!pEntry) + throw UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + const SwLineNumberInfo& rInfo = m_pDoc->GetLineNumberInfo(); + switch(pEntry->nWID) + { + case WID_NUM_ON: + aRet <<= rInfo.IsPaintLineNumbers(); + break; + case WID_CHARACTER_STYLE : + { + OUString aString; + // return empty string if no char format is set + // otherwise it would be created here + if(rInfo.HasCharFormat()) + { + SwStyleNameMapper::FillProgName( + rInfo.GetCharFormat(m_pDoc->getIDocumentStylePoolAccess())->GetName(), + aString, + SwGetPoolIdFromName::ChrFmt); + } + aRet <<= aString; + } + break; + case WID_NUMBERING_TYPE : + aRet <<= static_cast<sal_Int16>(rInfo.GetNumType().GetNumberingType()); + break; + case WID_NUMBER_POSITION : + { + sal_Int16 nRet = 0; + switch(rInfo.GetPos()) + { + case LINENUMBER_POS_LEFT: + nRet = style::LineNumberPosition::LEFT; + break; + case LINENUMBER_POS_RIGHT : + nRet = style::LineNumberPosition::RIGHT ; + break; + case LINENUMBER_POS_INSIDE: + nRet = style::LineNumberPosition::INSIDE ; + break; + case LINENUMBER_POS_OUTSIDE : + nRet = style::LineNumberPosition::OUTSIDE ; + break; + } + aRet <<= nRet; + } + break; + case WID_DISTANCE : + { + sal_uInt32 nPos = rInfo.GetPosFromLeft(); + if(USHRT_MAX == nPos) + nPos = 0; + aRet <<= static_cast < sal_Int32 >(convertTwipToMm100(nPos)); + } + break; + case WID_INTERVAL : + aRet <<= static_cast<sal_Int16>(rInfo.GetCountBy()); + break; + case WID_SEPARATOR_TEXT : + aRet <<= rInfo.GetDivider(); + break; + case WID_SEPARATOR_INTERVAL: + aRet <<= static_cast<sal_Int16>(rInfo.GetDividerCountBy()); + break; + case WID_COUNT_EMPTY_LINES : + aRet <<= rInfo.IsCountBlankLines(); + break; + case WID_COUNT_LINES_IN_FRAMES : + aRet <<= rInfo.IsCountInFlys(); + break; + case WID_RESTART_AT_EACH_PAGE : + aRet <<= rInfo.IsRestartEachPage(); + break; + } + return aRet; +} + +void SwXLineNumberingProperties::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno:: Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ +OSL_FAIL("not implemented"); +} + +void SwXLineNumberingProperties::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno:: Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ +OSL_FAIL("not implemented"); +} + +void SwXLineNumberingProperties::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno:: Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ +OSL_FAIL("not implemented"); +} + +void SwXLineNumberingProperties::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno:: Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ +OSL_FAIL("not implemented"); +} + +constexpr OUString aInvalidStyle = u"__XXX___invalid"_ustr; + +class SwXNumberingRules::Impl + : public SvtListener +{ + SwXNumberingRules& m_rParent; + virtual void Notify(const SfxHint&) override; + public: + explicit Impl(SwXNumberingRules& rParent) : m_rParent(rParent) {} +}; + +bool SwXNumberingRules::isInvalidStyle(std::u16string_view rName) +{ + return rName == aInvalidStyle; +} + +OUString SwXNumberingRules::getImplementationName() +{ + return "SwXNumberingRules"; +} + +sal_Bool SwXNumberingRules::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXNumberingRules::getSupportedServiceNames() +{ + Sequence<OUString> aRet { "com.sun.star.text.NumberingRules" }; + return aRet; +} + +SwXNumberingRules::SwXNumberingRules(const SwNumRule& rRule, SwDoc* doc) : + m_pImpl(new SwXNumberingRules::Impl(*this)), + m_pDoc(doc), + m_pDocShell(nullptr), + m_pNumRule(new SwNumRule(rRule)), + m_pPropertySet(GetNumberingRulesSet()), + m_bOwnNumRuleCreated(true) +{ + // first organize the document - it is dependent on the set character formats + // if no format is set, it should work as well + for( sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + SwNumFormat rFormat(m_pNumRule->Get(i)); + SwCharFormat* pCharFormat = rFormat.GetCharFormat(); + if(pCharFormat) + { + m_pDoc = pCharFormat->GetDoc(); + break; + } + } + if(m_pDoc) + m_pImpl->StartListening(GetPageDescNotifier(m_pDoc)); + for(sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + m_sNewCharStyleNames[i] = aInvalidStyle; + m_sNewBulletFontNames[i] = aInvalidStyle; + } +} + +SwXNumberingRules::SwXNumberingRules(SwDocShell& rDocSh) : + m_pImpl(new SwXNumberingRules::Impl(*this)), + m_pDoc(nullptr), + m_pDocShell(&rDocSh), + m_pNumRule(nullptr), + m_pPropertySet(GetNumberingRulesSet()), + m_bOwnNumRuleCreated(false) +{ + if (!m_pDocShell->GetDoc()) + throw uno::RuntimeException("Unitialized shell passed to SwXNumberingRules constructor"); + m_pImpl->StartListening(GetPageDescNotifier(m_pDocShell->GetDoc())); +} + +SwXNumberingRules::SwXNumberingRules(SwDoc& rDoc) : + m_pImpl(new SwXNumberingRules::Impl(*this)), + m_pDoc(&rDoc), + m_pDocShell(nullptr), + m_pNumRule(nullptr), + m_pPropertySet(GetNumberingRulesSet()), + m_bOwnNumRuleCreated(false) +{ + m_pImpl->StartListening(GetPageDescNotifier(&rDoc)); + m_sCreatedNumRuleName = rDoc.GetUniqueNumRuleName(); + rDoc.MakeNumRule( m_sCreatedNumRuleName, nullptr, false, + // #i89178# + numfunc::GetDefaultPositionAndSpaceMode() ); +} + +SwXNumberingRules::~SwXNumberingRules() +{ + SolarMutexGuard aGuard; + if(m_pDoc && !m_sCreatedNumRuleName.isEmpty()) + m_pDoc->DelNumRule( m_sCreatedNumRuleName ); + if( m_bOwnNumRuleCreated ) + delete m_pNumRule; +} + +void SwXNumberingRules::replaceByIndex(sal_Int32 nIndex, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + if(nIndex < 0 || MAXLEVEL <= nIndex) + throw lang::IndexOutOfBoundsException(); + + auto rProperties = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>( + rElement); + if(!rProperties) + throw lang::IllegalArgumentException(); + SwNumRule* pRule = nullptr; + if(m_pNumRule) + SwXNumberingRules::SetNumberingRuleByIndex( *m_pNumRule, + *rProperties, nIndex); + else if(m_pDocShell) + { + // #i87650# - correction of cws warnings: + SwNumRule aNumRule( *(m_pDocShell->GetDoc()->GetOutlineNumRule()) ); + SwXNumberingRules::SetNumberingRuleByIndex( aNumRule, + *rProperties, nIndex); + // set character format if needed + // this code appears to be dead - except when a style is assigned for BITMAP numbering? + const SwCharFormats* pFormats = m_pDocShell->GetDoc()->GetCharFormats(); + const size_t nChCount = pFormats->size(); + for(sal_uInt16 i = 0; i < MAXLEVEL;i++) + { + SwNumFormat aFormat(aNumRule.Get( i )); + if (!m_sNewCharStyleNames[i].isEmpty() && + (!aFormat.GetCharFormat() || aFormat.GetCharFormat()->GetName()!= m_sNewCharStyleNames[i])) + { + SwCharFormat* pCharFormat = nullptr; + for(size_t j = 0; j< nChCount; ++j) + { + SwCharFormat* pTmp = (*pFormats)[j]; + if(pTmp->GetName() == m_sNewCharStyleNames[i]) + { + pCharFormat = pTmp; + break; + } + } + if(!pCharFormat) + { + SfxStyleSheetBase* pBase; + pBase = m_pDocShell->GetStyleSheetPool()->Find(m_sNewCharStyleNames[i], + SfxStyleFamily::Char); + if(!pBase) + pBase = &m_pDocShell->GetStyleSheetPool()->Make(m_sNewCharStyleNames[i], SfxStyleFamily::Char); + pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + + } + aFormat.SetCharFormat( pCharFormat ); + aNumRule.Set( i, aFormat ); + } + } + m_pDocShell->GetDoc()->SetOutlineNumRule( aNumRule ); + } + else if(m_pDoc && !m_sCreatedNumRuleName.isEmpty() && + nullptr != (pRule = m_pDoc->FindNumRulePtr( m_sCreatedNumRuleName ))) + { + SwXNumberingRules::SetNumberingRuleByIndex( *pRule, + *rProperties, nIndex); + + pRule->Validate(*m_pDoc); + } + else + throw uno::RuntimeException(); +} + +sal_Int32 SwXNumberingRules::getCount() +{ + return MAXLEVEL; +} + +uno::Any SwXNumberingRules::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(nIndex < 0 || MAXLEVEL <= nIndex) + throw lang::IndexOutOfBoundsException(); + + uno::Any aVal; + const SwNumRule* pRule = m_pNumRule; + if(!pRule && m_pDoc && !m_sCreatedNumRuleName.isEmpty()) + pRule = m_pDoc->FindNumRulePtr( m_sCreatedNumRuleName ); + if(pRule) + { + uno::Sequence<beans::PropertyValue> aRet = GetNumberingRuleByIndex( + *pRule, nIndex); + aVal <<= aRet; + + } + else if(m_pDocShell) + { + uno::Sequence<beans::PropertyValue> aRet = GetNumberingRuleByIndex( + *m_pDocShell->GetDoc()->GetOutlineNumRule(), nIndex); + aVal <<= aRet; + } + else + throw uno::RuntimeException(); + return aVal; +} + +uno::Type SwXNumberingRules::getElementType() +{ + return cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(); +} + +sal_Bool SwXNumberingRules::hasElements() +{ + return true; +} + +const TranslateId STR_POOLCOLL_HEADLINE_ARY[] +{ + STR_POOLCOLL_HEADLINE1, + STR_POOLCOLL_HEADLINE2, + STR_POOLCOLL_HEADLINE3, + STR_POOLCOLL_HEADLINE4, + STR_POOLCOLL_HEADLINE5, + STR_POOLCOLL_HEADLINE6, + STR_POOLCOLL_HEADLINE7, + STR_POOLCOLL_HEADLINE8, + STR_POOLCOLL_HEADLINE9, + STR_POOLCOLL_HEADLINE10 +}; + +uno::Sequence<beans::PropertyValue> SwXNumberingRules::GetNumberingRuleByIndex( + const SwNumRule& rNumRule, sal_Int32 nIndex) const +{ + SolarMutexGuard aGuard; + OSL_ENSURE( 0 <= nIndex && nIndex < MAXLEVEL, "index out of range" ); + + const SwNumFormat& rFormat = rNumRule.Get( o3tl::narrowing<sal_uInt16>(nIndex) ); + + SwCharFormat* pCharFormat = rFormat.GetCharFormat(); + OUString CharStyleName; + if (pCharFormat) + CharStyleName = pCharFormat->GetName(); + + // Whether or not a style is present: the array entry overwrites this string + if (!m_sNewCharStyleNames[nIndex].isEmpty() && + !SwXNumberingRules::isInvalidStyle(m_sNewCharStyleNames[nIndex])) + { + CharStyleName = m_sNewCharStyleNames[nIndex]; + } + + OUString aUString; + if (m_pDocShell) // -> Chapter Numbering + { + // template name + OUString sValue(SwResId(STR_POOLCOLL_HEADLINE_ARY[nIndex])); + const SwTextFormatColls* pColls = m_pDocShell->GetDoc()->GetTextFormatColls(); + const size_t nCount = pColls->size(); + for(size_t i = 0; i < nCount; ++i) + { + SwTextFormatColl &rTextColl = *pColls->operator[](i); + if(rTextColl.IsDefault()) + continue; + + const sal_Int16 nOutLevel = rTextColl.IsAssignedToListLevelOfOutlineStyle() + ? static_cast<sal_Int16>(rTextColl.GetAssignedOutlineStyleLevel()) + : MAXLEVEL; + if ( nOutLevel == nIndex ) + { + sValue = rTextColl.GetName(); + break; // the style for the level in question has been found + } + else if( sValue==rTextColl.GetName() ) + { + // if the default for the level is existing, but its + // level is different, then it cannot be the default. + sValue.clear(); + } + } + SwStyleNameMapper::FillProgName(sValue, aUString, SwGetPoolIdFromName::TxtColl); + } + + OUString referer; + if (m_pDoc != nullptr) { + auto const sh = m_pDoc->GetPersist(); + if (sh != nullptr && sh->HasName()) { + referer = sh->GetMedium()->GetName(); + } + } + return GetPropertiesForNumFormat( + rFormat, CharStyleName, m_pDocShell ? & aUString : nullptr, referer); + +} + +uno::Sequence<beans::PropertyValue> SwXNumberingRules::GetPropertiesForNumFormat( + const SwNumFormat& rFormat, OUString const& rCharFormatName, + OUString const*const pHeadingStyleName, OUString const & referer) +{ + bool bChapterNum = pHeadingStyleName != nullptr; + + std::vector<PropertyValue> aPropertyValues; + aPropertyValues.reserve(32); + //fill all properties into the array + + //adjust + SvxAdjust eAdj = rFormat.GetNumAdjust(); + sal_Int16 nINT16 = aSvxToUnoAdjust[eAdj]; + aPropertyValues.push_back(comphelper::makePropertyValue("Adjust", nINT16)); + + //parentnumbering + nINT16 = rFormat.GetIncludeUpperLevels(); + aPropertyValues.push_back(comphelper::makePropertyValue("ParentNumbering", nINT16)); + + //prefix + OUString aUString = rFormat.GetPrefix(); + aPropertyValues.push_back(comphelper::makePropertyValue("Prefix", aUString)); + + //suffix + aUString = rFormat.GetSuffix(); + aPropertyValues.push_back(comphelper::makePropertyValue("Suffix", aUString)); + + //listformat + if (rFormat.HasListFormat()) + { + aPropertyValues.push_back(comphelper::makePropertyValue("ListFormat", rFormat.GetListFormat())); + } + + if (rFormat.GetIsLegal()) + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_LEVEL_IS_LEGAL, true)); + + //char style name + aUString.clear(); + SwStyleNameMapper::FillProgName( rCharFormatName, aUString, SwGetPoolIdFromName::ChrFmt); + aPropertyValues.push_back(comphelper::makePropertyValue("CharStyleName", aUString)); + + //startvalue + nINT16 = rFormat.GetStart(); + aPropertyValues.push_back(comphelper::makePropertyValue("StartWith", nINT16)); + + if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + //leftmargin + sal_Int32 nINT32 = convertTwipToMm100(rFormat.GetAbsLSpace()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_LEFT_MARGIN, nINT32)); + + //chartextoffset + nINT32 = convertTwipToMm100(rFormat.GetCharTextDistance()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_SYMBOL_TEXT_DISTANCE, nINT32)); + + //firstlineoffset + nINT32 = convertTwipToMm100(rFormat.GetFirstLineOffset()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_FIRST_LINE_OFFSET, nINT32)); + } + + // PositionAndSpaceMode + nINT16 = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION; + if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + nINT16 = PositionAndSpaceMode::LABEL_ALIGNMENT; + } + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_POSITION_AND_SPACE_MODE, nINT16)); + + if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + // LabelFollowedBy + nINT16 = LabelFollow::LISTTAB; + if ( rFormat.GetLabelFollowedBy() == SvxNumberFormat::SPACE ) + { + nINT16 = LabelFollow::SPACE; + } + else if ( rFormat.GetLabelFollowedBy() == SvxNumberFormat::NOTHING ) + { + nINT16 = LabelFollow::NOTHING; + } + else if ( rFormat.GetLabelFollowedBy() == SvxNumberFormat::NEWLINE ) + { + nINT16 = LabelFollow::NEWLINE; + } + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_LABEL_FOLLOWED_BY, nINT16)); + + // ListtabStopPosition + sal_Int32 nINT32 = convertTwipToMm100(rFormat.GetListtabPos()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_LISTTAB_STOP_POSITION, nINT32)); + + // FirstLineIndent + nINT32 = convertTwipToMm100(rFormat.GetFirstLineIndent()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_FIRST_LINE_INDENT, nINT32)); + + // IndentAt + nINT32 = convertTwipToMm100(rFormat.GetIndentAt()); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_INDENT_AT, nINT32)); + } + + //numberingtype + nINT16 = rFormat.GetNumberingType(); + aPropertyValues.push_back(comphelper::makePropertyValue("NumberingType", nINT16)); + + if(!bChapterNum) + { + if(SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType()) + { + sal_UCS4 cBullet = rFormat.GetBulletChar(); + + //BulletId + nINT16 = cBullet; + aPropertyValues.push_back(comphelper::makePropertyValue("BulletId", nINT16)); + + std::optional<vcl::Font> pFont = rFormat.GetBulletFont(); + + //BulletChar + aUString = OUString(&cBullet, 1); + aPropertyValues.push_back(comphelper::makePropertyValue("BulletChar", aUString)); + + //BulletFontName + aUString = pFont ? pFont->GetStyleName() : OUString(); + aPropertyValues.push_back(comphelper::makePropertyValue("BulletFontName", aUString)); + + //BulletFont + if(pFont) + { + awt::FontDescriptor aDesc; + SvxUnoFontDescriptor::ConvertFromFont( *pFont, aDesc ); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_BULLET_FONT, aDesc)); + } + } + if (SVX_NUM_BITMAP == rFormat.GetNumberingType()) + { + const SvxBrushItem* pBrush = rFormat.GetBrush(); + const Graphic* pGraphic = pBrush ? pBrush->GetGraphic(referer) : nullptr; + if (pGraphic) + { + //GraphicBitmap + uno::Reference<awt::XBitmap> xBitmap(pGraphic->GetXGraphic(), uno::UNO_QUERY); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_GRAPHIC_BITMAP, xBitmap)); + } + + Size aSize = rFormat.GetGraphicSize(); + // #i101131# + // adjust conversion due to type mismatch between <Size> and <awt::Size> + awt::Size aAwtSize(convertTwipToMm100(aSize.Width()), convertTwipToMm100(aSize.Height())); + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_GRAPHIC_SIZE, aAwtSize)); + + const SwFormatVertOrient* pOrient = rFormat.GetGraphicOrientation(); + if(pOrient) + { + uno::Any any; + pOrient->QueryValue(any); + aPropertyValues.emplace_back( + UNO_NAME_VERT_ORIENT, -1, any, PropertyState_DIRECT_VALUE); + } + } + } + else + { + aUString = *pHeadingStyleName; + aPropertyValues.push_back(comphelper::makePropertyValue(UNO_NAME_HEADING_STYLE_NAME, aUString)); + } + + return ::comphelper::containerToSequence(aPropertyValues); +} + +void SwXNumberingRules::SetNumberingRuleByIndex( + SwNumRule& rNumRule, + const uno::Sequence<beans::PropertyValue>& rProperties, sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + OSL_ENSURE( 0 <= nIndex && nIndex < MAXLEVEL, "index out of range" ); + + SwNumFormat aFormat(rNumRule.Get( o3tl::narrowing<sal_uInt16>(nIndex) )); + + OUString sHeadingStyleName; + OUString sParagraphStyleName; + + SetPropertiesToNumFormat(aFormat, m_sNewCharStyleNames[nIndex], + &m_sNewBulletFontNames[nIndex], + &sHeadingStyleName, &sParagraphStyleName, + m_pDoc, m_pDocShell, rProperties); + + + if (m_pDoc && !sParagraphStyleName.isEmpty()) + { + const SwTextFormatColls* pColls = m_pDoc->GetTextFormatColls(); + const size_t nCount = pColls->size(); + for (size_t k = 0; k < nCount; ++k) + { + SwTextFormatColl &rTextColl = *((*pColls)[k]); + if (rTextColl.GetName() == sParagraphStyleName) + rTextColl.SetFormatAttr( SwNumRuleItem( rNumRule.GetName())); + } + } + + if (!sHeadingStyleName.isEmpty()) + { + assert(m_pDocShell); + const SwTextFormatColls* pColls = m_pDocShell->GetDoc()->GetTextFormatColls(); + const size_t nCount = pColls->size(); + for (size_t k = 0; k < nCount; ++k) + { + SwTextFormatColl &rTextColl = *((*pColls)[k]); + if (rTextColl.IsDefault()) + continue; + if (rTextColl.IsAssignedToListLevelOfOutlineStyle() && + rTextColl.GetAssignedOutlineStyleLevel() == nIndex && + rTextColl.GetName() != sHeadingStyleName) + { + rTextColl.DeleteAssignmentToListLevelOfOutlineStyle(); + } + else if (rTextColl.GetName() == sHeadingStyleName) + { + rTextColl.AssignToListLevelOfOutlineStyle( nIndex ); + } + } + } + + rNumRule.Set(o3tl::narrowing<sal_uInt16>(nIndex), aFormat); +} + +void SwXNumberingRules::SetPropertiesToNumFormat( + SwNumFormat & aFormat, + OUString & rCharStyleName, OUString *const pBulletFontName, + OUString *const pHeadingStyleName, + OUString *const pParagraphStyleName, + SwDoc *const pDoc, + SwDocShell *const pDocShell, + const uno::Sequence<beans::PropertyValue>& rProperties) +{ + assert(pDoc == nullptr || pDocShell == nullptr); // can't be both ordinary and chapter numbering + + bool bWrongArg = false; + std::unique_ptr<SvxBrushItem> pSetBrush; + std::unique_ptr<Size> pSetSize; + std::unique_ptr<SwFormatVertOrient> pSetVOrient; + bool bCharStyleNameSet = false; + + for (const beans::PropertyValue& rProp : rProperties) + { + if (rProp.Name == UNO_NAME_ADJUST) + { + sal_Int16 nValue = text::HoriOrientation::NONE; + rProp.Value >>= nValue; + switch (nValue) { + case text::HoriOrientation::RIGHT: + aFormat.SetNumAdjust(SvxAdjust::Right); + break; + case text::HoriOrientation::CENTER: + aFormat.SetNumAdjust(SvxAdjust::Center); + break; + case text::HoriOrientation::LEFT: + aFormat.SetNumAdjust(SvxAdjust::Left); + break; + default: + bWrongArg = true; + break; + } + } + else if (rProp.Name == UNO_NAME_PARENT_NUMBERING) + { + sal_Int16 nSet = 0; + rProp.Value >>= nSet; + if(nSet >= 0 && MAXLEVEL >= nSet) + aFormat.SetIncludeUpperLevels( static_cast< sal_uInt8 >(nSet) ); + } + else if (rProp.Name == UNO_NAME_PREFIX) + { + OUString uTmp; + rProp.Value >>= uTmp; + aFormat.SetPrefix(uTmp); + } + else if (rProp.Name == UNO_NAME_SUFFIX) + { + OUString uTmp; + rProp.Value >>= uTmp; + aFormat.SetSuffix(uTmp); + } + else if (rProp.Name == UNO_NAME_CHAR_STYLE_NAME) + { + bCharStyleNameSet = true; + OUString uTmp; + rProp.Value >>= uTmp; + OUString sCharFormatName; + SwStyleNameMapper::FillUIName( uTmp, sCharFormatName, SwGetPoolIdFromName::ChrFmt ); + SwDoc *const pLocalDoc = pDocShell ? pDocShell->GetDoc() : pDoc; + if (sCharFormatName.isEmpty()) + { + rCharStyleName.clear(); + aFormat.SetCharFormat(nullptr); + aFormat.SetCharFormatName(""); + } + else if (pLocalDoc) + { + SwCharFormat* pCharFormat = nullptr; + if (!sCharFormatName.isEmpty()) + { + pCharFormat = pLocalDoc->FindCharFormatByName(sCharFormatName); + if(!pCharFormat) + { + + SfxStyleSheetBase* pBase; + SfxStyleSheetBasePool* pPool = pLocalDoc->GetDocShell()->GetStyleSheetPool(); + pBase = pPool->Find(sCharFormatName, SfxStyleFamily::Char); + if(!pBase) + pBase = &pPool->Make(sCharFormatName, SfxStyleFamily::Char); + pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat(); + } + } + aFormat.SetCharFormat( pCharFormat ); + // #i51842# + // If the character format has been found its name should not be in the + // char style names array + rCharStyleName.clear(); + } + else + rCharStyleName = sCharFormatName; + } + else if (rProp.Name == UNO_NAME_START_WITH) + { + sal_Int16 nVal = 0; + rProp.Value >>= nVal; + aFormat.SetStart(nVal); + } + else if (rProp.Name == UNO_NAME_LEFT_MARGIN) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + // #i23727# nValue can be negative + aFormat.SetAbsLSpace(o3tl::toTwips(nValue, o3tl::Length::mm100)); + } + else if (rProp.Name == UNO_NAME_SYMBOL_TEXT_DISTANCE) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + if (nValue >= 0) + aFormat.SetCharTextDistance(o3tl::toTwips(nValue, o3tl::Length::mm100)); + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_FIRST_LINE_OFFSET) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + // #i23727# nValue can be positive + nValue = o3tl::toTwips(nValue, o3tl::Length::mm100); + aFormat.SetFirstLineOffset(nValue); + } + else if (rProp.Name == UNO_NAME_POSITION_AND_SPACE_MODE) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + if ( nValue == 0 ) + { + aFormat.SetPositionAndSpaceMode( SvxNumberFormat::LABEL_WIDTH_AND_POSITION ); + } + else if ( nValue == 1 ) + { + aFormat.SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + } + else + { + bWrongArg = true; + } + } + else if (rProp.Name == UNO_NAME_LABEL_FOLLOWED_BY) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + if ( nValue == LabelFollow::LISTTAB ) + { + aFormat.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + } + else if ( nValue == LabelFollow::SPACE ) + { + aFormat.SetLabelFollowedBy( SvxNumberFormat::SPACE ); + } + else if ( nValue == LabelFollow::NOTHING ) + { + aFormat.SetLabelFollowedBy( SvxNumberFormat::NOTHING ); + } + else if ( nValue == LabelFollow::NEWLINE ) + { + aFormat.SetLabelFollowedBy( SvxNumberFormat::NEWLINE ); + } + else + { + bWrongArg = true; + } + } + else if (rProp.Name == UNO_NAME_LISTTAB_STOP_POSITION) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + nValue = o3tl::toTwips(nValue, o3tl::Length::mm100); + if ( nValue >= 0 ) + { + aFormat.SetListtabPos( nValue ); + } + else + { + bWrongArg = true; + } + } + else if (rProp.Name == UNO_NAME_FIRST_LINE_INDENT) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + nValue = o3tl::toTwips(nValue, o3tl::Length::mm100); + aFormat.SetFirstLineIndent( nValue ); + } + else if (rProp.Name == UNO_NAME_INDENT_AT) + { + sal_Int32 nValue = 0; + rProp.Value >>= nValue; + nValue = o3tl::toTwips(nValue, o3tl::Length::mm100); + aFormat.SetIndentAt( nValue ); + } + else if (rProp.Name == UNO_NAME_NUMBERING_TYPE) + { + sal_Int16 nSet = 0; + rProp.Value >>= nSet; + if(nSet >= 0) + aFormat.SetNumberingType(static_cast<SvxNumType>(nSet)); + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_PARAGRAPH_STYLE_NAME) + { + if (pParagraphStyleName) + { + OUString uTmp; + rProp.Value >>= uTmp; + OUString sStyleName; + SwStyleNameMapper::FillUIName(uTmp, sStyleName, SwGetPoolIdFromName::TxtColl ); + *pParagraphStyleName = sStyleName; + } + } + else if (rProp.Name == UNO_NAME_BULLET_ID) + { + sal_Int16 nSet = 0; + if( rProp.Value >>= nSet ) + aFormat.SetBulletChar(nSet); + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_BULLET_FONT) + { + awt::FontDescriptor desc; + if (rProp.Value >>= desc) + { + // #i93725# + // do not accept "empty" font + if (!desc.Name.isEmpty()) + { + vcl::Font aFont; + SvxUnoFontDescriptor::ConvertToFont(desc, aFont); + aFormat.SetBulletFont(&aFont); + } + } + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_BULLET_FONT_NAME) + { + OUString sBulletFontName; + rProp.Value >>= sBulletFontName; + SwDocShell *const pLclDocShell = pDocShell ? pDocShell : pDoc ? pDoc->GetDocShell() : nullptr; + if (!sBulletFontName.isEmpty() && pLclDocShell) + { + const SvxFontListItem* pFontListItem = + static_cast<const SvxFontListItem* >(pLclDocShell + ->GetItem( SID_ATTR_CHAR_FONTLIST )); + const FontList* pList = pFontListItem->GetFontList(); + FontMetric aFontMetric = pList->Get( + sBulletFontName, WEIGHT_NORMAL, ITALIC_NONE); + vcl::Font aFont(aFontMetric); + aFormat.SetBulletFont(&aFont); + } + else if (pBulletFontName) + *pBulletFontName = sBulletFontName; + } + else if (rProp.Name == UNO_NAME_BULLET_CHAR) + { + OUString aChar; + rProp.Value >>= aChar; + if (aChar.isEmpty()) + { + // If w:lvlText's value is null - set bullet char to zero + aFormat.SetBulletChar(u'\0'); + } + else + { + sal_Int32 nIndexUtf16 = 0; + sal_UCS4 cBullet = aChar.iterateCodePoints(&nIndexUtf16); + if (aChar.getLength() == nIndexUtf16) + aFormat.SetBulletChar(cBullet); + else + bWrongArg = true; + } + } + else if (rProp.Name == UNO_NAME_GRAPHIC) + { + uno::Reference<graphic::XGraphic> xGraphic; + if (rProp.Value >>= xGraphic) + { + if (!pSetBrush) + { + const SvxBrushItem* pOrigBrush = aFormat.GetBrush(); + if(pOrigBrush) + pSetBrush.reset(new SvxBrushItem(*pOrigBrush)); + else + pSetBrush.reset(new SvxBrushItem(OUString(), OUString(), GPOS_AREA, RES_BACKGROUND)); + } + Graphic aGraphic(xGraphic); + pSetBrush->SetGraphic(aGraphic); + } + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_GRAPHIC_BITMAP) + { + uno::Reference<awt::XBitmap> xBitmap; + if (rProp.Value >>= xBitmap) + { + if(!pSetBrush) + { + const SvxBrushItem* pOrigBrush = aFormat.GetBrush(); + if(pOrigBrush) + pSetBrush.reset(new SvxBrushItem(*pOrigBrush)); + else + pSetBrush.reset(new SvxBrushItem(OUString(), OUString(), GPOS_AREA, RES_BACKGROUND)); + } + + uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY); + Graphic aGraphic(xGraphic); + pSetBrush->SetGraphic(aGraphic); + } + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_GRAPHIC_SIZE) + { + if(!pSetSize) + pSetSize.reset(new Size); + awt::Size size; + if (rProp.Value >>= size) + { + pSetSize->setWidth(o3tl::toTwips(size.Width, o3tl::Length::mm100)); + pSetSize->setHeight(o3tl::toTwips(size.Height, o3tl::Length::mm100)); + } + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_VERT_ORIENT) + { + if(!pSetVOrient) + { + if(aFormat.GetGraphicOrientation()) + pSetVOrient.reset(aFormat.GetGraphicOrientation()->Clone()); + else + pSetVOrient.reset(new SwFormatVertOrient); + } + pSetVOrient->PutValue(rProp.Value, MID_VERTORIENT_ORIENT); + } + else if (rProp.Name == UNO_NAME_HEADING_STYLE_NAME + && pDocShell) // only on chapter numbering + { + if (pHeadingStyleName) + { + OUString uTmp; + rProp.Value >>= uTmp; + OUString sStyleName; + SwStyleNameMapper::FillUIName(uTmp, sStyleName, SwGetPoolIdFromName::TxtColl ); + *pHeadingStyleName = sStyleName; + } + } + else if (rProp.Name == UNO_NAME_BULLET_REL_SIZE) + { + // BulletRelSize - unsupported - only available in Impress + } + else if (rProp.Name == UNO_NAME_BULLET_COLOR) + { + // BulletColor - ignored too + } + else if (rProp.Name == UNO_NAME_GRAPHIC_URL) + { + OUString aURL; + if (rProp.Value >>= aURL) + { + if(!pSetBrush) + { + const SvxBrushItem* pOrigBrush = aFormat.GetBrush(); + if(pOrigBrush) + pSetBrush.reset(new SvxBrushItem(*pOrigBrush)); + else + pSetBrush.reset(new SvxBrushItem(OUString(), OUString(), GPOS_AREA, RES_BACKGROUND)); + } + + Graphic aGraphic = vcl::graphic::loadFromURL(aURL); + if (!aGraphic.IsNone()) + pSetBrush->SetGraphic(aGraphic); + } + else + bWrongArg = true; + } + else if (rProp.Name == UNO_NAME_LIST_FORMAT) + { + OUString uTmp; + rProp.Value >>= uTmp; + aFormat.SetListFormat(uTmp); + } + else if (rProp.Name == UNO_NAME_LEVEL_IS_LEGAL) + { + if (bool bVal; rProp.Value >>= bVal) + aFormat.SetIsLegal(bVal); + } + else + { + // Invalid property name + throw beans::UnknownPropertyException("Unknown property " + rProp.Name); + } + } + if(!bWrongArg && (pSetBrush || pSetSize || pSetVOrient)) + { + if(!pSetBrush && aFormat.GetBrush()) + pSetBrush.reset(new SvxBrushItem(*aFormat.GetBrush())); + + if(pSetBrush) + { + if(!pSetVOrient && aFormat.GetGraphicOrientation()) + pSetVOrient.reset( new SwFormatVertOrient(*aFormat.GetGraphicOrientation()) ); + + if(!pSetSize) + { + pSetSize.reset(new Size(aFormat.GetGraphicSize())); + if(!pSetSize->Width() || !pSetSize->Height()) + { + const Graphic* pGraphic = pSetBrush->GetGraphic(); + if(pGraphic) + *pSetSize = ::GetGraphicSizeTwip(*pGraphic, nullptr); + } + } + sal_Int16 eOrient = pSetVOrient ? + pSetVOrient->GetVertOrient() : text::VertOrientation::NONE; + aFormat.SetGraphicBrush( pSetBrush.get(), pSetSize.get(), text::VertOrientation::NONE == eOrient ? nullptr : &eOrient ); + } + } + if ((!bCharStyleNameSet || rCharStyleName.isEmpty()) + && aFormat.GetNumberingType() == NumberingType::BITMAP + && !aFormat.GetCharFormat() + && !SwXNumberingRules::isInvalidStyle(rCharStyleName)) + { + OUString tmp; + SwStyleNameMapper::FillProgName(RES_POOLCHR_BULLET_LEVEL, tmp); + rCharStyleName = tmp; + } + + if(bWrongArg) + throw lang::IllegalArgumentException(); +} + +uno::Reference< XPropertySetInfo > SwXNumberingRules::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef = m_pPropertySet->getPropertySetInfo(); + return aRef; +} + +void SwXNumberingRules::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + SolarMutexGuard aGuard; + std::unique_ptr<SwNumRule> pDocRule; + SwNumRule* pCreatedRule = nullptr; + if(!m_pNumRule) + { + if(m_pDocShell) + { + pDocRule.reset(new SwNumRule(*m_pDocShell->GetDoc()->GetOutlineNumRule())); + } + else if(m_pDoc && !m_sCreatedNumRuleName.isEmpty()) + { + pCreatedRule = m_pDoc->FindNumRulePtr(m_sCreatedNumRuleName); + } + + } + if(!m_pNumRule && !pDocRule && !pCreatedRule) + throw RuntimeException(); + + if(rPropertyName == UNO_NAME_IS_AUTOMATIC) + { + bool bVal = *o3tl::doAccess<bool>(rValue); + if(!pCreatedRule) + pDocRule ? pDocRule->SetAutoRule(bVal) : m_pNumRule->SetAutoRule(bVal); + } + else if(rPropertyName == UNO_NAME_IS_CONTINUOUS_NUMBERING) + { + bool bVal = *o3tl::doAccess<bool>(rValue); + pDocRule ? pDocRule->SetContinusNum(bVal) : + pCreatedRule ? pCreatedRule->SetContinusNum(bVal) : m_pNumRule->SetContinusNum(bVal); + } + else if(rPropertyName == UNO_NAME_NAME) + { + throw IllegalArgumentException(); + } + else if(rPropertyName == UNO_NAME_IS_ABSOLUTE_MARGINS) + { + bool bVal = *o3tl::doAccess<bool>(rValue); + pDocRule ? pDocRule->SetAbsSpaces(bVal) : + pCreatedRule ? pCreatedRule->SetAbsSpaces(bVal) : m_pNumRule->SetAbsSpaces(bVal); + } + else if(rPropertyName == UNO_NAME_NUMBERING_IS_OUTLINE) + { + bool bVal = *o3tl::doAccess<bool>(rValue); + SwNumRuleType eNumRuleType = bVal ? OUTLINE_RULE : NUM_RULE; + pDocRule ? pDocRule->SetRuleType(eNumRuleType) : + pCreatedRule ? pCreatedRule->SetRuleType(eNumRuleType) : m_pNumRule->SetRuleType(eNumRuleType); + } + else if(rPropertyName == UNO_NAME_DEFAULT_LIST_ID) + { + throw IllegalArgumentException(); + } + else + throw UnknownPropertyException(rPropertyName); + + if(pDocRule) + { + assert(m_pDocShell); + m_pDocShell->GetDoc()->SetOutlineNumRule(*pDocRule); + pDocRule.reset(); + } + else if(pCreatedRule) + { + pCreatedRule->Validate(*m_pDoc); + } +} + +Any SwXNumberingRules::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + const SwNumRule* pRule = m_pNumRule; + if(!pRule && m_pDocShell) + pRule = m_pDocShell->GetDoc()->GetOutlineNumRule(); + else if(m_pDoc && !m_sCreatedNumRuleName.isEmpty()) + pRule = m_pDoc->FindNumRulePtr( m_sCreatedNumRuleName ); + if(!pRule) + throw RuntimeException(); + + if(rPropertyName == UNO_NAME_IS_AUTOMATIC) + { + aRet <<= pRule->IsAutoRule(); + } + else if(rPropertyName == UNO_NAME_IS_CONTINUOUS_NUMBERING) + { + aRet <<= pRule->IsContinusNum(); + } + else if(rPropertyName == UNO_NAME_NAME) + aRet <<= pRule->GetName(); + else if(rPropertyName == UNO_NAME_IS_ABSOLUTE_MARGINS) + { + aRet <<= pRule->IsAbsSpaces(); + } + else if(rPropertyName == UNO_NAME_NUMBERING_IS_OUTLINE) + { + aRet <<= pRule->IsOutlineRule(); + } + else if(rPropertyName == UNO_NAME_DEFAULT_LIST_ID) + { + OSL_ENSURE( !pRule->GetDefaultListId().isEmpty(), + "<SwXNumberingRules::getPropertyValue(..)> - no default list id found. Serious defect." ); + aRet <<= pRule->GetDefaultListId(); + } + else + throw UnknownPropertyException(rPropertyName); + return aRet; +} + +void SwXNumberingRules::addPropertyChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) +{ +} + +void SwXNumberingRules::removePropertyChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) +{ +} + +void SwXNumberingRules::addVetoableChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ ) +{ +} + +void SwXNumberingRules::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ ) +{ +} + +OUString SwXNumberingRules::getName() +{ + if(m_pNumRule) + { + OUString aString; + SwStyleNameMapper::FillProgName(m_pNumRule->GetName(), aString, SwGetPoolIdFromName::NumRule ); + return aString; + } + // consider chapter numbering <SwXNumberingRules> + if ( m_pDocShell ) + { + OUString aString; + SwStyleNameMapper::FillProgName( m_pDocShell->GetDoc()->GetOutlineNumRule()->GetName(), + aString, SwGetPoolIdFromName::NumRule ); + return aString; + } + return m_sCreatedNumRuleName; +} + +void SwXNumberingRules::setName(const OUString& /*rName*/) +{ + throw RuntimeException("readonly"); +} + +void SwXNumberingRules::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + if(m_rParent.m_bOwnNumRuleCreated) + delete m_rParent.m_pNumRule; + m_rParent.m_pNumRule = nullptr; + m_rParent.m_pDoc = nullptr; + } +} + +OUString SwXChapterNumbering::getImplementationName() +{ + return "SwXChapterNumbering"; +} + +sal_Bool SwXChapterNumbering::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > SwXChapterNumbering::getSupportedServiceNames() +{ + return { "com.sun.star.text.ChapterNumbering", "com.sun.star.text.NumberingRules" }; +} + +SwXChapterNumbering::SwXChapterNumbering(SwDocShell& rDocSh) : + SwXNumberingRules(rDocSh) +{ +} + +SwXChapterNumbering::~SwXChapterNumbering() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unosrch.cxx b/sw/source/core/unocore/unosrch.cxx new file mode 100644 index 0000000000..d41dccb0d0 --- /dev/null +++ b/sw/source/core/unocore/unosrch.cxx @@ -0,0 +1,603 @@ +/* -*- 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 <hintids.hxx> +#include <unosrch.hxx> +#include <unomap.hxx> +#include <swtypes.hxx> + +#include <osl/diagnose.h> +#include <i18nlangtag/languagetag.hxx> +#include <i18nutil/searchopt.hxx> +#include <o3tl/any.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svl/itemprop.hxx> +#include <svl/itempool.hxx> +#include <memory> +#include <unordered_map> + +using namespace ::com::sun::star; + +class SwSearchProperties_Impl +{ + std::unordered_map<OUString, beans::PropertyValue> maValues; + SfxItemPropertyMap mrMap; + + SwSearchProperties_Impl(const SwSearchProperties_Impl&) = delete; + SwSearchProperties_Impl& operator=(const SwSearchProperties_Impl&) = delete; + +public: + SwSearchProperties_Impl(); + + /// @throws beans::UnknownPropertyException + /// @throws lang::IllegalArgumentException + /// @throws uno::RuntimeException + void SetProperties(const uno::Sequence< beans::PropertyValue >& aSearchAttribs); + uno::Sequence< beans::PropertyValue > GetProperties() const; + + void FillItemSet(SfxItemSet& rSet, bool bIsValueSearch) const; + bool HasAttributes() const; +}; + +SwSearchProperties_Impl::SwSearchProperties_Impl() : + mrMap( aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR)->getPropertyMap() ) +{ +} + +void SwSearchProperties_Impl::SetProperties(const uno::Sequence< beans::PropertyValue >& aSearchAttribs) +{ + //delete all existing values + maValues.clear(); + + for(const beans::PropertyValue& rSearchAttrib : aSearchAttribs) + { + const OUString& sName = rSearchAttrib.Name; + if( !mrMap.hasPropertyByName(sName) ) + throw beans::UnknownPropertyException(sName); + maValues[sName] = rSearchAttrib; + } +} + +uno::Sequence< beans::PropertyValue > SwSearchProperties_Impl::GetProperties() const +{ + uno::Sequence< beans::PropertyValue > aRet(maValues.size()); + beans::PropertyValue* pProps = aRet.getArray(); + sal_Int32 nPropCount = 0; + for(auto const & rPair : maValues) + { + pProps[nPropCount++] = rPair.second; + } + return aRet; +} + +void SwSearchProperties_Impl::FillItemSet(SfxItemSet& rSet, bool bIsValueSearch) const +{ + + std::unique_ptr<SfxPoolItem> pBoxItem, + pCharBoxItem, + pBreakItem, + pAutoKernItem , + pWLineItem , + pTabItem , + pSplitItem , + pRegItem , + pLineSpaceItem , + pLineNumItem , + pKeepItem , + pFirstLineIndent, + pTextLeftMargin, + pRightMargin, + pLRItem , + pULItem , + pBackItem , + pAdjItem , + pDescItem , + pInetItem , + pDropItem , + pWeightItem , + pULineItem , + pOLineItem , + pCharFormatItem , + pShadItem , + pPostItem , + pNHyphItem , + pLangItem , + pKernItem , + pFontSizeItem , + pFontItem , + pBlinkItem , + pEscItem , + pCrossedOutItem , + pContourItem , + pCharColorItem , + pCasemapItem , + pBrushItem , + pFontCJKItem, + pFontSizeCJKItem, + pCJKLangItem, + pCJKPostureItem, + pCJKWeightItem, + pFontCTLItem, + pFontSizeCTLItem, + pCTLLangItem, + pCTLPostureItem, + pCTLWeightItem, + pShadowItem, + pCharReliefItem, + pCharRotate, + pCharScaleWidth, + pParaVertAlign, + pParaOrphans, + pParaWidows; + + auto funcClone = [&rSet](sal_uInt16 nWID, std::unique_ptr<SfxPoolItem> & rpPoolItem) + { + if(!rpPoolItem) + rpPoolItem.reset(rSet.GetPool()->GetDefaultItem(nWID).Clone()); + return rpPoolItem.get(); + }; + for(auto const & rPair : maValues) + { + SfxPoolItem* pTempItem = nullptr; + const SfxItemPropertyMapEntry* pPropEntry = mrMap.getByName(rPair.first); + assert(pPropEntry && "SetProperties only enters values into maValues if mrMap.hasPropertyByName() was true"); + const SfxItemPropertyMapEntry & rPropEntry = *pPropEntry; + sal_uInt16 nWID = rPropEntry.nWID; + switch(nWID) + { + case RES_BOX: + pTempItem = funcClone(nWID, pBoxItem); + break; + case RES_CHRATR_BOX: + pTempItem = funcClone(nWID, pCharBoxItem); + break; + case RES_BREAK: + pTempItem = funcClone(nWID, pBreakItem); + break; + case RES_CHRATR_AUTOKERN: + pTempItem = funcClone(nWID, pAutoKernItem); + break; + case RES_CHRATR_BACKGROUND: + pTempItem = funcClone(nWID, pBrushItem); + break; + case RES_CHRATR_CASEMAP: + pTempItem = funcClone(nWID, pCasemapItem); + break; + case RES_CHRATR_COLOR: + pTempItem = funcClone(nWID, pCharColorItem); + break; + case RES_CHRATR_CONTOUR: + pTempItem = funcClone(nWID, pContourItem); + break; + case RES_CHRATR_CROSSEDOUT: + pTempItem = funcClone(nWID, pCrossedOutItem); + break; + case RES_CHRATR_ESCAPEMENT: + pTempItem = funcClone(nWID, pEscItem); + break; + case RES_CHRATR_BLINK: + pTempItem = funcClone(nWID, pBlinkItem); + break; + case RES_CHRATR_FONT: + pTempItem = funcClone(nWID, pFontItem); + break; + case RES_CHRATR_FONTSIZE: + pTempItem = funcClone(nWID, pFontSizeItem); + break; + case RES_CHRATR_KERNING: + pTempItem = funcClone(nWID, pKernItem); + break; + case RES_CHRATR_LANGUAGE: + pTempItem = funcClone(nWID, pLangItem); + break; + case RES_CHRATR_NOHYPHEN: + pTempItem = funcClone(nWID, pNHyphItem); + break; + case RES_CHRATR_POSTURE: + pTempItem = funcClone(nWID, pPostItem); + break; + case RES_CHRATR_SHADOWED: + pTempItem = funcClone(nWID, pShadItem); + break; + case RES_TXTATR_CHARFMT: + pTempItem = funcClone(nWID, pCharFormatItem); + break; + case RES_CHRATR_UNDERLINE: + pTempItem = funcClone(nWID, pULineItem); + break; + case RES_CHRATR_OVERLINE: + pTempItem = funcClone(nWID, pOLineItem); + break; + case RES_CHRATR_WEIGHT: + pTempItem = funcClone(nWID, pWeightItem); + break; + case RES_PARATR_DROP: + pTempItem = funcClone(nWID, pDropItem); + break; + case RES_TXTATR_INETFMT: + pTempItem = funcClone(nWID, pInetItem); + break; + case RES_PAGEDESC: + pTempItem = funcClone(nWID, pDescItem); + break; + case RES_PARATR_ADJUST: + pTempItem = funcClone(nWID, pAdjItem); + break; + case RES_BACKGROUND: + pTempItem = funcClone(nWID, pBackItem); + break; + case RES_UL_SPACE: + pTempItem = funcClone(nWID, pULItem); + break; + case RES_MARGIN_FIRSTLINE: + pTempItem = funcClone(nWID, pFirstLineIndent); + break; + case RES_MARGIN_TEXTLEFT: + pTempItem = funcClone(nWID, pTextLeftMargin); + break; + case RES_MARGIN_RIGHT: + pTempItem = funcClone(nWID, pRightMargin); + break; + case RES_LR_SPACE: + pTempItem = funcClone(nWID, pLRItem); + break; + case RES_KEEP: + pTempItem = funcClone(nWID, pKeepItem); + break; + case RES_LINENUMBER: + pTempItem = funcClone(nWID, pLineNumItem); + break; + case RES_PARATR_LINESPACING: + pTempItem = funcClone(nWID, pLineSpaceItem); + break; + case RES_PARATR_REGISTER: + pTempItem = funcClone(nWID, pRegItem); + break; + case RES_PARATR_SPLIT: + pTempItem = funcClone(nWID, pSplitItem); + break; + case RES_PARATR_TABSTOP: + pTempItem = funcClone(nWID, pTabItem); + break; + case RES_CHRATR_WORDLINEMODE: + pTempItem = funcClone(nWID, pWLineItem); + break; + case RES_CHRATR_CJK_FONT: + pTempItem = funcClone(nWID, pFontCJKItem); + break; + case RES_CHRATR_CJK_FONTSIZE: + pTempItem = funcClone(nWID, pFontSizeCJKItem); + break; + case RES_CHRATR_CJK_LANGUAGE: + pTempItem = funcClone(nWID, pCJKLangItem); + break; + case RES_CHRATR_CJK_POSTURE: + pTempItem = funcClone(nWID, pCJKPostureItem); + break; + case RES_CHRATR_CJK_WEIGHT: + pTempItem = funcClone(nWID, pCJKWeightItem); + break; + case RES_CHRATR_CTL_FONT: + pTempItem = funcClone(nWID, pFontCTLItem); + break; + case RES_CHRATR_CTL_FONTSIZE: + pTempItem = funcClone(nWID, pFontSizeCTLItem); + break; + case RES_CHRATR_CTL_LANGUAGE: + pTempItem = funcClone(nWID, pCTLLangItem); + break; + case RES_CHRATR_CTL_POSTURE: + pTempItem = funcClone(nWID, pCTLPostureItem); + break; + case RES_CHRATR_CTL_WEIGHT: + pTempItem = funcClone(nWID, pCTLWeightItem); + break; + case RES_CHRATR_SHADOW: + pTempItem = funcClone(nWID, pShadowItem); + break; + case RES_CHRATR_RELIEF: + pTempItem = funcClone(nWID, pCharReliefItem); + break; + case RES_CHRATR_ROTATE: + pTempItem = funcClone(nWID, pCharRotate); + break; + case RES_CHRATR_SCALEW: + pTempItem = funcClone(nWID, pCharScaleWidth); + break; + case RES_PARATR_VERTALIGN: + pTempItem = funcClone(nWID, pParaVertAlign); + break; + case RES_PARATR_ORPHANS: + pTempItem = funcClone(nWID, pParaOrphans); + break; + case RES_PARATR_WIDOWS: + pTempItem = funcClone(nWID, pParaWidows); + break; + } + if(pTempItem) + { + if(bIsValueSearch) + { + pTempItem->PutValue(rPair.second.Value, rPropEntry.nMemberId); + rSet.Put(*pTempItem); + } + else + rSet.InvalidateItem( pTempItem->Which() ); + } + } +} + +bool SwSearchProperties_Impl::HasAttributes() const +{ + return !maValues.empty(); +} + +SwXTextSearch::SwXTextSearch() : + m_pSearchProperties( new SwSearchProperties_Impl), + m_pReplaceProperties( new SwSearchProperties_Impl), + m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_SEARCH)), + m_bAll(false), + m_bWord(false), + m_bBack(false), + m_bExpr(false), + m_bCase(false), + m_bStyles(false), + m_bSimilarity(false), + m_bLevRelax(false), + m_nLevExchange(2), + m_nLevAdd(2), + m_nLevRemove(2), + m_bIsValueSearch(true) +{ +} + +SwXTextSearch::~SwXTextSearch() +{ + m_pSearchProperties.reset(); + m_pReplaceProperties.reset(); +} + +namespace +{ +} + +OUString SwXTextSearch::getSearchString() +{ + SolarMutexGuard aGuard; + return m_sSearchText; +} + +void SwXTextSearch::setSearchString(const OUString& rString) +{ + SolarMutexGuard aGuard; + m_sSearchText = rString; +} + +OUString SwXTextSearch::getReplaceString() +{ + SolarMutexGuard aGuard; + return m_sReplaceText; +} + +void SwXTextSearch::setReplaceString(const OUString& rReplaceString) +{ + SolarMutexGuard aGuard; + m_sReplaceText = rReplaceString; +} + +uno::Reference< beans::XPropertySetInfo > SwXTextSearch::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef = m_pPropSet->getPropertySetInfo(); + return aRef; +} + +void SwXTextSearch::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException ("Property is read-only: " + rPropertyName, getXWeak() ); + bool bVal = false; + if(auto b = o3tl::tryAccess<bool>(aValue)) + bVal = *b; + switch(pEntry->nWID) + { + case WID_SEARCH_ALL : m_bAll = bVal; break; + case WID_WORDS: m_bWord = bVal; break; + case WID_BACKWARDS : m_bBack = bVal; break; + case WID_REGULAR_EXPRESSION : m_bExpr = bVal; break; + case WID_CASE_SENSITIVE : m_bCase = bVal; break; + //case WID_IN_SELECTION : bInSel = bVal; break; + case WID_STYLES : m_bStyles = bVal; break; + case WID_SIMILARITY : m_bSimilarity = bVal; break; + case WID_SIMILARITY_RELAX: m_bLevRelax = bVal; break; + case WID_SIMILARITY_EXCHANGE: aValue >>= m_nLevExchange; break; + case WID_SIMILARITY_ADD: aValue >>= m_nLevAdd; break; + case WID_SIMILARITY_REMOVE : aValue >>= m_nLevRemove;break; + }; + +} + +uno::Any SwXTextSearch::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName); + bool bSet = false; + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + sal_Int16 nSet = 0; + switch(pEntry->nWID) + { + case WID_SEARCH_ALL : bSet = m_bAll; goto SET_BOOL; + case WID_WORDS: bSet = m_bWord; goto SET_BOOL; + case WID_BACKWARDS : bSet = m_bBack; goto SET_BOOL; + case WID_REGULAR_EXPRESSION : bSet = m_bExpr; goto SET_BOOL; + case WID_CASE_SENSITIVE : bSet = m_bCase; goto SET_BOOL; + //case WID_IN_SELECTION : bSet = bInSel; goto SET_BOOL; + case WID_STYLES : bSet = m_bStyles; goto SET_BOOL; + case WID_SIMILARITY : bSet = m_bSimilarity; goto SET_BOOL; + case WID_SIMILARITY_RELAX: bSet = m_bLevRelax; +SET_BOOL: + aRet <<= bSet; + break; + case WID_SIMILARITY_EXCHANGE: nSet = m_nLevExchange; goto SET_UINT16; + case WID_SIMILARITY_ADD: nSet = m_nLevAdd; goto SET_UINT16; + case WID_SIMILARITY_REMOVE : nSet = m_nLevRemove; +SET_UINT16: + aRet <<= nSet; + break; + } + + return aRet; +} + +void SwXTextSearch::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextSearch::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextSearch::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXTextSearch::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) +{ + OSL_FAIL("not implemented"); +} + +sal_Bool SwXTextSearch::getValueSearch() +{ + SolarMutexGuard aGuard; + return m_bIsValueSearch; +} + +void SwXTextSearch::setValueSearch(sal_Bool ValueSearch_) +{ + SolarMutexGuard aGuard; + m_bIsValueSearch = ValueSearch_; +} + +uno::Sequence< beans::PropertyValue > SwXTextSearch::getSearchAttributes() +{ + return m_pSearchProperties->GetProperties(); +} + +void SwXTextSearch::setSearchAttributes(const uno::Sequence< beans::PropertyValue >& rSearchAttribs) +{ + m_pSearchProperties->SetProperties(rSearchAttribs); +} + +uno::Sequence< beans::PropertyValue > SwXTextSearch::getReplaceAttributes() +{ + return m_pReplaceProperties->GetProperties(); +} + +void SwXTextSearch::setReplaceAttributes(const uno::Sequence< beans::PropertyValue >& rReplaceAttribs) +{ + m_pReplaceProperties->SetProperties(rReplaceAttribs); +} + +void SwXTextSearch::FillSearchItemSet(SfxItemSet& rSet) const +{ + m_pSearchProperties->FillItemSet(rSet, m_bIsValueSearch); +} + +void SwXTextSearch::FillReplaceItemSet(SfxItemSet& rSet) const +{ + m_pReplaceProperties->FillItemSet(rSet, m_bIsValueSearch); +} + +bool SwXTextSearch::HasSearchAttributes() const +{ + return m_pSearchProperties->HasAttributes(); +} + +bool SwXTextSearch::HasReplaceAttributes() const +{ + return m_pReplaceProperties->HasAttributes(); +} + +OUString SwXTextSearch::getImplementationName() +{ + return "SwXTextSearch"; +} + +sal_Bool SwXTextSearch::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXTextSearch::getSupportedServiceNames() +{ + return { "com.sun.star.util.SearchDescriptor", "com.sun.star.util.ReplaceDescriptor" }; +} + +void SwXTextSearch::FillSearchOptions( i18nutil::SearchOptions2& rSearchOpt ) const +{ + if( m_bSimilarity ) + { + rSearchOpt.AlgorithmType2 = util::SearchAlgorithms2::APPROXIMATE; + rSearchOpt.changedChars = m_nLevExchange; + rSearchOpt.deletedChars = m_nLevRemove; + rSearchOpt.insertedChars = m_nLevAdd; + if( m_bLevRelax ) + rSearchOpt.searchFlag |= util::SearchFlags::LEV_RELAXED; + } + else if( m_bExpr ) + { + rSearchOpt.AlgorithmType2 = util::SearchAlgorithms2::REGEXP; + } + else + { + rSearchOpt.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE; + } + + rSearchOpt.Locale = GetAppLanguageTag().getLocale(); + rSearchOpt.searchString = m_sSearchText; + rSearchOpt.replaceString = m_sReplaceText; + + if( !m_bCase ) + rSearchOpt.transliterateFlags |= TransliterationFlags::IGNORE_CASE; + if( m_bWord ) + rSearchOpt.searchFlag |= util::SearchFlags::NORM_WORD_ONLY; + +// bInSel: 1; // How is that possible? +// TODO: pSearch->bStyles! +// inSelection?? +// aSrchParam.SetSrchInSelection(TypeConversion::toBOOL(aVal)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unostyle.cxx b/sw/source/core/unocore/unostyle.cxx new file mode 100644 index 0000000000..94219281b5 --- /dev/null +++ b/sw/source/core/unocore/unostyle.cxx @@ -0,0 +1,5614 @@ +/* -*- 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 <sal/config.h> + +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <comphelper/propertysequence.hxx> +#include <hintids.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <svl/hint.hxx> +#include <svtools/ctrltool.hxx> +#include <svl/style.hxx> +#include <svl/itemiter.hxx> +#include <svl/listener.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <svx/pageitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/flstitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/paperinf.hxx> +#include <editeng/wghtitem.hxx> + +#include <autostyle_helper.hxx> +#include <pagedesc.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <docary.hxx> +#include <charfmt.hxx> +#include <cmdid.h> +#include <unomid.h> +#include <unomap.hxx> +#include <unostyle.hxx> +#include <unosett.hxx> +#include <docsh.hxx> +#include <paratr.hxx> +#include <unoprnms.hxx> +#include <shellio.hxx> +#include <docstyle.hxx> +#include <unotextbodyhf.hxx> +#include <fmthdft.hxx> +#include <fmtpdsc.hxx> +#include <strings.hrc> +#include <poolfmt.hxx> +#include <unoevent.hxx> +#include <fmtruby.hxx> +#include <SwStyleNameMapper.hxx> +#include <sfx2/printer.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/style/ParagraphStyleCategory.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <istyleaccess.hxx> +#include <fmtfsize.hxx> +#include <numrule.hxx> +#include <tblafmt.hxx> +#include <frameformats.hxx> + +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <svl/stylepool.hxx> +#include <svx/unobrushitemhelper.hxx> +#include <editeng/unoipset.hxx> +#include <editeng/memberids.h> +#include <svx/unomid.hxx> +#include <svx/unoshape.hxx> +#include <svx/xflbstit.hxx> +#include <svx/xflbmtit.hxx> +#include <swunohelper.hxx> +#include <svx/xbtmpit.hxx> + +#include <ccoll.hxx> +#include <hints.hxx> +#include <uiitems.hxx> + +#include <cassert> +#include <memory> +#include <set> +#include <string_view> +#include <limits> + +using namespace css; +using namespace css::io; +using namespace css::lang; +using namespace css::uno; + +namespace { + + // these should really be constexprs, but MSVC still is apparently too stupid for them + #define nPoolChrNormalRange (RES_POOLCHR_NORMAL_END - RES_POOLCHR_NORMAL_BEGIN) + #define nPoolChrHtmlRange (RES_POOLCHR_HTML_END - RES_POOLCHR_HTML_BEGIN) + #define nPoolCollTextRange ( RES_POOLCOLL_TEXT_END - RES_POOLCOLL_TEXT_BEGIN) + #define nPoolCollListsRange ( RES_POOLCOLL_LISTS_END - RES_POOLCOLL_LISTS_BEGIN) + #define nPoolCollExtraRange ( RES_POOLCOLL_EXTRA_END - RES_POOLCOLL_EXTRA_BEGIN) + #define nPoolCollRegisterRange ( RES_POOLCOLL_REGISTER_END - RES_POOLCOLL_REGISTER_BEGIN) + #define nPoolCollDocRange ( RES_POOLCOLL_DOC_END - RES_POOLCOLL_DOC_BEGIN) + #define nPoolCollHtmlRange ( RES_POOLCOLL_HTML_END - RES_POOLCOLL_HTML_BEGIN) + #define nPoolFrameRange ( RES_POOLFRM_END - RES_POOLFRM_BEGIN) + #define nPoolPageRange ( RES_POOLPAGE_END - RES_POOLPAGE_BEGIN) + #define nPoolNumRange ( RES_POOLNUMRULE_END - RES_POOLNUMRULE_BEGIN) + #define nPoolCollListsStackedStart ( nPoolCollTextRange) + #define nPoolCollExtraStackedStart ( nPoolCollListsStackedStart + nPoolCollListsRange) + #define nPoolCollRegisterStackedStart ( nPoolCollExtraStackedStart + nPoolCollExtraRange) + #define nPoolCollDocStackedStart ( nPoolCollRegisterStackedStart + nPoolCollRegisterRange) + #define nPoolCollHtmlStackedStart ( nPoolCollDocStackedStart + nPoolCollDocRange) + using paragraphstyle_t = std::remove_const<decltype(style::ParagraphStyleCategory::TEXT)>::type; + using collectionbits_t = sal_uInt16; + struct ParagraphStyleCategoryEntry + { + paragraphstyle_t m_eCategory; + SfxStyleSearchBits m_nSwStyleBits; + collectionbits_t m_nCollectionBits; + constexpr ParagraphStyleCategoryEntry(paragraphstyle_t eCategory, SfxStyleSearchBits nSwStyleBits, collectionbits_t nCollectionBits) + : m_eCategory(eCategory) + , m_nSwStyleBits(nSwStyleBits) + , m_nCollectionBits(nCollectionBits) + { } + }; + +constexpr ParagraphStyleCategoryEntry sParagraphStyleCategoryEntries[] +{ + { style::ParagraphStyleCategory::TEXT, SfxStyleSearchBits::SwText, COLL_TEXT_BITS }, + { style::ParagraphStyleCategory::CHAPTER, SfxStyleSearchBits::SwChapter, COLL_DOC_BITS }, + { style::ParagraphStyleCategory::LIST, SfxStyleSearchBits::SwList, COLL_LISTS_BITS }, + { style::ParagraphStyleCategory::INDEX, SfxStyleSearchBits::SwIndex, COLL_REGISTER_BITS }, + { style::ParagraphStyleCategory::EXTRA, SfxStyleSearchBits::SwExtra, COLL_EXTRA_BITS }, + { style::ParagraphStyleCategory::HTML, SfxStyleSearchBits::SwHtml, COLL_HTML_BITS } +}; + +class StyleFamilyEntry +{ +public: + template <SfxStyleFamily f> static StyleFamilyEntry Create(sal_uInt16 nPropMapType, SwGetPoolIdFromName aPoolId, OUString sName, TranslateId pResId) + { + return StyleFamilyEntry(f, nPropMapType, aPoolId, sName, pResId, GetCountOrName<f>, CreateStyle<f>, TranslateIndex<f>); + } + + SfxStyleFamily family() const { return m_eFamily; } + sal_uInt16 propMapType() const { return m_nPropMapType; } + const uno::Reference<beans::XPropertySetInfo>& xPSInfo() const { return m_xPSInfo; } + SwGetPoolIdFromName poolId() const { return m_aPoolId; } + const OUString& name() const { return m_sName; } + const TranslateId& resId() const { return m_pResId; } + + sal_Int32 getCountOrName(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) const { return m_fGetCountOrName(rDoc, pString, nIndex); } + css::uno::Reference<css::style::XStyle> createStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName) const { return m_fCreateStyle(pBasePool, pDocShell, sStyleName); } + sal_uInt16 translateIndex(const sal_uInt16 nIndex) const { return m_fTranslateIndex(nIndex); } + +private: + using GetCountOrName_t = sal_Int32 (*)(const SwDoc&, OUString*, sal_Int32); + using CreateStyle_t = uno::Reference<css::style::XStyle>(*)(SfxStyleSheetBasePool*, SwDocShell*, const OUString&); + using TranslateIndex_t = sal_uInt16(*)(const sal_uInt16); + SfxStyleFamily m_eFamily; + sal_uInt16 m_nPropMapType; + uno::Reference<beans::XPropertySetInfo> m_xPSInfo; + SwGetPoolIdFromName m_aPoolId; + OUString m_sName; + TranslateId m_pResId; + GetCountOrName_t m_fGetCountOrName; + CreateStyle_t m_fCreateStyle; + TranslateIndex_t m_fTranslateIndex; + StyleFamilyEntry(SfxStyleFamily eFamily, sal_uInt16 nPropMapType, SwGetPoolIdFromName aPoolId, OUString sName, TranslateId pResId, GetCountOrName_t fGetCountOrName, CreateStyle_t fCreateStyle, TranslateIndex_t fTranslateIndex) + : m_eFamily(eFamily) + , m_nPropMapType(nPropMapType) + , m_xPSInfo(aSwMapProvider.GetPropertySet(nPropMapType)->getPropertySetInfo()) + , m_aPoolId(aPoolId) + , m_sName(std::move(sName)) + , m_pResId(pResId) + , m_fGetCountOrName(fGetCountOrName) + , m_fCreateStyle(fCreateStyle) + , m_fTranslateIndex(fTranslateIndex) + { } + template<SfxStyleFamily> static inline sal_Int32 GetCountOrName(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex); + template<SfxStyleFamily> static inline css::uno::Reference<css::style::XStyle> CreateStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName); + template<SfxStyleFamily> static inline sal_uInt16 TranslateIndex(const sal_uInt16 nIndex) { return nIndex; } +}; + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Char>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + const sal_uInt16 nBaseCount = nPoolChrHtmlRange + nPoolChrNormalRange; + nIndex -= nBaseCount; + sal_Int32 nCount = 0; + for(auto pFormat : *rDoc.GetCharFormats()) + { + if(pFormat->IsDefault() && pFormat != rDoc.GetDfltCharFormat()) + continue; + if(!IsPoolUserFormat(pFormat->GetPoolFormatId())) + continue; + if(nIndex == nCount) + { + // the default character format needs to be set to "Default!" + if(rDoc.GetDfltCharFormat() == pFormat) + *pString = SwResId(STR_POOLCHR_STANDARD); + else + *pString = pFormat->GetName(); + break; + } + ++nCount; + } + return nCount + nBaseCount; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Para>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + const sal_uInt16 nBaseCount = nPoolCollHtmlStackedStart + nPoolCollHtmlRange; + nIndex -= nBaseCount; + sal_Int32 nCount = 0; + for(auto pColl : *rDoc.GetTextFormatColls()) + { + if(pColl->IsDefault()) + continue; + if(!IsPoolUserFormat(pColl->GetPoolFormatId())) + continue; + if(nIndex == nCount) + { + *pString = pColl->GetName(); + break; + } + ++nCount; + } + return nCount + nBaseCount; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Frame>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + nIndex -= nPoolFrameRange; + sal_Int32 nCount = 0; + for(const auto pFormat : *rDoc.GetFrameFormats()) + { + if(pFormat->IsDefault() || pFormat->IsAuto()) + continue; + if(!IsPoolUserFormat(pFormat->GetPoolFormatId())) + continue; + if(nIndex == nCount) + { + *pString = pFormat->GetName(); + break; + } + ++nCount; + } + return nCount + nPoolFrameRange; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Page>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + nIndex -= nPoolPageRange; + sal_Int32 nCount = 0; + const size_t nArrLen = rDoc.GetPageDescCnt(); + for(size_t i = 0; i < nArrLen; ++i) + { + const SwPageDesc& rDesc = rDoc.GetPageDesc(i); + if(!IsPoolUserFormat(rDesc.GetPoolFormatId())) + continue; + if(nIndex == nCount) + { + *pString = rDesc.GetName(); + break; + } + ++nCount; + } + nCount += nPoolPageRange; + return nCount; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Pseudo>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + nIndex -= nPoolNumRange; + sal_Int32 nCount = 0; + for(const auto pRule : rDoc.GetNumRuleTable()) + { + if(pRule->IsAutoRule()) + continue; + if(!IsPoolUserFormat(pRule->GetPoolFormatId())) + continue; + if(nIndex == nCount) + { + *pString = pRule->GetName(); + break; + } + ++nCount; + } + return nCount + nPoolNumRange; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Table>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + if (!rDoc.HasTableStyles()) + return 0; + + const auto pAutoFormats = &rDoc.GetTableStyles(); + const sal_Int32 nCount = pAutoFormats->size(); + if (0 <= nIndex && nIndex < nCount) + *pString = pAutoFormats->operator[](nIndex).GetName(); + + return nCount; +} + +template<> +sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Cell>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) +{ + const auto& rAutoFormats = rDoc.GetTableStyles(); + const auto& rTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap(); + const sal_Int32 nUsedCellStylesCount = rAutoFormats.size() * rTableTemplateMap.size(); + const sal_Int32 nCount = nUsedCellStylesCount + rDoc.GetCellStyles().size(); + if (0 <= nIndex && nIndex < nCount) + { + if (nUsedCellStylesCount > nIndex) + { + const sal_Int32 nAutoFormat = nIndex / rTableTemplateMap.size(); + const sal_Int32 nBoxFormat = rTableTemplateMap[nIndex % rTableTemplateMap.size()]; + const SwTableAutoFormat& rTableFormat = rAutoFormats[nAutoFormat]; + SwStyleNameMapper::FillProgName(rTableFormat.GetName(), *pString, SwGetPoolIdFromName::TabStyle); + *pString += rTableFormat.GetTableTemplateCellSubName(rTableFormat.GetBoxFormat(nBoxFormat)); + } + else + *pString = rDoc.GetCellStyles()[nIndex-nUsedCellStylesCount].GetName(); + } + return nCount; +} + +template<> +sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Char>(const sal_uInt16 nIndex) +{ + static_assert(nPoolChrNormalRange > 0 && nPoolChrHtmlRange > 0, "invalid pool range"); + if (nIndex < nPoolChrNormalRange) + return nIndex + RES_POOLCHR_NORMAL_BEGIN; + else if (nIndex < (nPoolChrHtmlRange + nPoolChrNormalRange)) + return nIndex + RES_POOLCHR_HTML_BEGIN - nPoolChrNormalRange; + throw lang::IndexOutOfBoundsException(); +} + +template<> +sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Para>(const sal_uInt16 nIndex) +{ + static_assert(nPoolCollTextRange > 0 && nPoolCollListsRange > 0 && nPoolCollExtraRange > 0 && nPoolCollRegisterRange > 0 && nPoolCollDocRange > 0 && nPoolCollHtmlRange > 0, "weird pool range"); + if (nIndex < nPoolCollListsStackedStart) + return nIndex + RES_POOLCOLL_TEXT_BEGIN; + else if (nIndex < nPoolCollExtraStackedStart) + return nIndex + RES_POOLCOLL_LISTS_BEGIN - nPoolCollListsStackedStart; + else if (nIndex < nPoolCollRegisterStackedStart) + return nIndex + RES_POOLCOLL_EXTRA_BEGIN - nPoolCollExtraStackedStart; + else if (nIndex < nPoolCollDocStackedStart) + return nIndex + RES_POOLCOLL_REGISTER_BEGIN - nPoolCollRegisterStackedStart; + else if (nIndex < nPoolCollHtmlStackedStart) + return nIndex + RES_POOLCOLL_DOC_BEGIN - nPoolCollDocStackedStart; + else if (nIndex < nPoolCollHtmlStackedStart + nPoolCollTextRange) + return nIndex + RES_POOLCOLL_HTML_BEGIN - nPoolCollHtmlStackedStart; + throw lang::IndexOutOfBoundsException(); +} + +template<> +sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Page>(const sal_uInt16 nIndex) +{ + if (nIndex < nPoolPageRange) + return nIndex + RES_POOLPAGE_BEGIN; + throw lang::IndexOutOfBoundsException(); +} + +template<> +sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Frame>(const sal_uInt16 nIndex) +{ + if (nIndex < nPoolFrameRange) + return nIndex + RES_POOLFRM_BEGIN; + throw lang::IndexOutOfBoundsException(); +} + +template<> +sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Pseudo>(const sal_uInt16 nIndex) +{ + if (nIndex < nPoolNumRange) + return nIndex + RES_POOLNUMRULE_BEGIN; + throw lang::IndexOutOfBoundsException(); +} + +const std::vector<StyleFamilyEntry>& lcl_GetStyleFamilyEntries() +{ + static const std::vector<StyleFamilyEntry> our_pStyleFamilyEntries{ + StyleFamilyEntry::Create<SfxStyleFamily::Char> (PROPERTY_MAP_CHAR_STYLE, SwGetPoolIdFromName::ChrFmt, "CharacterStyles", STR_STYLE_FAMILY_CHARACTER), + StyleFamilyEntry::Create<SfxStyleFamily::Para> (PROPERTY_MAP_PARA_STYLE, SwGetPoolIdFromName::TxtColl, "ParagraphStyles", STR_STYLE_FAMILY_PARAGRAPH), + StyleFamilyEntry::Create<SfxStyleFamily::Page> (PROPERTY_MAP_PAGE_STYLE, SwGetPoolIdFromName::PageDesc, "PageStyles", STR_STYLE_FAMILY_PAGE), + StyleFamilyEntry::Create<SfxStyleFamily::Frame> (PROPERTY_MAP_FRAME_STYLE, SwGetPoolIdFromName::FrmFmt, "FrameStyles", STR_STYLE_FAMILY_FRAME), + StyleFamilyEntry::Create<SfxStyleFamily::Pseudo>(PROPERTY_MAP_NUM_STYLE, SwGetPoolIdFromName::NumRule, "NumberingStyles", STR_STYLE_FAMILY_NUMBERING), + StyleFamilyEntry::Create<SfxStyleFamily::Table> (PROPERTY_MAP_TABLE_STYLE, SwGetPoolIdFromName::TabStyle, "TableStyles", STR_STYLE_FAMILY_TABLE), + StyleFamilyEntry::Create<SfxStyleFamily::Cell> (PROPERTY_MAP_CELL_STYLE, SwGetPoolIdFromName::CellStyle, "CellStyles", STR_STYLE_FAMILY_CELL), + }; + return our_pStyleFamilyEntries; +} + +class SwStyleBase_Impl +{ +private: + SwDoc& m_rDoc; + const SwPageDesc* m_pOldPageDesc; + rtl::Reference<SwDocStyleSheet> m_xNewBase; + SfxItemSet* m_pItemSet; + std::unique_ptr<SfxItemSet> m_pMyItemSet; + OUString m_rStyleName; + const SwAttrSet* m_pParentStyle; +public: + SwStyleBase_Impl(SwDoc& rSwDoc, OUString aName, const SwAttrSet* pParentStyle) + : m_rDoc(rSwDoc) + , m_pOldPageDesc(nullptr) + , m_pItemSet(nullptr) + , m_rStyleName(std::move(aName)) + , m_pParentStyle(pParentStyle) + { } + + rtl::Reference<SwDocStyleSheet>& getNewBase() + { + return m_xNewBase; + } + + void setNewBase(SwDocStyleSheet* pNew) + { + m_xNewBase = pNew; + } + + bool HasItemSet() const + { + return m_xNewBase.is(); + } + + SfxItemSet& GetItemSet() + { + assert(m_xNewBase.is()); + if(!m_pItemSet) + { + m_pMyItemSet.reset(new SfxItemSet(m_xNewBase->GetItemSet())); + m_pItemSet = m_pMyItemSet.get(); + + // set parent style to have the correct XFillStyle setting as XFILL_NONE + if(!m_pItemSet->GetParent() && m_pParentStyle) + m_pItemSet->SetParent(m_pParentStyle); + } + return *m_pItemSet; + } + + const SwPageDesc* GetOldPageDesc(); + + // still a hack, but a bit more explicit and with a proper scope + struct ItemSetOverrider + { + SwStyleBase_Impl& m_rStyleBase; + SfxItemSet* m_pOldSet; + ItemSetOverrider(SwStyleBase_Impl& rStyleBase, SfxItemSet* pTemp) + : m_rStyleBase(rStyleBase) + , m_pOldSet(m_rStyleBase.m_pItemSet) + { m_rStyleBase.m_pItemSet = pTemp; } + ~ItemSetOverrider() + { m_rStyleBase.m_pItemSet = m_pOldSet; }; + }; +}; + +class SwStyleProperties_Impl; +class SwXStyle : public cppu::WeakImplHelper + < + css::style::XStyle, + css::beans::XPropertySet, + css::beans::XMultiPropertySet, + css::lang::XServiceInfo, + css::lang::XUnoTunnel, + css::beans::XPropertyState, + css::beans::XMultiPropertyStates + > + , public SfxListener + , public SvtListener +{ + SwDoc* m_pDoc; + OUString m_sStyleName; + const StyleFamilyEntry& m_rEntry; + bool m_bIsDescriptor; + bool m_bIsConditional; + OUString m_sParentStyleName; + +protected: + SfxStyleSheetBasePool* m_pBasePool; + std::unique_ptr<SwStyleProperties_Impl> m_pPropertiesImpl; + css::uno::Reference<css::container::XNameAccess> m_xStyleFamily; + css::uno::Reference<css::beans::XPropertySet> m_xStyleData; + + template<sal_uInt16> + void SetPropertyValue(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any&, SwStyleBase_Impl&); + void SetPropertyValues_Impl( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ); + SfxStyleSheetBase* GetStyleSheetBase(); + void PrepareStyleBase(SwStyleBase_Impl& rBase); + template<sal_uInt16> + uno::Any GetStyleProperty(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase); + uno::Any GetStyleProperty_Impl(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase); + uno::Any GetPropertyValue_Impl(const SfxItemPropertySet* pPropSet, SwStyleBase_Impl& rBase, const OUString& rPropertyName); + +public: + SwXStyle(SwDoc* pDoc, SfxStyleFamily eFam, bool bConditional = false); + SwXStyle(SfxStyleSheetBasePool* pPool, SfxStyleFamily eFamily, SwDoc* pDoc, const OUString& rStyleName); + virtual ~SwXStyle() override; + + + static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId(); + + //XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + + //XNamed + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName(const OUString& Name_) override; + + //XStyle + virtual sal_Bool SAL_CALL isUserDefined() override; + virtual sal_Bool SAL_CALL isInUse() override; + virtual OUString SAL_CALL getParentStyle() override; + virtual void SAL_CALL setParentStyle(const OUString& aParentStyle) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) override + { OSL_FAIL("not implemented"); }; + virtual void SAL_CALL removePropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) override + { OSL_FAIL("not implemented"); }; + virtual void SAL_CALL addVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) override + { OSL_FAIL("not implemented"); }; + virtual void SAL_CALL removeVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) override + { OSL_FAIL("not implemented"); }; + + //XMultiPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >&, const css::uno::Reference< css::beans::XPropertiesChangeListener >& ) override + {}; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& ) override + {}; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >&, const css::uno::Reference< css::beans::XPropertiesChangeListener >& ) override + {}; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + //XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return {"SwXStyle"}; }; + virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override + { return cppu::supportsService(this, rServiceName); }; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //SfxListener + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + //SvtListener + virtual void Notify(const SfxHint&) override; + const OUString& GetStyleName() const { return m_sStyleName;} + SfxStyleFamily GetFamily() const {return m_rEntry.family();} + + bool IsDescriptor() const {return m_bIsDescriptor;} + bool IsConditional() const { return m_bIsConditional;} + const OUString& GetParentStyleName() const { return m_sParentStyleName;} + void SetDoc(SwDoc* pDc, SfxStyleSheetBasePool* pPool) + { + m_bIsDescriptor = false; m_pDoc = pDc; + m_pBasePool = pPool; + SfxListener::StartListening(*m_pBasePool); + } + SwDoc* GetDoc() const { return m_pDoc; } + void Invalidate(); + void ApplyDescriptorProperties(); + void SetStyleName(const OUString& rSet){ m_sStyleName = rSet;} + /// @throws beans::PropertyVetoException + /// @throws lang::IllegalArgumentException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + void SetStyleProperty(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& rBase); + void PutItemToSet(const SvxSetItem* pSetItem, const SfxItemPropertySet& rPropSet, const SfxItemPropertyMapEntry& rEntry, const uno::Any& rVal, SwStyleBase_Impl& rBaseImpl); +}; + +typedef cppu::ImplInheritanceHelper< SwXStyle, css::document::XEventsSupplier> SwXFrameStyle_Base; +class SwXFrameStyle + : public SwXFrameStyle_Base + , public sw::ICoreFrameStyle +{ +public: + SwXFrameStyle(SfxStyleSheetBasePool& rPool, + SwDoc* pDoc, + const OUString& rStyleName) : + SwXFrameStyle_Base(&rPool, SfxStyleFamily::Frame, pDoc, rStyleName){} + explicit SwXFrameStyle(SwDoc *pDoc); + + virtual css::uno::Reference< css::container::XNameReplace > SAL_CALL getEvents( ) override; + + //ICoreStyle + virtual void SetItem(sal_uInt16 eAtr, const SfxPoolItem& rItem) override; + virtual const SfxPoolItem* GetItem(sal_uInt16 eAtr) override; + virtual css::document::XEventsSupplier& GetEventsSupplier() override + { return *this; }; +}; + +class SwXPageStyle + : public SwXStyle +{ +protected: + void SetPropertyValues_Impl( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ); + css::uno::Sequence< css::uno::Any > GetPropertyValues_Impl( const css::uno::Sequence< OUString >& aPropertyNames ); + +public: + SwXPageStyle(SfxStyleSheetBasePool& rPool, SwDocShell* pDocSh, const OUString& rStyleName); + explicit SwXPageStyle(SwDocShell* pDocSh); + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; +}; + +class SwStyleProperties_Impl +{ + const SfxItemPropertyMap& mrMap; + std::map<OUString, uno::Any> m_vPropertyValues; +public: + explicit SwStyleProperties_Impl(const SfxItemPropertyMap& rMap) + : mrMap(rMap) + { } + + bool AllowsKey(std::u16string_view rName) + { + return mrMap.hasPropertyByName(rName); + } + bool SetProperty(const OUString& rName, const uno::Any& rValue) + { + if(!AllowsKey(rName)) + return false; + m_vPropertyValues[rName] = rValue; + return true; + } + void GetProperty(const OUString& rName, const uno::Any*& pAny) + { + if(!AllowsKey(rName)) + { + pAny = nullptr; + return; + } + pAny = &m_vPropertyValues[rName]; + return; + } + bool ClearProperty( const OUString& rName ) + { + if(!AllowsKey(rName)) + return false; + m_vPropertyValues[rName] = uno::Any(); + return true; + } + void ClearAllProperties( ) + { m_vPropertyValues.clear(); } + void Apply(SwXStyle& rStyle) + { + for(const auto& rPropertyPair : m_vPropertyValues) + { + if(rPropertyPair.second.hasValue()) + rStyle.setPropertyValue(rPropertyPair.first, rPropertyPair.second); + } + } +}; + +template<SfxStyleFamily eFamily> +css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName) +{ + return pBasePool ? new SwXStyle(pBasePool, eFamily, pDocShell->GetDoc(), sStyleName) : new SwXStyle(pDocShell->GetDoc(), eFamily, false); +} + +template<> +css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Frame>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName) +{ + return pBasePool ? new SwXFrameStyle(*pBasePool, pDocShell->GetDoc(), sStyleName) : new SwXFrameStyle(pDocShell->GetDoc()); +} + +template<> +css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Page>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName) +{ + return pBasePool ? new SwXPageStyle(*pBasePool, pDocShell, sStyleName) : new SwXPageStyle(pDocShell); +} + +template<> +css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Table>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName) +{ + return SwXTextTableStyle::CreateXTextTableStyle(pDocShell, sStyleName); +} + +template<> +css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Cell>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName) +{ + return SwXTextCellStyle::CreateXTextCellStyle(pDocShell, sStyleName); +} + +class XStyleFamily : public cppu::WeakImplHelper +< + container::XNameContainer, + lang::XServiceInfo, + container::XIndexAccess, + beans::XPropertySet +> +, public SfxListener +{ + const StyleFamilyEntry& m_rEntry; + SfxStyleSheetBasePool* m_pBasePool; + SwDocShell* m_pDocShell; + + SwXStyle* FindStyle(std::u16string_view rStyleName) const; + sal_Int32 GetCountOrName(OUString* pString, sal_Int32 nIndex = SAL_MAX_INT32) + { return m_rEntry.getCountOrName(*m_pDocShell->GetDoc(), pString, nIndex); }; + static const StyleFamilyEntry& InitEntry(SfxStyleFamily eFamily) + { + auto& entries = lcl_GetStyleFamilyEntries(); + const auto pEntry = std::find_if(entries.begin(), entries.end(), + [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; }); + assert(pEntry != entries.end()); + return *pEntry; + } +public: + XStyleFamily(SwDocShell* pDocShell, const SfxStyleFamily eFamily) + : m_rEntry(InitEntry(eFamily)) + , m_pBasePool(pDocShell->GetStyleSheetPool()) + , m_pDocShell(pDocShell) + { + if (m_pBasePool) //tdf#124142 html docs can have no styles + StartListening(*m_pBasePool); + } + + //XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override + { + SolarMutexGuard aGuard; + return GetCountOrName(nullptr); + }; + virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override; + + //XElementAccess + virtual uno::Type SAL_CALL getElementType( ) override + { return cppu::UnoType<style::XStyle>::get(); }; + virtual sal_Bool SAL_CALL hasElements( ) override + { + if(!m_pBasePool) + throw uno::RuntimeException(); + return true; + } + + //XNameAccess + virtual uno::Any SAL_CALL getByName(const OUString& Name) override; + virtual uno::Sequence< OUString > SAL_CALL getElementNames() override; + virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override; + + //XNameContainer + virtual void SAL_CALL insertByName(const OUString& Name, const uno::Any& Element) override; + virtual void SAL_CALL replaceByName(const OUString& Name, const uno::Any& Element) override; + virtual void SAL_CALL removeByName(const OUString& Name) override; + + //XPropertySet + virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override + { return {}; }; + virtual void SAL_CALL setPropertyValue( const OUString&, const uno::Any&) override + { SAL_WARN("sw.uno", "###unexpected!"); }; + virtual uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override + { SAL_WARN("sw.uno", "###unexpected!"); }; + virtual void SAL_CALL removePropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override + { SAL_WARN("sw.uno", "###unexpected!"); }; + virtual void SAL_CALL addVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override + { SAL_WARN("sw.uno", "###unexpected!"); }; + virtual void SAL_CALL removeVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override + { SAL_WARN("sw.uno", "###unexpected!"); }; + + //SfxListener + virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override + { + if(rHint.GetId() == SfxHintId::Dying) + { + m_pBasePool = nullptr; + m_pDocShell = nullptr; + EndListening(rBC); + } + } + + //XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return {"XStyleFamily"}; }; + virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override + { return cppu::supportsService(this, rServiceName); }; + virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { return { "com.sun.star.style.StyleFamily" }; } +}; +} + +OUString SwXStyleFamilies::getImplementationName() + { return {"SwXStyleFamilies"}; } + +sal_Bool SwXStyleFamilies::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXStyleFamilies::getSupportedServiceNames() + { return { "com.sun.star.style.StyleFamilies" }; } + +SwXStyleFamilies::SwXStyleFamilies(SwDocShell& rDocShell) : + SwUnoCollection(rDocShell.GetDoc()), + m_pDocShell(&rDocShell) + { } + +SwXStyleFamilies::~SwXStyleFamilies() + { } + +uno::Any SAL_CALL SwXStyleFamilies::getByName(const OUString& Name) +{ + SolarMutexGuard aGuard; + if(!IsValid()) + throw uno::RuntimeException(); + auto& entries(lcl_GetStyleFamilyEntries()); + const auto pEntry = std::find_if(entries.begin(), entries.end(), + [&Name] (const StyleFamilyEntry& e) { return e.name() == Name; }); + if(pEntry == entries.end()) + throw container::NoSuchElementException(); + return getByIndex(pEntry - entries.begin()); +} + +uno::Sequence< OUString > SwXStyleFamilies::getElementNames() +{ + auto& entries(lcl_GetStyleFamilyEntries()); + uno::Sequence<OUString> aNames(entries.size()); + std::transform(entries.begin(), entries.end(), + aNames.getArray(), [] (const StyleFamilyEntry& e) { return e.name(); }); + return aNames; +} + +sal_Bool SwXStyleFamilies::hasByName(const OUString& Name) +{ + auto& entries(lcl_GetStyleFamilyEntries()); + return std::any_of(entries.begin(), entries.end(), + [&Name] (const StyleFamilyEntry& e) { return e.name() == Name; }); +} + +sal_Int32 SwXStyleFamilies::getCount() +{ + return lcl_GetStyleFamilyEntries().size(); +} + +uno::Any SwXStyleFamilies::getByIndex(sal_Int32 nIndex) +{ + auto& entries(lcl_GetStyleFamilyEntries()); + SolarMutexGuard aGuard; + if(nIndex < 0 || o3tl::make_unsigned(nIndex) >= entries.size()) + throw lang::IndexOutOfBoundsException(); + if(!IsValid()) + throw uno::RuntimeException(); + auto eFamily = entries[nIndex].family(); + assert(eFamily != SfxStyleFamily::All); + auto& rxFamily = m_vFamilies[eFamily]; + if(!rxFamily.is()) + rxFamily = new XStyleFamily(m_pDocShell, eFamily); + return uno::Any(rxFamily); +} + +uno::Type SwXStyleFamilies::getElementType() +{ + return cppu::UnoType<container::XNameContainer>::get(); +} + +sal_Bool SwXStyleFamilies::hasElements() + { return true; } + +void SwXStyleFamilies::loadStylesFromURL(const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& aOptions) +{ + SolarMutexGuard aGuard; + if(!IsValid() || rURL.isEmpty()) + throw uno::RuntimeException(); + SwgReaderOption aOpt; + aOpt.SetFrameFormats(true); + aOpt.SetTextFormats(true); + aOpt.SetPageDescs(true); + aOpt.SetNumRules(true); + aOpt.SetMerge(false); + for(const auto& rProperty: aOptions) + { + bool bValue = false; + if(rProperty.Value.getValueType() == cppu::UnoType<bool>::get()) + bValue = rProperty.Value.get<bool>(); + + if(rProperty.Name == UNO_NAME_OVERWRITE_STYLES) + aOpt.SetMerge(!bValue); + else if(rProperty.Name == UNO_NAME_LOAD_NUMBERING_STYLES) + aOpt.SetNumRules(bValue); + else if(rProperty.Name == UNO_NAME_LOAD_PAGE_STYLES) + aOpt.SetPageDescs(bValue); + else if(rProperty.Name == UNO_NAME_LOAD_FRAME_STYLES) + aOpt.SetFrameFormats(bValue); + else if(rProperty.Name == UNO_NAME_LOAD_TEXT_STYLES) + aOpt.SetTextFormats(bValue); + else if(rProperty.Name == "InputStream") + { + Reference<XInputStream> xInputStream; + if (!(rProperty.Value >>= xInputStream)) + throw IllegalArgumentException("Parameter 'InputStream' could not be converted to " + "type 'com::sun::star::io::XInputStream'", + nullptr, 0); + + aOpt.SetInputStream(xInputStream); + + } + } + const ErrCodeMsg nErr = m_pDocShell->LoadStylesFromFile( rURL, aOpt, true ); + if(nErr) + throw io::IOException(); +} + +uno::Sequence< beans::PropertyValue > SwXStyleFamilies::getStyleLoaderOptions() +{ + const uno::Any aVal(true); + return comphelper::InitPropertySequence({ + { UNO_NAME_LOAD_TEXT_STYLES, aVal }, + { UNO_NAME_LOAD_FRAME_STYLES, aVal }, + { UNO_NAME_LOAD_PAGE_STYLES, aVal }, + { UNO_NAME_LOAD_NUMBERING_STYLES, aVal }, + { UNO_NAME_OVERWRITE_STYLES, aVal } + }); +} + +static bool lcl_GetHeaderFooterItem( + SfxItemSet const& rSet, std::u16string_view rPropName, bool const bFooter, + SvxSetItem const*& o_rpItem) +{ + o_rpItem = rSet.GetItemIfSet( + bFooter ? SID_ATTR_PAGE_FOOTERSET : SID_ATTR_PAGE_HEADERSET, + false); + if (!o_rpItem && + rPropName == UNO_NAME_FIRST_IS_SHARED) + { // fdo#79269 header may not exist, check footer then + o_rpItem = rSet.GetItemIfSet( + (!bFooter) ? SID_ATTR_PAGE_FOOTERSET : SID_ATTR_PAGE_HEADERSET, + false); + } + return o_rpItem; +} + +uno::Reference<css::style::XStyle> SwXStyleFamilies::CreateStyle(SfxStyleFamily eFamily, SwDoc& rDoc) +{ + auto& entries(lcl_GetStyleFamilyEntries()); + const auto pEntry = std::find_if(entries.begin(), entries.end(), + [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; }); + return pEntry == entries.end() ? nullptr : pEntry->createStyle(nullptr, rDoc.GetDocShell(), ""); +} + +// FIXME: Ugly special casing that should die. +uno::Reference<css::style::XStyle> SwXStyleFamilies::CreateStyleCondParagraph(SwDoc& rDoc) + { return new SwXStyle(&rDoc, SfxStyleFamily::Para, true); }; + +uno::Any XStyleFamily::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(nIndex < 0) + throw lang::IndexOutOfBoundsException(); + if(!m_pBasePool) + throw uno::RuntimeException(); + OUString sStyleName; + try + { + SwStyleNameMapper::FillUIName(m_rEntry.translateIndex(nIndex), sStyleName); + } catch(...) {} + if (sStyleName.isEmpty()) + GetCountOrName(&sStyleName, nIndex); + if(sStyleName.isEmpty()) + throw lang::IndexOutOfBoundsException(); + return getByName(sStyleName); +} + +uno::Any XStyleFamily::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + OUString sStyleName; + SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId()); + if(!m_pBasePool) + throw uno::RuntimeException(); + SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family()); + if(!pBase) + throw container::NoSuchElementException(rName); + uno::Reference<style::XStyle> xStyle = FindStyle(sStyleName); + if(!xStyle.is()) + xStyle = m_rEntry.createStyle(m_pBasePool, m_pDocShell, m_rEntry.family() == SfxStyleFamily::Frame ? pBase->GetName() : sStyleName); + return uno::Any(xStyle); +} + +uno::Sequence<OUString> XStyleFamily::getElementNames() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + std::vector<OUString> vRet; + std::unique_ptr<SfxStyleSheetIterator> pIt = m_pBasePool->CreateIterator(m_rEntry.family()); + for (SfxStyleSheetBase* pStyle = pIt->First(); pStyle; pStyle = pIt->Next()) + { + OUString sName; + SwStyleNameMapper::FillProgName(pStyle->GetName(), sName, m_rEntry.poolId()); + vRet.push_back(sName); + } + return comphelper::containerToSequence(vRet); +} + +sal_Bool XStyleFamily::hasByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + OUString sStyleName; + SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId()); + SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family()); + return nullptr != pBase; +} + +void XStyleFamily::insertByName(const OUString& rName, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + OUString sStyleName; + SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId()); + SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family()); + if (pBase) + throw container::ElementExistException(); + if(rElement.getValueType().getTypeClass() != uno::TypeClass_INTERFACE) + throw lang::IllegalArgumentException(); + if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId()) + { + // handle cell style + uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>(); + SwXTextCellStyle* pNewStyle = dynamic_cast<SwXTextCellStyle*>(xStyle.get()); + if (!pNewStyle) + throw lang::IllegalArgumentException(); + + pNewStyle->setName(sStyleName); // insertByName sets the element name + m_pDocShell->GetDoc()->GetCellStyles().AddBoxFormat(*pNewStyle->GetBoxFormat(), sStyleName); + pNewStyle->SetPhysical(); + } + else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId()) + { + // handle table style + uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>(); + SwXTextTableStyle* pNewStyle = dynamic_cast<SwXTextTableStyle*>(xStyle.get()); + if (!pNewStyle) + throw lang::IllegalArgumentException(); + + pNewStyle->setName(sStyleName); // insertByName sets the element name + m_pDocShell->GetDoc()->GetTableStyles().AddAutoFormat(*pNewStyle->GetTableFormat()); + pNewStyle->SetPhysical(); + } + else + { + uno::Reference<lang::XUnoTunnel> xStyleTunnel = rElement.get<uno::Reference<lang::XUnoTunnel>>(); + SwXStyle* pNewStyle = comphelper::getFromUnoTunnel<SwXStyle>(xStyleTunnel); + if (!pNewStyle || !pNewStyle->IsDescriptor() || pNewStyle->GetFamily() != m_rEntry.family()) + throw lang::IllegalArgumentException(); + + SfxStyleSearchBits nMask = SfxStyleSearchBits::All; + if(m_rEntry.family() == SfxStyleFamily::Para && !pNewStyle->IsConditional()) + nMask &= ~SfxStyleSearchBits::SwCondColl; + auto pStyle = &m_pBasePool->Make(sStyleName, m_rEntry.family(), nMask); + pNewStyle->SetDoc(m_pDocShell->GetDoc(), m_pBasePool); + pNewStyle->SetStyleName(sStyleName); + pStyle->SetParent(pNewStyle->GetParentStyleName()); + // after all, we still need to apply the properties of the descriptor + pNewStyle->ApplyDescriptorProperties(); + } +} + +void XStyleFamily::replaceByName(const OUString& rName, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + OUString sStyleName; + SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId()); + SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family()); + // replacements only for userdefined styles + if(!pBase) + throw container::NoSuchElementException(); + if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId()) + { + // handle cell styles, don't call on assigned cell styles (TableStyle child) + OUString sParent; + SwBoxAutoFormat* pBoxAutoFormat = SwXTextCellStyle::GetBoxAutoFormat(m_pDocShell, sStyleName, &sParent); + if (pBoxAutoFormat && sParent.isEmpty())// if parent exists then this style is assigned to a table style. Don't replace. + { + uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>(); + SwXTextCellStyle* pStyleToReplaceWith = dynamic_cast<SwXTextCellStyle*>(xStyle.get()); + if (!pStyleToReplaceWith) + throw lang::IllegalArgumentException(); + + pStyleToReplaceWith->setName(sStyleName); + *pBoxAutoFormat = *pStyleToReplaceWith->GetBoxFormat(); + pStyleToReplaceWith->SetPhysical(); + } + } + else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId()) + { + // handle table styles + SwTableAutoFormat* pTableAutoFormat = SwXTextTableStyle::GetTableAutoFormat(m_pDocShell, sStyleName); + if (pTableAutoFormat) + { + uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>(); + SwXTextTableStyle* pStyleToReplaceWith = dynamic_cast<SwXTextTableStyle*>(xStyle.get()); + if (!pStyleToReplaceWith) + throw lang::IllegalArgumentException(); + + pStyleToReplaceWith->setName(sStyleName); + *pTableAutoFormat = *pStyleToReplaceWith->GetTableFormat(); + pStyleToReplaceWith->SetPhysical(); + } + } + else + { + if(!pBase->IsUserDefined()) + throw lang::IllegalArgumentException(); + //if there's an object available to this style then it must be invalidated + uno::Reference<style::XStyle> xStyle = FindStyle(pBase->GetName()); + if(xStyle.is()) + { + SwXStyle* pStyle = comphelper::getFromUnoTunnel<SwXStyle>(xStyle); + if(pStyle) + pStyle->Invalidate(); + } + m_pBasePool->Remove(pBase); + insertByName(rName, rElement); + } +} + +void XStyleFamily::removeByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + OUString sName; + SwStyleNameMapper::FillUIName(rName, sName, m_rEntry.poolId()); + SfxStyleSheetBase* pBase = m_pBasePool->Find(sName, m_rEntry.family()); + if(!pBase) + throw container::NoSuchElementException(); + if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId()) + { + // handle cell style + m_pDocShell->GetDoc()->GetCellStyles().RemoveBoxFormat(rName); + } + else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId()) + { + // handle table style + m_pDocShell->GetDoc()->GetTableStyles().EraseAutoFormat(rName); + } + else + m_pBasePool->Remove(pBase); +} + +uno::Any SAL_CALL XStyleFamily::getPropertyValue( const OUString& sPropertyName ) +{ + if(sPropertyName != "DisplayName") + throw beans::UnknownPropertyException( "unknown property: " + sPropertyName, getXWeak() ); + SolarMutexGuard aGuard; + return uno::Any(SwResId(m_rEntry.resId())); +} + + +SwXStyle* XStyleFamily::FindStyle(std::u16string_view rStyleName) const +{ + SwXStyle* pFoundStyle = nullptr; + m_pBasePool->ForAllListeners( + [this, &pFoundStyle, &rStyleName] (SfxListener* pListener) + { + SwXStyle* pTempStyle = dynamic_cast<SwXStyle*>(pListener); + if(pTempStyle && pTempStyle->GetFamily() == m_rEntry.family() && pTempStyle->GetStyleName() == rStyleName) + { + pFoundStyle = pTempStyle; + return true; // break + } + return false; + }); + return pFoundStyle; +} + +static SwGetPoolIdFromName lcl_GetSwEnumFromSfxEnum(SfxStyleFamily eFamily) +{ + auto& entries(lcl_GetStyleFamilyEntries()); + const auto pEntry = std::find_if(entries.begin(), entries.end(), + [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; }); + if(pEntry != entries.end()) + return pEntry->poolId(); + SAL_WARN("sw.uno", "someone asking for all styles in unostyle.cxx!" ); + return SwGetPoolIdFromName::ChrFmt; +} + +const uno::Sequence<sal_Int8>& SwXStyle::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theSwXStyleUnoTunnelId; + return theSwXStyleUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SwXStyle::getSomething(const uno::Sequence<sal_Int8>& rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + + +uno::Sequence< OUString > SwXStyle::getSupportedServiceNames() +{ + tools::Long nCount = 1; + if(SfxStyleFamily::Para == m_rEntry.family()) + { + nCount = 5; + if(m_bIsConditional) + nCount++; + } + else if(SfxStyleFamily::Char == m_rEntry.family()) + nCount = 5; + else if(SfxStyleFamily::Page == m_rEntry.family()) + nCount = 3; + uno::Sequence< OUString > aRet(nCount); + OUString* pArray = aRet.getArray(); + pArray[0] = "com.sun.star.style.Style"; + switch(m_rEntry.family()) + { + case SfxStyleFamily::Char: + pArray[1] = "com.sun.star.style.CharacterStyle"; + pArray[2] = "com.sun.star.style.CharacterProperties"; + pArray[3] = "com.sun.star.style.CharacterPropertiesAsian"; + pArray[4] = "com.sun.star.style.CharacterPropertiesComplex"; + break; + case SfxStyleFamily::Page: + pArray[1] = "com.sun.star.style.PageStyle"; + pArray[2] = "com.sun.star.style.PageProperties"; + break; + case SfxStyleFamily::Para: + pArray[1] = "com.sun.star.style.ParagraphStyle"; + pArray[2] = "com.sun.star.style.ParagraphProperties"; + pArray[3] = "com.sun.star.style.ParagraphPropertiesAsian"; + pArray[4] = "com.sun.star.style.ParagraphPropertiesComplex"; + if(m_bIsConditional) + pArray[5] = "com.sun.star.style.ConditionalParagraphStyle"; + break; + + default: + ; + } + return aRet; +} + +static uno::Reference<beans::XPropertySet> lcl_InitStandardStyle(const SfxStyleFamily eFamily, uno::Reference<container::XNameAccess> const & rxStyleFamily) +{ + using return_t = decltype(lcl_InitStandardStyle(eFamily, rxStyleFamily)); + if(eFamily != SfxStyleFamily::Para && eFamily != SfxStyleFamily::Page) + return {}; + auto aResult(rxStyleFamily->getByName("Standard")); + if(!aResult.has<return_t>()) + return {}; + return aResult.get<return_t>(); +} + +static uno::Reference<container::XNameAccess> lcl_InitStyleFamily(SwDoc* pDoc, const StyleFamilyEntry& rEntry) +{ + using return_t = decltype(lcl_InitStyleFamily(pDoc, rEntry)); + if(rEntry.family() != SfxStyleFamily::Char + && rEntry.family() != SfxStyleFamily::Para + && rEntry.family() != SfxStyleFamily::Page) + return {}; + auto xModel(pDoc->GetDocShell()->GetBaseModel()); + uno::Reference<style::XStyleFamiliesSupplier> xFamilySupplier(xModel, uno::UNO_QUERY); + auto xFamilies = xFamilySupplier->getStyleFamilies(); + auto aResult(xFamilies->getByName(rEntry.name())); + if(!aResult.has<return_t>()) + return {}; + return aResult.get<return_t>(); +} + +static bool lcl_InitConditional(SfxStyleSheetBasePool* pBasePool, const SfxStyleFamily eFamily, const OUString& rStyleName) +{ + if(!pBasePool || eFamily != SfxStyleFamily::Para) + return false; + SfxStyleSheetBase* pBase = pBasePool->Find(rStyleName, eFamily); + SAL_WARN_IF(!pBase, "sw.uno", "where is the style?" ); + if(!pBase) + return false; + const sal_uInt16 nId(SwStyleNameMapper::GetPoolIdFromUIName(rStyleName, SwGetPoolIdFromName::TxtColl)); + if(nId != USHRT_MAX) + return ::IsConditionalByPoolId(nId); + return RES_CONDTXTFMTCOLL == static_cast<SwDocStyleSheet*>(pBase)->GetCollection()->Which(); +} + +static const StyleFamilyEntry& lcl_GetStyleEntry(const SfxStyleFamily eFamily) +{ + auto& entries = lcl_GetStyleFamilyEntries(); + const auto pEntry = std::find_if(entries.begin(), entries.end(), + [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; }); + assert(pEntry != entries.end()); + return *pEntry; +} + +SwXStyle::SwXStyle(SwDoc* pDoc, SfxStyleFamily eFamily, bool bConditional) + : m_pDoc(pDoc) + , m_rEntry(lcl_GetStyleEntry(eFamily)) + , m_bIsDescriptor(true) + , m_bIsConditional(bConditional) + , m_pBasePool(nullptr) + , m_xStyleFamily(lcl_InitStyleFamily(pDoc, m_rEntry)) + , m_xStyleData(lcl_InitStandardStyle(eFamily, m_xStyleFamily)) +{ + assert(!m_bIsConditional || m_rEntry.family() == SfxStyleFamily::Para); // only paragraph styles are conditional + // Register ourselves as a listener to the document (via the page descriptor) + SvtListener::StartListening(pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); + m_pPropertiesImpl = std::make_unique<SwStyleProperties_Impl>( + aSwMapProvider.GetPropertySet(m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType())->getPropertyMap()); +} + +SwXStyle::SwXStyle(SfxStyleSheetBasePool* pPool, SfxStyleFamily eFamily, SwDoc* pDoc, const OUString& rStyleName) + : m_pDoc(pDoc) + , m_sStyleName(rStyleName) + , m_rEntry(lcl_GetStyleEntry(eFamily)) + , m_bIsDescriptor(false) + , m_bIsConditional(lcl_InitConditional(pPool, eFamily, rStyleName)) + , m_pBasePool(pPool) +{ } + +SwXStyle::~SwXStyle() +{ + SolarMutexGuard aGuard; + if(m_pBasePool) + SfxListener::EndListening(*m_pBasePool); + m_pPropertiesImpl.reset(); + SvtListener::EndListeningAll(); +} + +void SwXStyle::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pDoc = nullptr; + m_xStyleData.clear(); + m_xStyleFamily.clear(); + } +} + +OUString SwXStyle::getName() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + return m_sStyleName; + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + SAL_WARN_IF(!pBase, "sw.uno", "where is the style?"); + if(!pBase) + throw uno::RuntimeException(); + OUString aString; + SwStyleNameMapper::FillProgName(pBase->GetName(), aString, lcl_GetSwEnumFromSfxEnum ( m_rEntry.family())); + return aString; +} + +void SwXStyle::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + { + m_sStyleName = rName; + return; + } + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + SAL_WARN_IF(!pBase, "sw.uno", "where is the style?"); + if(!pBase || !pBase->IsUserDefined()) + throw uno::RuntimeException(); + rtl::Reference<SwDocStyleSheet> xTmp(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + if(!xTmp->SetName(rName)) + throw uno::RuntimeException(); + m_sStyleName = rName; +} + +sal_Bool SwXStyle::isUserDefined() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + //if it is not found it must be non user defined + return pBase && pBase->IsUserDefined(); +} + +sal_Bool SwXStyle::isInUse() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + throw uno::RuntimeException(); + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family(), SfxStyleSearchBits::Used); + return pBase && pBase->IsUsed(); +} + +OUString SwXStyle::getParentStyle() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + { + if(!m_bIsDescriptor) + throw uno::RuntimeException(); + return m_sParentStyleName; + } + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + OUString aString; + if(pBase) + aString = pBase->GetParent(); + SwStyleNameMapper::FillProgName(aString, aString, lcl_GetSwEnumFromSfxEnum(m_rEntry.family())); + return aString; +} + +void SwXStyle::setParentStyle(const OUString& rParentStyle) +{ + SolarMutexGuard aGuard; + OUString sParentStyle; + SwStyleNameMapper::FillUIName(rParentStyle, sParentStyle, lcl_GetSwEnumFromSfxEnum ( m_rEntry.family()) ); + if(!m_pBasePool) + { + if(!m_bIsDescriptor) + throw uno::RuntimeException(); + m_sParentStyleName = sParentStyle; + try + { + const auto aAny = m_xStyleFamily->getByName(sParentStyle); + m_xStyleData = aAny.get<decltype(m_xStyleData)>(); + } + catch(...) + { } + return; + } + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + if(!pBase) + throw uno::RuntimeException(); + rtl::Reference<SwDocStyleSheet> xBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + //make it a 'real' style - necessary for pooled styles + xBase->GetItemSet(); + if(xBase->GetParent() != sParentStyle) + { + if(!xBase->SetParent(sParentStyle)) + throw uno::RuntimeException(); + } +} + +uno::Reference<beans::XPropertySetInfo> SwXStyle::getPropertySetInfo() +{ + if(m_bIsConditional) + { + assert(m_rEntry.family() == SfxStyleFamily::Para); + static auto xCondParaRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CONDITIONAL_PARA_STYLE)->getPropertySetInfo(); + return xCondParaRef; + } + return m_rEntry.xPSInfo(); +} + +void SwXStyle::ApplyDescriptorProperties() +{ + m_bIsDescriptor = false; + m_xStyleData.clear(); + m_xStyleFamily.clear(); + m_pPropertiesImpl->Apply(*this); +} + +namespace { + const TranslateId STR_POOLPAGE_ARY[] = + { + // Page styles + STR_POOLPAGE_STANDARD, + STR_POOLPAGE_FIRST, + STR_POOLPAGE_LEFT, + STR_POOLPAGE_RIGHT, + STR_POOLPAGE_ENVELOPE, + STR_POOLPAGE_REGISTER, + STR_POOLPAGE_HTML, + STR_POOLPAGE_FOOTNOTE, + STR_POOLPAGE_ENDNOTE, + STR_POOLPAGE_LANDSCAPE + }; +} + +const SwPageDesc* SwStyleBase_Impl::GetOldPageDesc() +{ + if(!m_pOldPageDesc) + { + SwPageDesc *pd = m_rDoc.FindPageDesc(m_rStyleName); + if(pd) + m_pOldPageDesc = pd; + + if(!m_pOldPageDesc) + { + for (size_t i = 0; i < SAL_N_ELEMENTS(STR_POOLPAGE_ARY); ++i) + { + if (SwResId(STR_POOLPAGE_ARY[i]) == m_rStyleName) + { + m_pOldPageDesc = m_rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_BEGIN + i); + break; + } + } + } + } + return m_pOldPageDesc; +} + + + +static sal_uInt8 lcl_TranslateMetric(const SfxItemPropertyMapEntry& rEntry, SwDoc* pDoc, uno::Any& o_aValue) +{ + // check for needed metric translation + if(!(rEntry.nMoreFlags & PropertyMoreFlags::METRIC_ITEM)) + return rEntry.nMemberId; + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + if((XATTR_FILLBMP_SIZEX == rEntry.nWID || XATTR_FILLBMP_SIZEY == rEntry.nWID) + && o_aValue.has<sal_Int32>() + && o_aValue.get<sal_Int32>() < 0) + return rEntry.nMemberId; + if(!pDoc) + return rEntry.nMemberId; + + const SfxItemPool& rPool = pDoc->GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(rEntry.nWID)); + if(eMapUnit != MapUnit::Map100thMM) + SvxUnoConvertFromMM(eMapUnit, o_aValue); + return rEntry.nMemberId; +} +template<> +void SwXStyle::SetPropertyValue<HINT_BEGIN>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + // default ItemSet handling + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + SfxItemSet aSet(*rStyleSet.GetPool(), rEntry.nWID, rEntry.nWID); + aSet.SetParent(&rStyleSet); + rPropSet.setPropertyValue(rEntry, rValue, aSet); + rStyleSet.Put(aSet); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_HIDDEN>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + bool bHidden = false; + if(rValue >>= bHidden) + { + //make it a 'real' style - necessary for pooled styles + o_rStyleBase.getNewBase()->GetItemSet(); + o_rStyleBase.getNewBase()->SetHidden(bHidden); + } + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_STYLE_INTEROP_GRAB_BAG>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + o_rStyleBase.getNewBase()->GetItemSet(); + o_rStyleBase.getNewBase()->SetGrabBagItem(rValue); + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(XATTR_FILLGRADIENT)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + uno::Any aValue(rValue); + const auto nMemberId(lcl_TranslateMetric(rEntry, m_pDoc, aValue)); + if(MID_NAME == nMemberId) + { + // add set commands for FillName items + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + if(!aValue.has<OUString>()) + throw lang::IllegalArgumentException(); + SvxShape::SetFillAttribute(rEntry.nWID, aValue.get<OUString>(), rStyleSet); + } + else if(MID_BITMAP == nMemberId) + { + if(sal_uInt16(XATTR_FILLBITMAP) == rEntry.nWID) + { + Graphic aNullGraphic; + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + XFillBitmapItem aXFillBitmapItem(std::move(aNullGraphic)); + aXFillBitmapItem.PutValue(aValue, nMemberId); + rStyleSet.Put(aXFillBitmapItem); + } + } + else + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, aValue, o_rStyleBase); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_BACKGROUND)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rStyleSet, RES_BACKGROUND, true, m_pDoc->IsInXMLImport())); + std::unique_ptr<SvxBrushItem> aChangedBrushItem(aOriginalBrushItem->Clone()); + + uno::Any aValue(rValue); + const auto nMemberId(lcl_TranslateMetric(rEntry, m_pDoc, aValue)); + aChangedBrushItem->PutValue(aValue, nMemberId); + + // 0xff is already the default - but if BackTransparent is set + // to true, it must be applied in the item set on ODF import + // to potentially override parent style, which is unknown yet + if(*aChangedBrushItem == *aOriginalBrushItem && (MID_GRAPHIC_TRANSPARENT != nMemberId || !aValue.has<bool>() || !aValue.get<bool>())) + return; + + setSvxBrushItemAsFillAttributesToTargetSet(*aChangedBrushItem, rStyleSet); +} +template<> +void SwXStyle::SetPropertyValue<OWN_ATTR_FILLBMP_MODE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + drawing::BitmapMode eMode; + if(!(rValue >>= eMode)) + { + if(!rValue.has<sal_Int32>()) + throw lang::IllegalArgumentException(); + eMode = static_cast<drawing::BitmapMode>(rValue.get<sal_Int32>()); + } + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + rStyleSet.Put(XFillBmpStretchItem(drawing::BitmapMode_STRETCH == eMode)); + rStyleSet.Put(XFillBmpTileItem(drawing::BitmapMode_REPEAT == eMode)); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_PAPER_BIN)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(!rValue.has<OUString>()) + throw lang::IllegalArgumentException(); + SfxPrinter* pPrinter = m_pDoc->getIDocumentDeviceAccess().getPrinter(true); + OUString sValue(rValue.get<OUString>()); + using printeridx_t = decltype(pPrinter->GetPaperBinCount()); + printeridx_t nBin = std::numeric_limits<printeridx_t>::max(); + if(sValue == "[From printer settings]") + nBin = std::numeric_limits<printeridx_t>::max()-1; + else if(pPrinter) + { + for(sal_uInt16 i=0, nEnd = pPrinter->GetPaperBinCount(); i < nEnd; ++i) + { + if (sValue == pPrinter->GetPaperBinName(i)) + { + nBin = i; + break; + } + } + } + if(nBin == std::numeric_limits<printeridx_t>::max()) + throw lang::IllegalArgumentException(); + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + SfxItemSet aSet(*rStyleSet.GetPool(), rEntry.nWID, rEntry.nWID); + aSet.SetParent(&rStyleSet); + rPropSet.setPropertyValue(rEntry, uno::Any(static_cast<sal_Int8>(nBin == std::numeric_limits<printeridx_t>::max()-1 ? -1 : nBin)), aSet); + rStyleSet.Put(aSet); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_NUM_RULES>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + auto xNumberTunnel(rValue.get<uno::Reference<container::XIndexReplace>>()); + if(!xNumberTunnel) + throw lang::IllegalArgumentException(); + SwXNumberingRules* pSwXRules = dynamic_cast<SwXNumberingRules*>(xNumberTunnel.get()); + if(!pSwXRules) + return; + SwNumRule aSetRule(*pSwXRules->GetNumRule()); + for(sal_uInt16 i = 0; i < MAXLEVEL; ++i) + { + const SwNumFormat* pFormat = aSetRule.GetNumFormat(i); + if(!pFormat) + continue; + SwNumFormat aFormat(*pFormat); + const auto& rCharName(pSwXRules->GetNewCharStyleNames()[i]); + if(!rCharName.isEmpty() + && !SwXNumberingRules::isInvalidStyle(rCharName) + && (!pFormat->GetCharFormat() || pFormat->GetCharFormat()->GetName() != rCharName)) + { + auto pCharFormatIt(std::find_if(m_pDoc->GetCharFormats()->begin(), m_pDoc->GetCharFormats()->end(), + [&rCharName] (SwCharFormat* pF) { return pF->GetName() == rCharName; })); + if(pCharFormatIt != m_pDoc->GetCharFormats()->end()) + aFormat.SetCharFormat(*pCharFormatIt); + else if(m_pBasePool) + { + auto pBase(m_pBasePool->Find(rCharName, SfxStyleFamily::Char)); + if(!pBase) + pBase = &m_pBasePool->Make(rCharName, SfxStyleFamily::Char); + aFormat.SetCharFormat(static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat()); + } + else + aFormat.SetCharFormat(nullptr); + } + // same for fonts: + const auto& rBulletName(pSwXRules->GetBulletFontNames()[i]); + if(!rBulletName.isEmpty() + && !SwXNumberingRules::isInvalidStyle(rBulletName) + && (!pFormat->GetBulletFont() || pFormat->GetBulletFont()->GetFamilyName() != rBulletName)) + { + const auto pFontListItem(static_cast<const SvxFontListItem*>(m_pDoc->GetDocShell()->GetItem(SID_ATTR_CHAR_FONTLIST))); + const auto pList(pFontListItem->GetFontList()); + FontMetric aFontInfo(pList->Get(rBulletName, WEIGHT_NORMAL, ITALIC_NONE)); + vcl::Font aFont(aFontInfo); + aFormat.SetBulletFont(&aFont); + } + aSetRule.Set(i, &aFormat); + } + o_rStyleBase.getNewBase()->SetNumRule(aSetRule); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_OUTLINELEVEL)>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(!rValue.has<sal_Int16>()) + return; + const auto nLevel(rValue.get<sal_Int16>()); + if(0 <= nLevel && nLevel <= MAXLEVEL) + o_rStyleBase.getNewBase()->GetCollection()->SetAttrOutlineLevel(nLevel); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_FOLLOW_STYLE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(!rValue.has<OUString>()) + return; + const auto sValue(rValue.get<OUString>()); + OUString aString; + SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.poolId()); + o_rStyleBase.getNewBase()->SetFollow(aString); +} + +template <> +void SwXStyle::SetPropertyValue<FN_UNO_LINK_STYLE>(const SfxItemPropertyMapEntry&, + const SfxItemPropertySet&, + const uno::Any& rValue, + SwStyleBase_Impl& o_rStyleBase) +{ + if (!rValue.has<OUString>()) + return; + const auto sValue(rValue.get<OUString>()); + OUString aString; + SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.poolId()); + o_rStyleBase.getNewBase()->SetLink(aString); +} + +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_PAGEDESC)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(MID_PAGEDESC_PAGEDESCNAME != rEntry.nMemberId) + { + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); + return; + } + if(!rValue.has<OUString>()) + throw lang::IllegalArgumentException(); + // special handling for RES_PAGEDESC + SfxItemSet& rStyleSet = o_rStyleBase.GetItemSet(); + std::unique_ptr<SwFormatPageDesc> pNewDesc; + if(const SwFormatPageDesc* pItem = rStyleSet.GetItemIfSet(RES_PAGEDESC)) + pNewDesc.reset(new SwFormatPageDesc(*pItem)); + else + pNewDesc.reset(new SwFormatPageDesc); + const auto sValue(rValue.get<OUString>()); + OUString sDescName; + SwStyleNameMapper::FillUIName(sValue, sDescName, SwGetPoolIdFromName::PageDesc); + if(pNewDesc->GetPageDesc() && pNewDesc->GetPageDesc()->GetName() == sDescName) + return; + if(sDescName.isEmpty()) + { + rStyleSet.ClearItem(RES_BREAK); + rStyleSet.Put(SwFormatPageDesc()); + } + else + { + SwPageDesc* pPageDesc(SwPageDesc::GetByName(*m_pDoc, sDescName)); + if(!pPageDesc) + throw lang::IllegalArgumentException(); + pNewDesc->RegisterToPageDesc(*pPageDesc); + rStyleSet.Put(std::move(pNewDesc)); + } +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_TEXT_VERT_ADJUST)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(m_rEntry.family() != SfxStyleFamily::Page) + { + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); + return; + } + if(!m_pDoc || !rValue.has<drawing::TextVerticalAdjust>() || !o_rStyleBase.GetOldPageDesc()) + return; + SwPageDesc* pPageDesc = m_pDoc->FindPageDesc(o_rStyleBase.GetOldPageDesc()->GetName()); + if(pPageDesc) + pPageDesc->SetVerticalAdjustment(rValue.get<drawing::TextVerticalAdjust>()); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_IS_AUTO_UPDATE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(!rValue.has<bool>()) + throw lang::IllegalArgumentException(); + const bool bAuto(rValue.get<bool>()); + if(SfxStyleFamily::Para == m_rEntry.family()) + o_rStyleBase.getNewBase()->GetCollection()->SetAutoUpdateOnDirectFormat(bAuto); + else if(SfxStyleFamily::Frame == m_rEntry.family()) + o_rStyleBase.getNewBase()->GetFrameFormat()->SetAutoUpdateOnDirectFormat(bAuto); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_PARA_STYLE_CONDITIONS>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + static_assert(COND_COMMAND_COUNT == 28, "invalid size of command count?"); + using expectedarg_t = uno::Sequence<beans::NamedValue>; + if(!rValue.has<expectedarg_t>() || !m_pBasePool) + throw lang::IllegalArgumentException(); + SwCondCollItem aCondItem; + const auto aNamedValues = rValue.get<expectedarg_t>(); + for(const auto& rNamedValue : aNamedValues) + { + if(!rNamedValue.Value.has<OUString>()) + throw lang::IllegalArgumentException(); + + const OUString sValue(rNamedValue.Value.get<OUString>()); + // get UI style name from programmatic style name + OUString aStyleName; + SwStyleNameMapper::FillUIName(sValue, aStyleName, lcl_GetSwEnumFromSfxEnum(m_rEntry.family())); + + // check for correct context and style name + const auto nIdx(GetCommandContextIndex(rNamedValue.Name)); + if (nIdx == -1) + throw lang::IllegalArgumentException(); + bool bStyleFound = false; + for(auto pBase = m_pBasePool->First(SfxStyleFamily::Para); pBase; pBase = m_pBasePool->Next()) + { + bStyleFound = pBase->GetName() == aStyleName; + if (bStyleFound) + break; + } + if (!bStyleFound) + throw lang::IllegalArgumentException(); + aCondItem.SetStyle(&aStyleName, nIdx); + } + o_rStyleBase.GetItemSet().Put(aCondItem); +} +template<> +void SwXStyle::SetPropertyValue<FN_UNO_CATEGORY>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(!o_rStyleBase.getNewBase()->IsUserDefined() || !rValue.has<paragraphstyle_t>()) + throw lang::IllegalArgumentException(); + static const std::map<paragraphstyle_t, SfxStyleSearchBits> aUnoToCore = []{ + std::map<paragraphstyle_t, SfxStyleSearchBits> map; + std::transform(std::begin(sParagraphStyleCategoryEntries), std::end(sParagraphStyleCategoryEntries), std::inserter(map, map.end()), + [] (const ParagraphStyleCategoryEntry& rEntry) { return std::make_pair(rEntry.m_eCategory, rEntry.m_nSwStyleBits); }); + return map; + }(); + const auto pUnoToCoreIt(aUnoToCore.find(rValue.get<paragraphstyle_t>())); + if (pUnoToCoreIt == aUnoToCore.end()) + throw lang::IllegalArgumentException(); + o_rStyleBase.getNewBase()->SetMask( pUnoToCoreIt->second|SfxStyleSearchBits::UserDefined ); +} +template<> +void SwXStyle::SetPropertyValue<SID_SWREGISTER_COLLECTION>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + OUString sName; + rValue >>= sName; + SwRegisterItem aReg(!sName.isEmpty()); + aReg.SetWhich(SID_SWREGISTER_MODE); + o_rStyleBase.GetItemSet().Put(aReg); + OUString aString; + SwStyleNameMapper::FillUIName(sName, aString, SwGetPoolIdFromName::TxtColl); + o_rStyleBase.GetItemSet().Put(SfxStringItem(SID_SWREGISTER_COLLECTION, aString ) ); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_TXTATR_CJK_RUBY)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(MID_RUBY_CHARSTYLE != rEntry.nMemberId) + return; + if(!rValue.has<OUString>()) + throw lang::IllegalArgumentException(); + const auto sValue(rValue.get<OUString>()); + SfxItemSet& rStyleSet(o_rStyleBase.GetItemSet()); + std::unique_ptr<SwFormatRuby> pRuby; + if(const SwFormatRuby* pRubyItem = rStyleSet.GetItemIfSet(RES_TXTATR_CJK_RUBY)) + pRuby.reset(new SwFormatRuby(*pRubyItem)); + else + pRuby.reset(new SwFormatRuby(OUString())); + OUString sStyle; + SwStyleNameMapper::FillUIName(sValue, sStyle, SwGetPoolIdFromName::ChrFmt); + pRuby->SetCharFormatName(sValue); + pRuby->SetCharFormatId(0); + if(!sValue.isEmpty()) + { + const sal_uInt16 nId(SwStyleNameMapper::GetPoolIdFromUIName(sValue, SwGetPoolIdFromName::ChrFmt)); + pRuby->SetCharFormatId(nId); + } + rStyleSet.Put(std::move(pRuby)); + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_DROP)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + if(MID_DROPCAP_CHAR_STYLE_NAME != rEntry.nMemberId) + { + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase); + return; + } + if(!rValue.has<OUString>()) + throw lang::IllegalArgumentException(); + SfxItemSet& rStyleSet(o_rStyleBase.GetItemSet()); + std::unique_ptr<SwFormatDrop> pDrop; + if(const SwFormatDrop* pDropItem = rStyleSet.GetItemIfSet(RES_PARATR_DROP)) + pDrop.reset(new SwFormatDrop(*pDropItem)); + else + pDrop.reset(new SwFormatDrop); + const auto sValue(rValue.get<OUString>()); + OUString sStyle; + SwStyleNameMapper::FillUIName(sValue, sStyle, SwGetPoolIdFromName::ChrFmt); + auto pStyle(static_cast<SwDocStyleSheet*>(m_pDoc->GetDocShell()->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char))); + //default character style must not be set as default format + if(!pStyle || pStyle->GetCharFormat() == m_pDoc->GetDfltCharFormat() ) + { + throw lang::IllegalArgumentException(); + } + pDrop->SetCharFormat(pStyle->GetCharFormat()); + rStyleSet.Put(std::move(pDrop)); +} +template<> +void SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_NUMRULE)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase) +{ + uno::Any aValue(rValue); + lcl_TranslateMetric(rEntry, m_pDoc, aValue); + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, aValue, o_rStyleBase); + // --> OD 2006-10-18 #i70223# + if(SfxStyleFamily::Para == m_rEntry.family() && + o_rStyleBase.getNewBase().is() && o_rStyleBase.getNewBase()->GetCollection() && + //rBase.getNewBase()->GetCollection()->GetOutlineLevel() < MAXLEVEL /* assigned to list level of outline style */) //#outline level,removed by zhaojianwei + o_rStyleBase.getNewBase()->GetCollection()->IsAssignedToListLevelOfOutlineStyle()) ////<-end,add by zhaojianwei + { + OUString sNewNumberingRuleName; + aValue >>= sNewNumberingRuleName; + if(sNewNumberingRuleName.isEmpty() || sNewNumberingRuleName != m_pDoc->GetOutlineNumRule()->GetName()) + o_rStyleBase.getNewBase()->GetCollection()->DeleteAssignmentToListLevelOfOutlineStyle(); + } +} + +void SwXStyle::SetStyleProperty(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& rBase) +{ + using propertytype_t = decltype(rEntry.nWID); + using coresetter_t = std::function<void(SwXStyle&, const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any&, SwStyleBase_Impl&)>; + static const std::map<propertytype_t, coresetter_t> aUnoToCore{ + // these explicit std::mem_fn() calls shouldn't be needed, but apparently MSVC is currently too stupid for C++11 again + { FN_UNO_HIDDEN, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_HIDDEN>) }, + { FN_UNO_STYLE_INTEROP_GRAB_BAG, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_STYLE_INTEROP_GRAB_BAG>) }, + { XATTR_FILLGRADIENT, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(XATTR_FILLGRADIENT)>) }, + { XATTR_FILLHATCH, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(XATTR_FILLGRADIENT)>) }, + { XATTR_FILLBITMAP, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(XATTR_FILLGRADIENT)>) }, + { XATTR_FILLFLOATTRANSPARENCE, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(XATTR_FILLGRADIENT)>) }, + { RES_BACKGROUND, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_BACKGROUND)>) }, + { OWN_ATTR_FILLBMP_MODE, std::mem_fn(&SwXStyle::SetPropertyValue<OWN_ATTR_FILLBMP_MODE>) }, + { RES_PAPER_BIN, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PAPER_BIN)>) }, + { FN_UNO_NUM_RULES, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_NUM_RULES>) }, + { RES_PARATR_OUTLINELEVEL, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_OUTLINELEVEL)>) }, + { FN_UNO_FOLLOW_STYLE, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_FOLLOW_STYLE>) }, + { FN_UNO_LINK_STYLE, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_LINK_STYLE>) }, + { RES_PAGEDESC, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PAGEDESC)>) }, + { RES_TEXT_VERT_ADJUST, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_TEXT_VERT_ADJUST)>) }, + { FN_UNO_IS_AUTO_UPDATE, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_IS_AUTO_UPDATE>) }, + { FN_UNO_PARA_STYLE_CONDITIONS, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_PARA_STYLE_CONDITIONS>) }, + { FN_UNO_CATEGORY, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_CATEGORY>) }, + { SID_SWREGISTER_COLLECTION, std::mem_fn(&SwXStyle::SetPropertyValue<SID_SWREGISTER_COLLECTION>) }, + { RES_TXTATR_CJK_RUBY, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_TXTATR_CJK_RUBY)>) }, + { RES_PARATR_DROP, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_DROP)>) }, + { RES_PARATR_NUMRULE, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_NUMRULE)>) } + }; + const auto pUnoToCoreIt(aUnoToCore.find(rEntry.nWID)); + if(pUnoToCoreIt != aUnoToCore.end()) + pUnoToCoreIt->second(*this, rEntry, rPropSet, rValue, rBase); + else + { + // adapted switch logic to a more readable state; removed goto's and made + // execution of standard setting of property in ItemSet dependent of this variable + uno::Any aValue(rValue); + lcl_TranslateMetric(rEntry, m_pDoc, aValue); + SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, aValue, rBase); + } +} + +void SwXStyle::SetPropertyValues_Impl(const uno::Sequence<OUString>& rPropertyNames, const uno::Sequence<uno::Any>& rValues) +{ + if(!m_pDoc) + throw uno::RuntimeException(); + sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap &rMap = pPropSet->getPropertyMap(); + if(rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException(); + + SwStyleBase_Impl aBaseImpl(*m_pDoc, m_sStyleName, &GetDoc()->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent + if(m_pBasePool) + { + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + SAL_WARN_IF(!pBase, "sw.uno", "where is the style?"); + if(!pBase) + throw uno::RuntimeException(); + aBaseImpl.setNewBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + } + if(!aBaseImpl.getNewBase().is() && !m_bIsDescriptor) + throw uno::RuntimeException(); + + const OUString* pNames = rPropertyNames.getConstArray(); + const uno::Any* pValues = rValues.getConstArray(); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); ++nProp) + { + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(pNames[nProp]); + if(!pEntry || (!m_bIsConditional && pNames[nProp] == UNO_NAME_PARA_STYLE_CONDITIONS)) + throw beans::UnknownPropertyException("Unknown property: " + pNames[nProp], getXWeak()); + if(pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException ("Property is read-only: " + pNames[nProp], getXWeak()); + if(aBaseImpl.getNewBase().is()) + SetStyleProperty(*pEntry, *pPropSet, pValues[nProp], aBaseImpl); + else if(!m_pPropertiesImpl->SetProperty(pNames[nProp], pValues[nProp])) + throw lang::IllegalArgumentException(); + } + + if(aBaseImpl.HasItemSet()) + aBaseImpl.getNewBase()->SetItemSet(aBaseImpl.GetItemSet()); +} + +void SwXStyle::setPropertyValues(const uno::Sequence<OUString>& rPropertyNames, const uno::Sequence<uno::Any>& rValues) +{ + SolarMutexGuard aGuard; + // workaround for bad designed API + try + { + SetPropertyValues_Impl( rPropertyNames, rValues ); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a lang::WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +SfxStyleSheetBase* SwXStyle::GetStyleSheetBase() +{ + if(!m_pBasePool) + return nullptr; + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + return pBase; +} +void SwXStyle::PrepareStyleBase(SwStyleBase_Impl& rBase) +{ + SfxStyleSheetBase* pBase(GetStyleSheetBase()); + if(!pBase) + throw uno::RuntimeException(); + if(!rBase.getNewBase().is()) + rBase.setNewBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); +} + +template<> +uno::Any SwXStyle::GetStyleProperty<HINT_BEGIN>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase); +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_IS_PHYSICAL>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl&) +{ + SfxStyleSheetBase* pBase(GetStyleSheetBase()); + if(!pBase) + return uno::Any(false); + bool bPhys = static_cast<SwDocStyleSheet*>(pBase)->IsPhysical(); + // The standard character format is not existing physically + if( bPhys && SfxStyleFamily::Char == GetFamily() && + static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat() && + static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat()->IsDefault() ) + bPhys = false; + return uno::Any(bool(bPhys)); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_HIDDEN>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl&) +{ + SfxStyleSheetBase* pBase(GetStyleSheetBase()); + if(!pBase) + return uno::Any(false); + rtl::Reference<SwDocStyleSheet> xBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + return uno::Any(xBase->IsHidden()); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_STYLE_INTEROP_GRAB_BAG>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl&) +{ + SfxStyleSheetBase* pBase(GetStyleSheetBase()); + if(!pBase) + return uno::Any(); + uno::Any aRet; + rtl::Reference<SwDocStyleSheet> xBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + xBase->GetGrabBagItem(aRet); + return aRet; +} +template<> +uno::Any SwXStyle::GetStyleProperty<sal_uInt16(RES_PAPER_BIN)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + SfxItemSet& rSet = rBase.GetItemSet(); + uno::Any aValue; + rPropSet.getPropertyValue(rEntry, rSet, aValue); + sal_Int8 nBin(aValue.get<sal_Int8>()); + if(nBin == -1) + return uno::Any(OUString("[From printer settings]")); + SfxPrinter* pPrinter = GetDoc()->getIDocumentDeviceAccess().getPrinter(false); + if(!pPrinter) + return uno::Any(); + return uno::Any(pPrinter->GetPaperBinName(nBin)); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_NUM_RULES>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + const SwNumRule* pRule = rBase.getNewBase()->GetNumRule(); + assert(pRule && "Where is the NumRule?"); + uno::Reference<container::XIndexReplace> xRules(new SwXNumberingRules(*pRule, GetDoc())); + return uno::Any(xRules); +} +template<> +uno::Any SwXStyle::GetStyleProperty<sal_uInt16(RES_PARATR_OUTLINELEVEL)>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + SAL_WARN_IF(SfxStyleFamily::Para != GetFamily(), "sw.uno", "only paras"); + return uno::Any(sal_Int16(rBase.getNewBase()->GetCollection()->GetAttrOutlineLevel())); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_FOLLOW_STYLE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + OUString aString; + SwStyleNameMapper::FillProgName(rBase.getNewBase()->GetFollow(), aString, lcl_GetSwEnumFromSfxEnum(GetFamily())); + return uno::Any(aString); +} + +template <> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_LINK_STYLE>(const SfxItemPropertyMapEntry&, + const SfxItemPropertySet&, + SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + OUString aString; + SwStyleNameMapper::FillProgName(rBase.getNewBase()->GetLink(), aString, + lcl_GetSwEnumFromSfxEnum(GetFamily())); + return uno::Any(aString); +} + +template<> +uno::Any SwXStyle::GetStyleProperty<sal_uInt16(RES_PAGEDESC)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + if(MID_PAGEDESC_PAGEDESCNAME != rEntry.nMemberId) + return GetStyleProperty<HINT_BEGIN>(rEntry, rPropSet, rBase); + // special handling for RES_PAGEDESC + const SwFormatPageDesc* pItem = + rBase.GetItemSet().GetItemIfSet(RES_PAGEDESC); + if(!pItem) + return uno::Any(); + const SwPageDesc* pDesc = pItem->GetPageDesc(); + if(!pDesc) + return uno::Any(); + OUString aString; + SwStyleNameMapper::FillProgName(pDesc->GetName(), aString, SwGetPoolIdFromName::PageDesc); + return uno::Any(aString); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_IS_AUTO_UPDATE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + switch(GetFamily()) + { + case SfxStyleFamily::Para : return uno::Any(rBase.getNewBase()->GetCollection()->IsAutoUpdateOnDirectFormat()); + case SfxStyleFamily::Frame: return uno::Any(rBase.getNewBase()->GetFrameFormat()->IsAutoUpdateOnDirectFormat()); + default: return uno::Any(); + } +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_DISPLAY_NAME>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + return uno::Any(rBase.getNewBase()->GetName()); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_PARA_STYLE_CONDITIONS>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + static_assert(COND_COMMAND_COUNT == 28, "invalid size of command count?"); + uno::Sequence<beans::NamedValue> aSeq(COND_COMMAND_COUNT); + sal_uInt16 nIndex = 0; + for(auto& rNV : asNonConstRange(aSeq)) + { + rNV.Name = GetCommandContextByIndex(nIndex++); + rNV.Value <<= OUString(); + } + SwFormat* pFormat = static_cast<SwDocStyleSheet*>(GetStyleSheetBase())->GetCollection(); + if(pFormat && RES_CONDTXTFMTCOLL == pFormat->Which()) + { + const CommandStruct* pCmds = SwCondCollItem::GetCmds(); + beans::NamedValue* pSeq = aSeq.getArray(); + for(sal_uInt16 n = 0; n < COND_COMMAND_COUNT; ++n) + { + const SwCollCondition* pCond = static_cast<SwConditionTextFormatColl*>(pFormat)->HasCondition(SwCollCondition(nullptr, pCmds[n].nCnd, pCmds[n].nSubCond)); + if(!pCond || !pCond->GetTextFormatColl()) + continue; + // get programmatic style name from UI style name + OUString aStyleName = pCond->GetTextFormatColl()->GetName(); + SwStyleNameMapper::FillProgName(aStyleName, aStyleName, lcl_GetSwEnumFromSfxEnum(GetFamily())); + pSeq[n].Value <<= aStyleName; + } + } + return uno::Any(aSeq); +} +template<> +uno::Any SwXStyle::GetStyleProperty<FN_UNO_CATEGORY>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + static const std::map<collectionbits_t, paragraphstyle_t> aUnoToCore = []{ + std::map<collectionbits_t, paragraphstyle_t> map; + std::transform(std::begin(sParagraphStyleCategoryEntries), std::end(sParagraphStyleCategoryEntries), std::inserter(map, map.end()), + [] (const ParagraphStyleCategoryEntry& rEntry) { return std::make_pair(rEntry.m_nCollectionBits, rEntry.m_eCategory); }); + return map; + }(); + const sal_uInt16 nPoolId = rBase.getNewBase()->GetCollection()->GetPoolFormatId(); + const auto pUnoToCoreIt(aUnoToCore.find(COLL_GET_RANGE_BITS & nPoolId)); + if(pUnoToCoreIt == aUnoToCore.end()) + return uno::Any(sal_Int16(-1)); + return uno::Any(pUnoToCoreIt->second); +} +template<> +uno::Any SwXStyle::GetStyleProperty<SID_SWREGISTER_COLLECTION>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + const SwPageDesc *pPageDesc = rBase.getNewBase()->GetPageDesc(); + if(!pPageDesc) + return uno::Any(OUString()); + const SwTextFormatColl* pCol = pPageDesc->GetRegisterFormatColl(); + if(!pCol) + return uno::Any(OUString()); + OUString aName; + SwStyleNameMapper::FillProgName(pCol->GetName(), aName, SwGetPoolIdFromName::TxtColl); + return uno::Any(aName); +} +template<> +uno::Any SwXStyle::GetStyleProperty<sal_uInt16(RES_BACKGROUND)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + const SfxItemSet& rSet = rBase.GetItemSet(); + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND)); + uno::Any aResult; + if(!aOriginalBrushItem->QueryValue(aResult, rEntry.nMemberId)) + SAL_WARN("sw.uno", "error getting attribute from RES_BACKGROUND."); + return aResult; +} +template<> +uno::Any SwXStyle::GetStyleProperty<OWN_ATTR_FILLBMP_MODE>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + const SfxItemSet& rSet = rBase.GetItemSet(); + if (rSet.Get(XATTR_FILLBMP_TILE).GetValue()) + return uno::Any(drawing::BitmapMode_REPEAT); + if (rSet.Get(XATTR_FILLBMP_STRETCH).GetValue()) + return uno::Any(drawing::BitmapMode_STRETCH); + return uno::Any(drawing::BitmapMode_NO_REPEAT); +} +template<> +uno::Any SwXStyle::GetStyleProperty<HINT_BEGIN>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase) +{ + PrepareStyleBase(rBase); + SfxItemSet& rSet = rBase.GetItemSet(); + uno::Any aResult; + rPropSet.getPropertyValue(rEntry, rSet, aResult); + // + // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here + if(rEntry.aType == cppu::UnoType<sal_Int16>::get() && aResult.getValueType() == cppu::UnoType<sal_Int32>::get()) + aResult <<= static_cast<sal_Int16>(aResult.get<sal_Int32>()); + // check for needed metric translation + if(rEntry.nMoreFlags & PropertyMoreFlags::METRIC_ITEM && GetDoc()) + { + const SfxItemPool& rPool = GetDoc()->GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(rEntry.nWID)); + bool bAllowedConvert(true); + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + if(XATTR_FILLBMP_SIZEX == rEntry.nWID || XATTR_FILLBMP_SIZEY == rEntry.nWID) + bAllowedConvert = !aResult.has<sal_Int32>() || aResult.get<sal_Int32>() > 0; + if(eMapUnit != MapUnit::Map100thMM && bAllowedConvert) + SvxUnoConvertToMM(eMapUnit, aResult); + } + return aResult; +} + +uno::Any SwXStyle::GetStyleProperty_Impl(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, SwStyleBase_Impl& rBase) +{ + using propertytype_t = decltype(rEntry.nWID); + using coresetter_t = std::function<uno::Any(SwXStyle&, const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl&)>; + static const std::map<propertytype_t, coresetter_t> aUnoToCore{ + // these explicit std::mem_fn() calls shouldn't be needed, but apparently MSVC is currently too stupid for C++11 again + { FN_UNO_IS_PHYSICAL, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_IS_PHYSICAL>) }, + { FN_UNO_HIDDEN, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_HIDDEN>) }, + { FN_UNO_STYLE_INTEROP_GRAB_BAG, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_STYLE_INTEROP_GRAB_BAG>) }, + { RES_PAPER_BIN, std::mem_fn(&SwXStyle::GetStyleProperty<sal_uInt16(RES_PAPER_BIN)>) }, + { FN_UNO_NUM_RULES, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_NUM_RULES>) }, + { RES_PARATR_OUTLINELEVEL, std::mem_fn(&SwXStyle::GetStyleProperty<sal_uInt16(RES_PARATR_OUTLINELEVEL)>) }, + { FN_UNO_FOLLOW_STYLE, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_FOLLOW_STYLE>) }, + { FN_UNO_LINK_STYLE, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_LINK_STYLE>) }, + { RES_PAGEDESC, std::mem_fn(&SwXStyle::GetStyleProperty<sal_uInt16(RES_PAGEDESC)>) }, + { FN_UNO_IS_AUTO_UPDATE, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_IS_AUTO_UPDATE>) }, + { FN_UNO_DISPLAY_NAME, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_DISPLAY_NAME>) }, + { FN_UNO_PARA_STYLE_CONDITIONS, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_PARA_STYLE_CONDITIONS>) }, + { FN_UNO_CATEGORY, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_CATEGORY>) }, + { SID_SWREGISTER_COLLECTION, std::mem_fn(&SwXStyle::GetStyleProperty<SID_SWREGISTER_COLLECTION>) }, + { RES_BACKGROUND, std::mem_fn(&SwXStyle::GetStyleProperty<sal_uInt16(RES_BACKGROUND)>) }, + { OWN_ATTR_FILLBMP_MODE, std::mem_fn(&SwXStyle::GetStyleProperty<OWN_ATTR_FILLBMP_MODE>) } + }; + const auto pUnoToCoreIt(aUnoToCore.find(rEntry.nWID)); + if(pUnoToCoreIt != aUnoToCore.end()) + return pUnoToCoreIt->second(*this, rEntry, rPropSet, rBase); + return GetStyleProperty<HINT_BEGIN>(rEntry, rPropSet, rBase); +} + +uno::Any SwXStyle::GetPropertyValue_Impl(const SfxItemPropertySet* pPropSet, SwStyleBase_Impl& rBase, const OUString& rPropertyName) +{ + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rPropertyName); + if(!pEntry || (!m_bIsConditional && rPropertyName == UNO_NAME_PARA_STYLE_CONDITIONS)) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak()); + if(m_pBasePool) + return GetStyleProperty_Impl(*pEntry, *pPropSet, rBase); + const uno::Any* pAny = nullptr; + m_pPropertiesImpl->GetProperty(rPropertyName, pAny); + if(pAny->hasValue()) + return *pAny; + uno::Any aValue; + switch(m_rEntry.family()) + { + case SfxStyleFamily::Pseudo: + throw uno::RuntimeException("No default value for: " + rPropertyName); + break; + case SfxStyleFamily::Para: + case SfxStyleFamily::Page: + aValue = m_xStyleData->getPropertyValue(rPropertyName); + break; + case SfxStyleFamily::Char: + case SfxStyleFamily::Frame: + { + if(pEntry->nWID < POOLATTR_BEGIN || pEntry->nWID >= RES_UNKNOWNATR_END) + throw uno::RuntimeException("No default value for: " + rPropertyName); + SwFormat* pFormat; + if(m_rEntry.family() == SfxStyleFamily::Char) + pFormat = m_pDoc->GetDfltCharFormat(); + else + pFormat = m_pDoc->GetDfltFrameFormat(); + const SwAttrPool* pPool = pFormat->GetAttrSet().GetPool(); + const SfxPoolItem& rItem = pPool->GetDefaultItem(pEntry->nWID); + rItem.QueryValue(aValue, pEntry->nMemberId); + } + break; + default: + ; + } + return aValue; +} + +uno::Any SwXStyle::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pBasePool && !m_bIsDescriptor) + throw uno::RuntimeException(); + sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + SwStyleBase_Impl aBase(*m_pDoc, m_sStyleName, &m_pDoc->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent + return GetPropertyValue_Impl(pPropSet, aBase, rPropertyName); +} + +uno::Sequence<uno::Any> SwXStyle::getPropertyValues(const uno::Sequence<OUString>& rPropertyNames) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pBasePool && !m_bIsDescriptor) + throw uno::RuntimeException(); + sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + SwStyleBase_Impl aBase(*m_pDoc, m_sStyleName, &m_pDoc->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent + uno::Sequence<uno::Any> aValues(rPropertyNames.getLength()); + auto aValuesRange = asNonConstRange(aValues); + // workaround for bad designed API + try + { + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); ++nProp) + aValuesRange[nProp] = GetPropertyValue_Impl(pPropSet, aBase, rPropertyNames[nProp]); + } + catch(beans::UnknownPropertyException&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch(lang::WrappedTargetException&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + return aValues; +} + +void SwXStyle::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + const uno::Sequence<OUString> aProperties(&rPropertyName, 1); + const uno::Sequence<uno::Any> aValues(&rValue, 1); + SetPropertyValues_Impl(aProperties, aValues); +} + +beans::PropertyState SwXStyle::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Sequence<OUString> aNames{rPropertyName}; + uno::Sequence<beans::PropertyState> aStates = getPropertyStates(aNames); + return aStates.getConstArray()[0]; +} + +// allow to retarget the SfxItemSet working on, default correctly. Only +// use pSourceSet below this point (except in header/footer processing) +static const SfxItemSet* lcl_GetItemsetForProperty(const SfxItemSet& rSet, SfxStyleFamily eFamily, std::u16string_view rPropertyName) +{ + if(eFamily != SfxStyleFamily::Page) + return &rSet; + const bool isFooter = o3tl::starts_with(rPropertyName, u"Footer"); + if(!isFooter && !o3tl::starts_with(rPropertyName, u"Header") && rPropertyName != UNO_NAME_FIRST_IS_SHARED) + return &rSet; + const SvxSetItem* pSetItem; + if(!lcl_GetHeaderFooterItem(rSet, rPropertyName, isFooter, pSetItem)) + return nullptr; + return &pSetItem->GetItemSet(); +} +uno::Sequence<beans::PropertyState> SwXStyle::getPropertyStates(const uno::Sequence<OUString>& rPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence<beans::PropertyState> aRet(rPropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + + if(!m_pBasePool) + throw uno::RuntimeException(); + SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family()); + + SAL_WARN_IF(!pBase, "sw.uno", "where is the style?"); + if(!pBase) + throw uno::RuntimeException(); + + const OUString* pNames = rPropertyNames.getConstArray(); + rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + const SfxItemSet& rSet = xStyle->GetItemSet(); + + for(sal_Int32 i = 0; i < rPropertyNames.getLength(); ++i) + { + const OUString sPropName = pNames[i]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(sPropName); + + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + sPropName, getXWeak()); + + if (FN_UNO_NUM_RULES == pEntry->nWID || FN_UNO_FOLLOW_STYLE == pEntry->nWID + || pEntry->nWID == FN_UNO_LINK_STYLE) + { + // handle NumRules first, done + pStates[i] = beans::PropertyState_DIRECT_VALUE; + continue; + } + const SfxItemSet* pSourceSet = lcl_GetItemsetForProperty(rSet, m_rEntry.family(), sPropName); + if(!pSourceSet) + { + // if no SetItem, value is ambiguous and we are done + pStates[i] = beans::PropertyState_AMBIGUOUS_VALUE; + continue; + } + switch(pEntry->nWID) + { + case OWN_ATTR_FILLBMP_MODE: + { + if(SfxItemState::SET == pSourceSet->GetItemState(XATTR_FILLBMP_STRETCH, false) + || SfxItemState::SET == pSourceSet->GetItemState(XATTR_FILLBMP_TILE, false)) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_AMBIGUOUS_VALUE; + } + } + break; + case XATTR_FILLSTYLE: + { + if (m_rEntry.family() == SfxStyleFamily::Frame + && xStyle->GetFrameFormat()->DerivedFrom() == GetDoc()->GetDfltFrameFormat()) + { // tdf#156155 mpDfltFrameFormat is the parent, but because + // it IsDefault() it is not enumerated/exported as a style + // to ODF, so export its one important value here. + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = pPropSet->getPropertyState(*pEntry, *pSourceSet); + } + } + break; + case RES_BACKGROUND: + { + // for FlyFrames we need to mark the used properties from type RES_BACKGROUND + // as beans::PropertyState_DIRECT_VALUE to let users of this property call + // getPropertyValue where the member properties will be mapped from the + // fill attributes to the according SvxBrushItem entries + if (SWUnoHelper::needToMapFillItemsToSvxBrushItemTypes(*pSourceSet, pEntry->nMemberId)) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + } + break; + default: + { + pStates[i] = pPropSet->getPropertyState(*pEntry, *pSourceSet); + + if(SfxStyleFamily::Page == m_rEntry.family() && SID_ATTR_PAGE_SIZE == pEntry->nWID && beans::PropertyState_DIRECT_VALUE == pStates[i]) + { + const SvxSizeItem& rSize = rSet.Get(SID_ATTR_PAGE_SIZE); + sal_uInt8 nMemberId = pEntry->nMemberId & 0x7f; + + if((LONG_MAX == rSize.GetSize().Width() && (MID_SIZE_WIDTH == nMemberId || MID_SIZE_SIZE == nMemberId)) || + (LONG_MAX == rSize.GetSize().Height() && MID_SIZE_HEIGHT == nMemberId)) + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + } + } + } + } + return aRet; +} + +void SwXStyle::setPropertyToDefault(const OUString& rPropertyName) +{ + const uno::Sequence<OUString> aSequence(&rPropertyName, 1); + setPropertiesToDefault(aSequence); +} + +static SwFormat* lcl_GetFormatForStyle(SwDoc const * pDoc, const rtl::Reference<SwDocStyleSheet>& xStyle, const SfxStyleFamily eFamily) +{ + if(!xStyle.is()) + return nullptr; + switch(eFamily) + { + case SfxStyleFamily::Char: return xStyle->GetCharFormat(); + case SfxStyleFamily::Para: return xStyle->GetCollection(); + case SfxStyleFamily::Frame: return xStyle->GetFrameFormat(); + case SfxStyleFamily::Page: + { + SwPageDesc* pDesc(pDoc->FindPageDesc(xStyle->GetPageDesc()->GetName())); + if(pDesc) + return &pDesc->GetMaster(); + } + break; + default: ; + } + return nullptr; +} + +void SAL_CALL SwXStyle::setPropertiesToDefault(const uno::Sequence<OUString>& aPropertyNames) +{ + SolarMutexGuard aGuard; + const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(GetStyleSheetBase()))); + SwFormat* pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family()); + if(!pTargetFormat) + { + if(!m_bIsDescriptor) + return; + for(const auto& rName : aPropertyNames) + m_pPropertiesImpl->ClearProperty(rName); + return; + } + const sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap &rMap = pPropSet->getPropertyMap(); + for(const auto& rName : aPropertyNames) + { + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rName); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rName, getXWeak()); + if (pEntry->nWID == FN_UNO_FOLLOW_STYLE || pEntry->nWID == FN_UNO_LINK_STYLE + || pEntry->nWID == FN_UNO_NUM_RULES) + throw uno::RuntimeException("Cannot reset: " + rName, getXWeak()); + if(pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw uno::RuntimeException("setPropertiesToDefault: property is read-only: " + rName, getXWeak()); + if(pEntry->nWID == RES_PARATR_OUTLINELEVEL) + { + static_cast<SwTextFormatColl*>(pTargetFormat)->DeleteAssignmentToListLevelOfOutlineStyle(); + continue; + } + pTargetFormat->ResetFormatAttr(pEntry->nWID); + if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + // + SwDoc* pDoc = pTargetFormat->GetDoc(); + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet(pDoc->GetAttrPool()); + aSet.SetParent(&pTargetFormat->GetAttrSet()); + + aSet.ClearItem(XATTR_FILLBMP_STRETCH); + aSet.ClearItem(XATTR_FILLBMP_TILE); + + pTargetFormat->SetFormatAttr(aSet); + } + } +} + +void SAL_CALL SwXStyle::setAllPropertiesToDefault() +{ + SolarMutexGuard aGuard; + if(!m_pBasePool) + { + if(!m_bIsDescriptor) + throw uno::RuntimeException(); + m_pPropertiesImpl->ClearAllProperties(); + return; + } + const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(GetStyleSheetBase()))); + if(!xStyle.is()) + throw uno::RuntimeException(); + if(SfxStyleFamily::Page == m_rEntry.family()) + { + size_t nPgDscPos(0); + SwPageDesc* pDesc = m_pDoc->FindPageDesc(xStyle->GetPageDesc()->GetName(), &nPgDscPos); + SwFormat* pPageFormat(nullptr); + if(pDesc) + { + pPageFormat = &pDesc->GetMaster(); + pDesc->SetUseOn(UseOnPage::All); + } + else + pPageFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family()); + SwPageDesc& rPageDesc = m_pDoc->GetPageDesc(nPgDscPos); + rPageDesc.ResetAllMasterAttr(); + + pPageFormat->SetPageFormatToDefault(); + SwPageDesc* pStdPgDsc = m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD); + std::shared_ptr<SwFormatFrameSize> aFrameSz(std::make_shared<SwFormatFrameSize>(SwFrameSize::Fixed)); + + if(RES_POOLPAGE_STANDARD == rPageDesc.GetPoolFormatId()) + { + if(m_pDoc->getIDocumentDeviceAccess().getPrinter(false)) + { + const Size aPhysSize( SvxPaperInfo::GetPaperSize( + static_cast<Printer*>(m_pDoc->getIDocumentDeviceAccess().getPrinter(false)))); + aFrameSz->SetSize(aPhysSize); + } + else + { + aFrameSz->SetSize(SvxPaperInfo::GetDefaultPaperSize()); + } + + } + else + { + aFrameSz.reset(pStdPgDsc->GetMaster().GetFrameSize().Clone()); + } + + if(pStdPgDsc->GetLandscape()) + { + SwTwips nTmp = aFrameSz->GetHeight(); + aFrameSz->SetHeight(aFrameSz->GetWidth()); + aFrameSz->SetWidth(nTmp); + } + + pPageFormat->SetFormatAttr(*aFrameSz); + m_pDoc->ChgPageDesc(nPgDscPos, m_pDoc->GetPageDesc(nPgDscPos)); + return; + } + if(SfxStyleFamily::Para == m_rEntry.family()) + { + if(xStyle->GetCollection()) + xStyle->GetCollection()->DeleteAssignmentToListLevelOfOutlineStyle(); + } + SwFormat* const pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family()); + if(!pTargetFormat) + return; + pTargetFormat->ResetAllFormatAttr(); +} + +uno::Sequence<uno::Any> SAL_CALL SwXStyle::getPropertyDefaults(const uno::Sequence<OUString>& aPropertyNames) +{ + SolarMutexGuard aGuard; + sal_Int32 nCount = aPropertyNames.getLength(); + uno::Sequence<uno::Any> aRet(nCount); + if(!nCount) + return aRet; + auto pRet = aRet.getArray(); + SfxStyleSheetBase* pBase = GetStyleSheetBase(); + if(!pBase) + throw uno::RuntimeException(); + rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + const sal_uInt16 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType(); + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + + const SfxItemSet &rSet = xStyle->GetItemSet(), *pParentSet = rSet.GetParent(); + for(sal_Int32 i = 0; i < nCount; ++i) + { + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(aPropertyNames[i]); + + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + aPropertyNames[i], getXWeak()); + // these cannot be in an item set, especially not the + // parent set, so the default value is void + if (pEntry->nWID >= RES_UNKNOWNATR_END) + continue; + + if(pParentSet) + { + aSwMapProvider.GetPropertySet(nPropSetId)->getPropertyValue(aPropertyNames[i], *pParentSet, pRet[i]); + } + else if(pEntry->nWID != rSet.GetPool()->GetSlotId(pEntry->nWID)) + { + const SfxPoolItem& rItem = rSet.GetPool()->GetDefaultItem(pEntry->nWID); + rItem.QueryValue(pRet[i], pEntry->nMemberId); + } + } + return aRet; +} + +uno::Any SwXStyle::getPropertyDefault(const OUString& rPropertyName) +{ + const uno::Sequence<OUString> aSequence(&rPropertyName, 1); + return getPropertyDefaults(aSequence)[0]; +} + +void SwXStyle::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + if((rHint.GetId() == SfxHintId::Dying) || (rHint.GetId() == SfxHintId::StyleSheetErased)) + { + m_pBasePool = nullptr; + SfxListener::EndListening(rBC); + } + else if(rHint.GetId() == SfxHintId::StyleSheetChanged) + { + SfxStyleSheetBasePool& rBP = static_cast<SfxStyleSheetBasePool&>(rBC); + SfxStyleSheetBase* pOwnBase = rBP.Find(m_sStyleName, m_rEntry.family()); + if(!pOwnBase) + { + SfxListener::EndListening(rBC); + Invalidate(); + } + } +} + +void SwXStyle::Invalidate() +{ + m_sStyleName.clear(); + m_pBasePool = nullptr; + m_pDoc = nullptr; + m_xStyleData.clear(); + m_xStyleFamily.clear(); +} + +SwXPageStyle::SwXPageStyle(SfxStyleSheetBasePool& rPool, SwDocShell* pDocSh, const OUString& rStyleName) + : SwXStyle(&rPool, SfxStyleFamily::Page, pDocSh->GetDoc(), rStyleName) +{ } + +SwXPageStyle::SwXPageStyle(SwDocShell* pDocSh) + : SwXStyle(pDocSh->GetDoc(), SfxStyleFamily::Page) +{ } + +void SwXStyle::PutItemToSet(const SvxSetItem* pSetItem, const SfxItemPropertySet& rPropSet, const SfxItemPropertyMapEntry& rEntry, const uno::Any& rVal, SwStyleBase_Impl& rBaseImpl) +{ + // create a new SvxSetItem and get it's ItemSet as new target + std::unique_ptr<SvxSetItem> pNewSetItem(pSetItem->Clone()); + SfxItemSet& rSetSet = pNewSetItem->GetItemSet(); + + // set parent to ItemSet to ensure XFILL_NONE as XFillStyleItem + rSetSet.SetParent(&m_pDoc->GetDfltFrameFormat()->GetAttrSet()); + + // replace the used SfxItemSet at the SwStyleBase_Impl temporarily and use the + // default method to set the property + { + SwStyleBase_Impl::ItemSetOverrider o(rBaseImpl, &rSetSet); + SetStyleProperty(rEntry, rPropSet, rVal, rBaseImpl); + } + + // reset parent at ItemSet from SetItem + rSetSet.SetParent(nullptr); + + // set the new SvxSetItem at the real target and delete it + rBaseImpl.GetItemSet().Put(std::move(pNewSetItem)); +} + +void SwXPageStyle::SetPropertyValues_Impl(const uno::Sequence<OUString>& rPropertyNames, const uno::Sequence<uno::Any>& rValues) +{ + if(!GetDoc()) + throw uno::RuntimeException(); + + if(rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException(); + + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PAGE_STYLE); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + SwStyleBase_Impl aBaseImpl(*GetDoc(), GetStyleName(), &GetDoc()->GetDfltFrameFormat()->GetAttrSet()); // add pDfltFrameFormat as parent + if(!m_pBasePool) + { + if(!IsDescriptor()) + throw uno::RuntimeException(); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); ++nProp) + if(!m_pPropertiesImpl->SetProperty(rPropertyNames[nProp], rValues[nProp])) + throw lang::IllegalArgumentException(); + return; + } + SfxStyleSheetBase* pBase = GetStyleSheetBase(); + if(!pBase) + throw uno::RuntimeException(); + aBaseImpl.setNewBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); ++nProp) + { + const OUString& rPropName = rPropertyNames[nProp]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rPropName); + + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropName, getXWeak()); + if(pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropName, getXWeak()); + + const bool bHeader(rPropName.startsWith("Header")); + const bool bFooter(rPropName.startsWith("Footer")); + const bool bFirstIsShared(rPropName == UNO_NAME_FIRST_IS_SHARED); + if(bHeader || bFooter || bFirstIsShared) + { + switch(pEntry->nWID) + { + case SID_ATTR_PAGE_ON: + case RES_BACKGROUND: + case RES_BOX: + case RES_LR_SPACE: + case RES_SHADOW: + case RES_UL_SPACE: + case SID_ATTR_PAGE_DYNAMIC: + case SID_ATTR_PAGE_SHARED: + case SID_ATTR_PAGE_SHARED_FIRST: + case SID_ATTR_PAGE_SIZE: + case RES_HEADER_FOOTER_EAT_SPACING: + { + // it is a Header/Footer entry, access the SvxSetItem containing it's information + const SvxSetItem* pSetItem = nullptr; + if (lcl_GetHeaderFooterItem(aBaseImpl.GetItemSet(), rPropName, bFooter, pSetItem)) + { + PutItemToSet(pSetItem, *pPropSet, *pEntry, rValues[nProp], aBaseImpl); + + if (pEntry->nWID == SID_ATTR_PAGE_SHARED_FIRST) + { + // Need to add this to the other as well + pSetItem = aBaseImpl.GetItemSet().GetItemIfSet( + bFooter ? SID_ATTR_PAGE_HEADERSET : SID_ATTR_PAGE_FOOTERSET, + false); + if (pSetItem) + { + PutItemToSet(pSetItem, *pPropSet, *pEntry, rValues[nProp], aBaseImpl); + } + } + } + else if(pEntry->nWID == SID_ATTR_PAGE_ON && rValues[nProp].get<bool>()) + { + // Header/footer gets switched on, create defaults and the needed SfxSetItem + SfxItemSetFixed + <RES_FRMATR_BEGIN,RES_FRMATR_END - 1, // [82 + + // FillAttribute support + XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014 + + SID_ATTR_BORDER_INNER,SID_ATTR_BORDER_INNER, // [10023 + SID_ATTR_PAGE_SIZE,SID_ATTR_PAGE_SIZE, // [10051 + SID_ATTR_PAGE_ON,SID_ATTR_PAGE_SHARED, // [10060 + SID_ATTR_PAGE_SHARED_FIRST,SID_ATTR_PAGE_SHARED_FIRST> + aTempSet(*aBaseImpl.GetItemSet().GetPool()); + + // set correct parent to get the XFILL_NONE FillStyle as needed + aTempSet.SetParent(&GetDoc()->GetDfltFrameFormat()->GetAttrSet()); + + aTempSet.Put(SfxBoolItem(SID_ATTR_PAGE_ON, true)); + constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm); + aTempSet.Put(SvxSizeItem(SID_ATTR_PAGE_SIZE, Size(constTwips_5mm, constTwips_5mm))); + aTempSet.Put(SvxLRSpaceItem(RES_LR_SPACE)); + aTempSet.Put(SvxULSpaceItem(RES_UL_SPACE)); + aTempSet.Put(SfxBoolItem(SID_ATTR_PAGE_SHARED, true)); + aTempSet.Put(SfxBoolItem(SID_ATTR_PAGE_SHARED_FIRST, true)); + aTempSet.Put(SfxBoolItem(SID_ATTR_PAGE_DYNAMIC, true)); + + SvxSetItem aNewSetItem(bFooter ? SID_ATTR_PAGE_FOOTERSET : SID_ATTR_PAGE_HEADERSET, aTempSet); + aBaseImpl.GetItemSet().Put(aNewSetItem); + } + } + continue; + case XATTR_FILLBMP_SIZELOG: + case XATTR_FILLBMP_TILEOFFSETX: + case XATTR_FILLBMP_TILEOFFSETY: + case XATTR_FILLBMP_POSOFFSETX: + case XATTR_FILLBMP_POSOFFSETY: + case XATTR_FILLBMP_POS: + case XATTR_FILLBMP_SIZEX: + case XATTR_FILLBMP_SIZEY: + case XATTR_FILLBMP_STRETCH: + case XATTR_FILLBMP_TILE: + case OWN_ATTR_FILLBMP_MODE: + case XATTR_FILLCOLOR: + case XATTR_FILLBACKGROUND: + case XATTR_FILLBITMAP: + case XATTR_GRADIENTSTEPCOUNT: + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_FILLSTYLE: + case XATTR_FILLTRANSPARENCE: + case XATTR_FILLFLOATTRANSPARENCE: + case XATTR_SECONDARYFILLCOLOR: + if(bFirstIsShared) // only special handling for headers/footers here + break; + { + const SvxSetItem* pSetItem = + aBaseImpl.GetItemSet().GetItemIfSet(bFooter ? SID_ATTR_PAGE_FOOTERSET : SID_ATTR_PAGE_HEADERSET, false); + + if(pSetItem) + { + // create a new SvxSetItem and get it's ItemSet as new target + std::unique_ptr<SvxSetItem> pNewSetItem(pSetItem->Clone()); + SfxItemSet& rSetSet = pNewSetItem->GetItemSet(); + + // set parent to ItemSet to ensure XFILL_NONE as XFillStyleItem + rSetSet.SetParent(&GetDoc()->GetDfltFrameFormat()->GetAttrSet()); + + // replace the used SfxItemSet at the SwStyleBase_Impl temporarily and use the + // default method to set the property + { + SwStyleBase_Impl::ItemSetOverrider o(aBaseImpl, &rSetSet); + SetStyleProperty(*pEntry, *pPropSet, rValues[nProp], aBaseImpl); + } + + // reset parent at ItemSet from SetItem + rSetSet.SetParent(nullptr); + + // set the new SvxSetItem at the real target and delete it + aBaseImpl.GetItemSet().Put(std::move(pNewSetItem)); + } + } + continue; + default: ; + } + } + switch(pEntry->nWID) + { + case SID_ATTR_PAGE_DYNAMIC: + case SID_ATTR_PAGE_SHARED: + case SID_ATTR_PAGE_SHARED_FIRST: + case SID_ATTR_PAGE_ON: + case RES_HEADER_FOOTER_EAT_SPACING: + // these slots are exclusive to Header/Footer, thus this is an error + throw beans::UnknownPropertyException("Unknown property: " + rPropName, getXWeak()); + case FN_UNO_HEADER: + case FN_UNO_HEADER_LEFT: + case FN_UNO_HEADER_RIGHT: + case FN_UNO_HEADER_FIRST: + case FN_UNO_FOOTER: + case FN_UNO_FOOTER_LEFT: + case FN_UNO_FOOTER_RIGHT: + case FN_UNO_FOOTER_FIRST: + throw lang::IllegalArgumentException(); + case FN_PARAM_FTN_INFO: + { + const SwPageFootnoteInfoItem& rItem = aBaseImpl.GetItemSet().Get(FN_PARAM_FTN_INFO); + std::unique_ptr<SfxPoolItem> pNewFootnoteItem(rItem.Clone()); + if(!pNewFootnoteItem->PutValue(rValues[nProp], pEntry->nMemberId)) + throw lang::IllegalArgumentException(); + aBaseImpl.GetItemSet().Put(std::move(pNewFootnoteItem)); + break; + } + default: + { + SetStyleProperty(*pEntry, *pPropSet, rValues[nProp], aBaseImpl); + break; + } + } + } + + if(aBaseImpl.HasItemSet()) + { + ::sw::UndoGuard const undoGuard(GetDoc()->GetIDocumentUndoRedo()); + + if (undoGuard.UndoWasEnabled()) + { + // Fix i64460: as long as Undo of page styles with header/footer causes trouble... + GetDoc()->GetIDocumentUndoRedo().DelAllUndoObj(); + } + + aBaseImpl.getNewBase()->SetItemSet(aBaseImpl.GetItemSet()); + } +} + +void SwXPageStyle::setPropertyValues(const uno::Sequence<OUString>& rPropertyNames, const uno::Sequence<uno::Any>& rValues) +{ + SolarMutexGuard aGuard; + + // workaround for bad designed API + try + { + SetPropertyValues_Impl(rPropertyNames, rValues); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a lang::WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +static rtl::Reference<SwXHeadFootText> lcl_makeHeaderFooter(const sal_uInt16 nRes, const bool bHeader, SwFrameFormat const*const pFrameFormat) +{ + if (!pFrameFormat) + return nullptr; + const SfxItemSet& rSet = pFrameFormat->GetAttrSet(); + const SfxPoolItem* pItem; + if(SfxItemState::SET != rSet.GetItemState(nRes, true, &pItem)) + return nullptr; + SwFrameFormat* const pHeadFootFormat = bHeader + ? static_cast<SwFormatHeader*>(const_cast<SfxPoolItem*>(pItem))->GetHeaderFormat() + : static_cast<SwFormatFooter*>(const_cast<SfxPoolItem*>(pItem))->GetFooterFormat(); + if(!pHeadFootFormat) + return nullptr; + return SwXHeadFootText::CreateXHeadFootText(*pHeadFootFormat, bHeader); +} + +uno::Sequence<uno::Any> SwXPageStyle::GetPropertyValues_Impl(const uno::Sequence<OUString>& rPropertyNames) +{ + if(!GetDoc()) + throw uno::RuntimeException(); + + sal_Int32 nLength = rPropertyNames.getLength(); + uno::Sequence<uno::Any> aRet (nLength); + auto aRetRange = asNonConstRange(aRet); + if(!m_pBasePool) + { + if(!IsDescriptor()) + throw uno::RuntimeException(); + for(sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); ++nProp) + { + const uno::Any* pAny = nullptr; + m_pPropertiesImpl->GetProperty(rPropertyNames[nProp], pAny); + if (!pAny->hasValue()) + aRetRange[nProp] = m_xStyleData->getPropertyValue(rPropertyNames[nProp]); + else + aRetRange[nProp] = *pAny; + } + return aRet; + } + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PAGE_STYLE); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + SwStyleBase_Impl aBase(*GetDoc(), GetStyleName(), &GetDoc()->GetDfltFrameFormat()->GetAttrSet()); // add pDfltFrameFormat as parent + SfxStyleSheetBase* pBase = GetStyleSheetBase(); + if(!pBase) + throw uno::RuntimeException(); + for(sal_Int32 nProp = 0; nProp < nLength; ++nProp) + { + const OUString& rPropName = rPropertyNames[nProp]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rPropName); + + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropName, getXWeak() ); + const bool bHeader(rPropName.startsWith("Header")); + const bool bFooter(rPropName.startsWith("Footer")); + const bool bFirstIsShared(rPropName == UNO_NAME_FIRST_IS_SHARED); + if(bHeader || bFooter || bFirstIsShared) + { + switch(pEntry->nWID) + { + case SID_ATTR_PAGE_ON: + case RES_BACKGROUND: + case RES_BOX: + case RES_LR_SPACE: + case RES_SHADOW: + case RES_UL_SPACE: + case SID_ATTR_PAGE_DYNAMIC: + case SID_ATTR_PAGE_SHARED: + case SID_ATTR_PAGE_SHARED_FIRST: + case SID_ATTR_PAGE_SIZE: + case RES_HEADER_FOOTER_EAT_SPACING: + { + // slot is a Header/Footer slot + rtl::Reference< SwDocStyleSheet > xStyle( new SwDocStyleSheet( *static_cast<SwDocStyleSheet*>(pBase) ) ); + const SfxItemSet& rSet = xStyle->GetItemSet(); + const SvxSetItem* pSetItem; + + if (lcl_GetHeaderFooterItem(rSet, rPropName, bFooter, pSetItem)) + { + // get from SfxItemSet of the corresponding SfxSetItem + const SfxItemSet& rSetSet = pSetItem->GetItemSet(); + { + SwStyleBase_Impl::ItemSetOverrider o(aBase, &const_cast< SfxItemSet& >(rSetSet)); + aRetRange[nProp] = GetStyleProperty_Impl(*pEntry, *pPropSet, aBase); + } + } + else if(pEntry->nWID == SID_ATTR_PAGE_ON) + { + // header/footer is not available, thus off. Default is <false>, though + aRetRange[nProp] <<= false; + } + } + continue; + case XATTR_FILLBMP_SIZELOG: + case XATTR_FILLBMP_TILEOFFSETX: + case XATTR_FILLBMP_TILEOFFSETY: + case XATTR_FILLBMP_POSOFFSETX: + case XATTR_FILLBMP_POSOFFSETY: + case XATTR_FILLBMP_POS: + case XATTR_FILLBMP_SIZEX: + case XATTR_FILLBMP_SIZEY: + case XATTR_FILLBMP_STRETCH: + case XATTR_FILLBMP_TILE: + case OWN_ATTR_FILLBMP_MODE: + case XATTR_FILLCOLOR: + case XATTR_FILLBACKGROUND: + case XATTR_FILLBITMAP: + case XATTR_GRADIENTSTEPCOUNT: + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_FILLSTYLE: + case XATTR_FILLTRANSPARENCE: + case XATTR_FILLFLOATTRANSPARENCE: + case XATTR_SECONDARYFILLCOLOR: + if(bFirstIsShared) // only special handling for headers/footers here + break; + { + rtl::Reference< SwDocStyleSheet > xStyle( new SwDocStyleSheet( *static_cast<SwDocStyleSheet*>(pBase) ) ); + const SfxItemSet& rSet = xStyle->GetItemSet(); + const SvxSetItem* pSetItem = + rSet.GetItemIfSet(bFooter ? SID_ATTR_PAGE_FOOTERSET : SID_ATTR_PAGE_HEADERSET, false); + if(pSetItem) + { + // set at SfxItemSet of the corresponding SfxSetItem + const SfxItemSet& rSetSet = pSetItem->GetItemSet(); + { + SwStyleBase_Impl::ItemSetOverrider o(aBase, &const_cast<SfxItemSet&>(rSetSet)); + aRetRange[nProp] = GetStyleProperty_Impl(*pEntry, *pPropSet, aBase); + } + } + } + continue; + default: ; + } + } + switch(pEntry->nWID) + { + // these slots are exclusive to Header/Footer, thus this is an error + case SID_ATTR_PAGE_DYNAMIC: + case SID_ATTR_PAGE_SHARED: + case SID_ATTR_PAGE_SHARED_FIRST: + case SID_ATTR_PAGE_ON: + case RES_HEADER_FOOTER_EAT_SPACING: + throw beans::UnknownPropertyException( "Unknown property: " + rPropName, getXWeak() ); + case FN_UNO_HEADER: + case FN_UNO_HEADER_LEFT: + case FN_UNO_HEADER_FIRST: + case FN_UNO_HEADER_RIGHT: + case FN_UNO_FOOTER: + case FN_UNO_FOOTER_LEFT: + case FN_UNO_FOOTER_FIRST: + case FN_UNO_FOOTER_RIGHT: + { + bool bLeft(false); + bool bFirst(false); + sal_uInt16 nRes = 0; + switch(pEntry->nWID) + { + case FN_UNO_HEADER: nRes = RES_HEADER; break; + case FN_UNO_HEADER_LEFT: nRes = RES_HEADER; bLeft = true; break; + case FN_UNO_HEADER_FIRST: nRes = RES_HEADER; bFirst = true; break; + case FN_UNO_HEADER_RIGHT: nRes = RES_HEADER; break; + case FN_UNO_FOOTER: nRes = RES_FOOTER; break; + case FN_UNO_FOOTER_LEFT: nRes = RES_FOOTER; bLeft = true; break; + case FN_UNO_FOOTER_FIRST: nRes = RES_FOOTER; bFirst = true; break; + case FN_UNO_FOOTER_RIGHT: nRes = RES_FOOTER; break; + default: ; + } + + const SwPageDesc* pDesc = aBase.GetOldPageDesc(); + assert(pDesc); + const SwFrameFormat* pFrameFormat = nullptr; + bool bShare = (nRes == RES_HEADER && pDesc->IsHeaderShared()) || (nRes == RES_FOOTER && pDesc->IsFooterShared()); + bool bShareFirst = pDesc->IsFirstShared(); + // TextLeft returns the left content if there is one, + // Text and TextRight return the master content. + // TextRight does the same as Text and is for + // compatibility only. + if(bLeft && !bShare) + pFrameFormat = &pDesc->GetLeft(); + else if(bFirst && !bShareFirst) + { + pFrameFormat = &pDesc->GetFirstMaster(); + // no need to make GetFirstLeft() accessible + // since it is always shared + } + else + pFrameFormat = &pDesc->GetMaster(); + const uno::Reference<text::XText> xRet = lcl_makeHeaderFooter(nRes, nRes == RES_HEADER, pFrameFormat); + if (xRet.is()) + aRetRange[nProp] <<= xRet; + } + break; + case FN_PARAM_FTN_INFO: + { + rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + const SfxItemSet& rSet = xStyle->GetItemSet(); + const SfxPoolItem& rItem = rSet.Get(FN_PARAM_FTN_INFO); + rItem.QueryValue(aRetRange[nProp], pEntry->nMemberId); + } + break; + default: + aRetRange[nProp] = GetStyleProperty_Impl(*pEntry, *pPropSet, aBase); + } + } + return aRet; +} + +uno::Sequence<uno::Any> SwXPageStyle::getPropertyValues(const uno::Sequence<OUString>& rPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence<uno::Any> aValues; + + // workaround for bad designed API + try + { + aValues = GetPropertyValues_Impl(rPropertyNames); + } + catch(beans::UnknownPropertyException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch(lang::WrappedTargetException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + + return aValues; +} + +uno::Any SwXPageStyle::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + const uno::Sequence<OUString> aProperties(&rPropertyName, 1); + return GetPropertyValues_Impl(aProperties)[0]; +} + +void SwXPageStyle::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + const uno::Sequence<OUString> aProperties(&rPropertyName, 1); + const uno::Sequence<uno::Any> aValues(&rValue, 1); + + // Trick: if the Domain Mapper changes the props of shared header/footer, + // store the old ones in time for later use. + const bool bIsHeader = rPropertyName == UNO_NAME_HEADER_IS_SHARED; + const bool bIsFooter = rPropertyName == UNO_NAME_FOOTER_IS_SHARED; + if ((bIsFooter || bIsHeader) && rValue == uno::Any(true)) + { + // Find the matching page descriptor + for (size_t i = 0; i < GetDoc()->GetPageDescCnt(); i++) + { + auto pPageDesc = &GetDoc()->GetPageDesc(i); + // If we have the right page descriptor stash the necessary formats in import time. + if (pPageDesc->GetName() == GetStyleName()) + { + auto pLeftHeader = pPageDesc->GetLeft().GetHeader().GetHeaderFormat(); + if (bIsHeader && pLeftHeader) + { + pPageDesc->StashFrameFormat(pPageDesc->GetLeft(), true, true, false); + pPageDesc->StashFrameFormat(pPageDesc->GetFirstMaster(), true, false, true); + pPageDesc->StashFrameFormat(pPageDesc->GetFirstLeft(), true, true, true); + } + auto pLeftFooter = pPageDesc->GetLeft().GetFooter().GetFooterFormat(); + if (bIsFooter && pLeftFooter) + { + pPageDesc->StashFrameFormat(pPageDesc->GetLeft(), false, true, false); + pPageDesc->StashFrameFormat(pPageDesc->GetFirstMaster(), false, false, true); + pPageDesc->StashFrameFormat(pPageDesc->GetFirstLeft(), false, true, true); + } + } + } + } + // And set the props... as we did it before. + SetPropertyValues_Impl(aProperties, aValues); +} + +SwXFrameStyle::SwXFrameStyle(SwDoc *pDoc) + : SwXFrameStyle_Base(pDoc, SfxStyleFamily::Frame, false) +{ } + +void SwXFrameStyle::SetItem(sal_uInt16 eAtr, const SfxPoolItem& rItem) +{ + assert(eAtr >= RES_FRMATR_BEGIN && eAtr < RES_FRMATR_END); + SfxStyleSheetBase* pBase = GetStyleSheetBase(); + if(!pBase) + return; + rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + SfxItemSet& rStyleSet = xStyle->GetItemSet(); + SfxItemSet aSet(*rStyleSet.GetPool(), sal_uInt16(eAtr), sal_uInt16(eAtr)); + aSet.Put(rItem); + xStyle->SetItemSet(aSet); +} + +const SfxPoolItem* SwXFrameStyle::GetItem(sal_uInt16 eAtr) +{ + assert(eAtr >= RES_FRMATR_BEGIN && eAtr < RES_FRMATR_END); + SfxStyleSheetBase* pBase = GetStyleSheetBase(); + if(!pBase) + return nullptr; + rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase))); + return &xStyle->GetItemSet().Get(eAtr); +} + +uno::Reference<container::XNameReplace> SwXFrameStyle::getEvents() +{ + return new SwFrameStyleEventDescriptor(*this); +} + +// Already implemented autostyle families: 3 +#define AUTOSTYLE_FAMILY_COUNT 3 +const IStyleAccess::SwAutoStyleFamily aAutoStyleByIndex[] = +{ + IStyleAccess::AUTO_STYLE_CHAR, + IStyleAccess::AUTO_STYLE_RUBY, + IStyleAccess::AUTO_STYLE_PARA +}; + +class SwAutoStylesEnumImpl +{ + std::vector<std::shared_ptr<SfxItemSet>> mAutoStyles; + std::vector<std::shared_ptr<SfxItemSet>>::iterator m_aIter; + SwDoc& m_rDoc; + IStyleAccess::SwAutoStyleFamily m_eFamily; +public: + SwAutoStylesEnumImpl( SwDoc& rInitDoc, IStyleAccess::SwAutoStyleFamily eFam ); + bool hasMoreElements() { return m_aIter != mAutoStyles.end(); } + std::shared_ptr<SfxItemSet> const & nextElement() { return *(m_aIter++); } + IStyleAccess::SwAutoStyleFamily getFamily() const { return m_eFamily; } + SwDoc& getDoc() const { return m_rDoc; } +}; + +SwXAutoStyles::SwXAutoStyles(SwDocShell& rDocShell) : + SwUnoCollection(rDocShell.GetDoc()), m_pDocShell( &rDocShell ) +{ +} + +SwXAutoStyles::~SwXAutoStyles() +{ +} + +sal_Int32 SwXAutoStyles::getCount() +{ + return AUTOSTYLE_FAMILY_COUNT; +} + +uno::Any SwXAutoStyles::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + if(nIndex < 0 || nIndex >= AUTOSTYLE_FAMILY_COUNT) + throw lang::IndexOutOfBoundsException(); + if(!IsValid()) + throw uno::RuntimeException(); + + uno::Reference< style::XAutoStyleFamily > aRef; + IStyleAccess::SwAutoStyleFamily nType = aAutoStyleByIndex[nIndex]; + switch( nType ) + { + case IStyleAccess::AUTO_STYLE_CHAR: + { + if(!m_xAutoCharStyles.is()) + m_xAutoCharStyles = new SwXAutoStyleFamily(m_pDocShell, nType); + aRef = m_xAutoCharStyles; + } + break; + case IStyleAccess::AUTO_STYLE_RUBY: + { + if(!m_xAutoRubyStyles.is()) + m_xAutoRubyStyles = new SwXAutoStyleFamily(m_pDocShell, nType ); + aRef = m_xAutoRubyStyles; + } + break; + case IStyleAccess::AUTO_STYLE_PARA: + { + if(!m_xAutoParaStyles.is()) + m_xAutoParaStyles = new SwXAutoStyleFamily(m_pDocShell, nType ); + aRef = m_xAutoParaStyles; + } + break; + + default: + ; + } + aRet <<= aRef; + + return aRet; +} + +uno::Type SwXAutoStyles::getElementType( ) +{ + return cppu::UnoType<style::XAutoStyleFamily>::get(); +} + +sal_Bool SwXAutoStyles::hasElements( ) +{ + return true; +} + +uno::Any SwXAutoStyles::getByName(const OUString& Name) +{ + uno::Any aRet; + if(Name == "CharacterStyles") + aRet = getByIndex(0); + else if(Name == "RubyStyles") + aRet = getByIndex(1); + else if(Name == "ParagraphStyles") + aRet = getByIndex(2); + else + throw container::NoSuchElementException(); + return aRet; +} + +uno::Sequence< OUString > SwXAutoStyles::getElementNames() +{ + uno::Sequence< OUString > aNames(AUTOSTYLE_FAMILY_COUNT); + OUString* pNames = aNames.getArray(); + pNames[0] = "CharacterStyles"; + pNames[1] = "RubyStyles"; + pNames[2] = "ParagraphStyles"; + return aNames; +} + +sal_Bool SwXAutoStyles::hasByName(const OUString& Name) +{ + if( Name == "CharacterStyles" || + Name == "RubyStyles" || + Name == "ParagraphStyles" ) + return true; + else + return false; +} + +SwXAutoStyleFamily::SwXAutoStyleFamily(SwDocShell* pDocSh, IStyleAccess::SwAutoStyleFamily nFamily) : + m_pDocShell( pDocSh ), m_eFamily(nFamily) +{ + // Register ourselves as a listener to the document (via the page descriptor) + StartListening(pDocSh->GetDoc()->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); +} + +SwXAutoStyleFamily::~SwXAutoStyleFamily() +{ +} + +void SwXAutoStyleFamily::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pDocShell = nullptr; +} + +std::shared_ptr<SfxItemSet> +PropValuesToAutoStyleItemSet(SwDoc& rDoc, IStyleAccess::SwAutoStyleFamily eFamily, + const uno::Sequence<beans::PropertyValue>& Values, SwAttrSet& aSet) +{ + const SfxItemPropertySet* pPropSet = nullptr; + switch( eFamily ) + { + case IStyleAccess::AUTO_STYLE_CHAR: + { + pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE); + break; + } + case IStyleAccess::AUTO_STYLE_RUBY: + { + pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_RUBY_AUTO_STYLE); + break; + } + case IStyleAccess::AUTO_STYLE_PARA: + { + pPropSet = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE); + break; + } + default: ; + } + + if( !pPropSet) + throw uno::RuntimeException(); + + const bool bTakeCareOfDrawingLayerFillStyle(IStyleAccess::AUTO_STYLE_PARA == eFamily); + + if(!bTakeCareOfDrawingLayerFillStyle) + { + for( const beans::PropertyValue& rValue : Values ) + { + try + { + pPropSet->setPropertyValue( rValue.Name, rValue.Value, aSet ); + } + catch (const beans::UnknownPropertyException &) + { + OSL_FAIL( "Unknown property" ); + } + catch (const lang::IllegalArgumentException &) + { + OSL_FAIL( "Illegal argument" ); + } + } + } + else + { + // set parent to ItemSet to ensure XFILL_NONE as XFillStyleItem + // to make cases in RES_BACKGROUND work correct; target *is* a style + // where this is the case + aSet.SetParent(&rDoc.GetDfltTextFormatColl()->GetAttrSet()); + + // here the used DrawingLayer FillStyles are imported when family is + // equal to IStyleAccess::AUTO_STYLE_PARA, thus we will need to serve the + // used slots functionality here to do this correctly + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + + for( const beans::PropertyValue& rValue : Values ) + { + const OUString& rPropName = rValue.Name; + uno::Any aValue(rValue.Value); + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rPropName); + + if (!pEntry) + { + SAL_WARN("sw.core", "SwXAutoStyleFamily::insertStyle: Unknown property: " << rPropName); + continue; + } + + const sal_uInt8 nMemberId(pEntry->nMemberId); + bool bDone(false); + + // check for needed metric translation + if(pEntry->nMoreFlags & PropertyMoreFlags::METRIC_ITEM) + { + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == pEntry->nWID || XATTR_FILLBMP_SIZEY == pEntry->nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(aValue >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const SfxItemPool& rPool = rDoc.GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(pEntry->nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertFromMM(eMapUnit, aValue); + } + } + } + + switch(pEntry->nWID) + { + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_FILLBITMAP: + case XATTR_FILLFLOATTRANSPARENCE: + // not yet needed; activate when LineStyle support may be added + // case XATTR_LINESTART: + // case XATTR_LINEEND: + // case XATTR_LINEDASH: + { + if(MID_NAME == nMemberId) + { + // add set commands for FillName items + OUString aTempName; + + if(!(aValue >>= aTempName)) + { + throw lang::IllegalArgumentException(); + } + + SvxShape::SetFillAttribute(pEntry->nWID, aTempName, aSet); + bDone = true; + } + else if (MID_BITMAP == nMemberId) + { + if(XATTR_FILLBITMAP == pEntry->nWID) + { + Graphic aNullGraphic; + XFillBitmapItem aXFillBitmapItem(std::move(aNullGraphic)); + + aXFillBitmapItem.PutValue(aValue, nMemberId); + aSet.Put(aXFillBitmapItem); + bDone = true; + } + } + + break; + } + case RES_BACKGROUND: + { + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(aSet, RES_BACKGROUND, true, rDoc.IsInXMLImport())); + std::unique_ptr<SvxBrushItem> aChangedBrushItem(aOriginalBrushItem->Clone()); + + aChangedBrushItem->PutValue(aValue, nMemberId); + + if(*aChangedBrushItem != *aOriginalBrushItem) + { + setSvxBrushItemAsFillAttributesToTargetSet(*aChangedBrushItem, aSet); + } + + bDone = true; + break; + } + case OWN_ATTR_FILLBMP_MODE: + { + drawing::BitmapMode eMode; + + if(!(aValue >>= eMode)) + { + sal_Int32 nMode = 0; + + if(!(aValue >>= nMode)) + { + throw lang::IllegalArgumentException(); + } + + eMode = static_cast<drawing::BitmapMode>(nMode); + } + + aSet.Put(XFillBmpStretchItem(drawing::BitmapMode_STRETCH == eMode)); + aSet.Put(XFillBmpTileItem(drawing::BitmapMode_REPEAT == eMode)); + + bDone = true; + break; + } + default: break; + } + + if(!bDone) + { + try + { + pPropSet->setPropertyValue( rPropName, aValue, aSet ); + } + catch (const beans::UnknownPropertyException &) + { + OSL_FAIL( "Unknown property" ); + } + catch (const lang::IllegalArgumentException &) + { + OSL_FAIL( "Illegal argument" ); + } + } + } + + // clear parent again + aSet.SetParent(nullptr); + } + + // need to ensure uniqueness of evtl. added NameOrIndex items + // currently in principle only needed when bTakeCareOfDrawingLayerFillStyle, + // but does not hurt and is easily forgotten later eventually, so keep it + // as common case + rDoc.CheckForUniqueItemForLineFillNameOrIndex(aSet); + + return rDoc.GetIStyleAccess().cacheAutomaticStyle(aSet, eFamily); +} + +uno::Reference< style::XAutoStyle > SwXAutoStyleFamily::insertStyle( + const uno::Sequence< beans::PropertyValue >& Values ) +{ + if (!m_pDocShell) + { + throw uno::RuntimeException(); + } + + WhichRangesContainer pRange; + switch (m_eFamily) + { + case IStyleAccess::AUTO_STYLE_CHAR: + { + pRange = aCharAutoFormatSetRange; + break; + } + case IStyleAccess::AUTO_STYLE_RUBY: + { + pRange = WhichRangesContainer(RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY); + break; + } + case IStyleAccess::AUTO_STYLE_PARA: + { + pRange = aTextNodeSetRange; // checked, already added support for [XATTR_FILL_FIRST, XATTR_FILL_LAST] + break; + } + default: + throw uno::RuntimeException(); + } + + SwAttrSet aEmptySet(m_pDocShell->GetDoc()->GetAttrPool(), pRange); + auto pSet = PropValuesToAutoStyleItemSet(*m_pDocShell->GetDoc(), m_eFamily, Values, aEmptySet); + + uno::Reference<style::XAutoStyle> xRet = new SwXAutoStyle(m_pDocShell->GetDoc(), pSet, m_eFamily); + + return xRet; +} + +uno::Reference< container::XEnumeration > SwXAutoStyleFamily::createEnumeration( ) +{ + if( !m_pDocShell ) + throw uno::RuntimeException(); + return uno::Reference< container::XEnumeration > + (new SwXAutoStylesEnumerator( *m_pDocShell->GetDoc(), m_eFamily )); +} + +uno::Type SwXAutoStyleFamily::getElementType( ) +{ + return cppu::UnoType<style::XAutoStyle>::get(); +} + +sal_Bool SwXAutoStyleFamily::hasElements( ) +{ + return false; +} + +SwAutoStylesEnumImpl::SwAutoStylesEnumImpl( SwDoc& rInitDoc, IStyleAccess::SwAutoStyleFamily eFam ) +: m_rDoc( rInitDoc ), m_eFamily( eFam ) +{ + // special case for ruby auto styles: + if ( IStyleAccess::AUTO_STYLE_RUBY == eFam ) + { + std::set< std::pair< sal_uInt16, text::RubyAdjust > > aRubyMap; + SwAttrPool& rAttrPool = m_rDoc.GetAttrPool(); + + // do this in two phases otherwise we invalidate the iterators when we insert into the pool + std::vector<const SwFormatRuby*> vRubyItems; + for (const SfxPoolItem* pItem : rAttrPool.GetItemSurrogates(RES_TXTATR_CJK_RUBY)) + { + auto pRubyItem = dynamic_cast<const SwFormatRuby*>(pItem); + if ( pRubyItem && pRubyItem->GetTextRuby() ) + vRubyItems.push_back(pRubyItem); + } + for (const SwFormatRuby* pRubyItem : vRubyItems) + { + std::pair< sal_uInt16, text::RubyAdjust > aPair( pRubyItem->GetPosition(), pRubyItem->GetAdjustment() ); + if ( aRubyMap.insert( aPair ).second ) + { + auto pItemSet = std::make_shared<SfxItemSetFixed<RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY>>( rAttrPool ); + pItemSet->Put( *pRubyItem ); + mAutoStyles.push_back( pItemSet ); + } + } + } + else + { + m_rDoc.GetIStyleAccess().getAllStyles( mAutoStyles, m_eFamily ); + } + + m_aIter = mAutoStyles.begin(); +} + +SwXAutoStylesEnumerator::SwXAutoStylesEnumerator( SwDoc& rDoc, IStyleAccess::SwAutoStyleFamily eFam ) +: m_pImpl( new SwAutoStylesEnumImpl( rDoc, eFam ) ) +{ + // Register ourselves as a listener to the document (via the page descriptor) + StartListening(rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); +} + +SwXAutoStylesEnumerator::~SwXAutoStylesEnumerator() +{ +} + +void SwXAutoStylesEnumerator::Notify( const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pImpl.reset(); +} + +sal_Bool SwXAutoStylesEnumerator::hasMoreElements( ) +{ + if( !m_pImpl ) + throw uno::RuntimeException(); + return m_pImpl->hasMoreElements(); +} + +uno::Any SwXAutoStylesEnumerator::nextElement( ) +{ + if( !m_pImpl ) + throw uno::RuntimeException(); + uno::Any aRet; + if( m_pImpl->hasMoreElements() ) + { + std::shared_ptr<SfxItemSet> pNextSet = m_pImpl->nextElement(); + uno::Reference< style::XAutoStyle > xAutoStyle = new SwXAutoStyle(&m_pImpl->getDoc(), + pNextSet, m_pImpl->getFamily()); + aRet <<= xAutoStyle; + } + return aRet; +} + +// SwXAutoStyle with the family IStyleAccess::AUTO_STYLE_PARA (or +// PROPERTY_MAP_PARA_AUTO_STYLE) now uses DrawingLayer FillStyles to allow +// unified paragraph background fill, thus the UNO API implementation has to +// support the needed slots for these. This seems to be used only for reading +// (no setPropertyValue implementation here), so maybe specialized for saving +// the Writer Doc to ODF + +SwXAutoStyle::SwXAutoStyle( + SwDoc* pDoc, + std::shared_ptr<SfxItemSet> pInitSet, + IStyleAccess::SwAutoStyleFamily eFam) +: mpSet(std::move(pInitSet)), + meFamily(eFam), + mrDoc(*pDoc) +{ + // Register ourselves as a listener to the document (via the page descriptor) + //StartListening(mrDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier()); +} + +SwXAutoStyle::~SwXAutoStyle() +{ +} + +void SwXAutoStyle::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + mpSet.reset(); +} + +uno::Reference< beans::XPropertySetInfo > SwXAutoStyle::getPropertySetInfo( ) +{ + uno::Reference< beans::XPropertySetInfo > xRet; + switch( meFamily ) + { + case IStyleAccess::AUTO_STYLE_CHAR: + { + static const auto xCharRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)->getPropertySetInfo(); + xRet = xCharRef; + } + break; + case IStyleAccess::AUTO_STYLE_RUBY: + { + static const auto xRubyRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_RUBY_AUTO_STYLE)->getPropertySetInfo(); + xRet = xRubyRef; + } + break; + case IStyleAccess::AUTO_STYLE_PARA: + { + static const auto xParaRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE)->getPropertySetInfo(); + xRet = xParaRef; + } + break; + + default: + ; + } + + return xRet; +} + +void SwXAutoStyle::setPropertyValue( const OUString& /*rPropertyName*/, const uno::Any& /*rValue*/ ) +{ +} + +uno::Any SwXAutoStyle::getPropertyValue( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + const uno::Sequence<OUString> aProperties(&rPropertyName, 1); + return GetPropertyValues_Impl(aProperties).getConstArray()[0]; +} + +void SwXAutoStyle::addPropertyChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ +} + +void SwXAutoStyle::removePropertyChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ +} + +void SwXAutoStyle::addVetoableChangeListener( const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + +void SwXAutoStyle::removeVetoableChangeListener( const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + +void SwXAutoStyle::setPropertyValues( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Sequence< uno::Any >& /*aValues*/ ) +{ +} + +uno::Sequence< uno::Any > SwXAutoStyle::GetPropertyValues_Impl( + const uno::Sequence< OUString > & rPropertyNames ) +{ + if( !mpSet ) + { + throw uno::RuntimeException(); + } + + // query_item + sal_uInt16 nPropSetId = PROPERTY_MAP_CHAR_AUTO_STYLE; + switch(meFamily) + { + case IStyleAccess::AUTO_STYLE_CHAR : nPropSetId = PROPERTY_MAP_CHAR_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_RUBY : nPropSetId = PROPERTY_MAP_RUBY_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_PARA : nPropSetId = PROPERTY_MAP_PARA_AUTO_STYLE; break; + default: ; + } + + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + const OUString* pNames = rPropertyNames.getConstArray(); + + const sal_Int32 nLen(rPropertyNames.getLength()); + uno::Sequence< uno::Any > aRet( nLen ); + uno::Any* pValues = aRet.getArray(); + const bool bTakeCareOfDrawingLayerFillStyle(IStyleAccess::AUTO_STYLE_PARA == meFamily); + + for( sal_Int32 i = 0; i < nLen; ++i ) + { + const OUString sPropName = pNames[i]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(sPropName); + if(!pEntry) + { + throw beans::UnknownPropertyException("Unknown property: " + sPropName, getXWeak() ); + } + + uno::Any aTarget; + bool bDone(false); + + if ( RES_TXTATR_AUTOFMT == pEntry->nWID || RES_AUTO_STYLE == pEntry->nWID ) + { + OUString sName(StylePool::nameOf( mpSet )); + aTarget <<= sName; + bDone = true; + } + else if(bTakeCareOfDrawingLayerFillStyle) + { + // add support for DrawingLayer FillStyle slots + switch(pEntry->nWID) + { + case RES_BACKGROUND: + { + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(*mpSet, RES_BACKGROUND)); + + if(!aOriginalBrushItem->QueryValue(aTarget, pEntry->nMemberId)) + { + OSL_ENSURE(false, "Error getting attribute from RES_BACKGROUND (!)"); + } + + bDone = true; + break; + } + case OWN_ATTR_FILLBMP_MODE: + { + if (mpSet->Get(XATTR_FILLBMP_TILE).GetValue()) + { + aTarget <<= drawing::BitmapMode_REPEAT; + } + else if (mpSet->Get(XATTR_FILLBMP_STRETCH).GetValue()) + { + aTarget <<= drawing::BitmapMode_STRETCH; + } + else + { + aTarget <<= drawing::BitmapMode_NO_REPEAT; + } + + bDone = true; + break; + } + } + } + + if(!bDone) + { + pPropSet->getPropertyValue( *pEntry, *mpSet, aTarget ); + } + + if(bTakeCareOfDrawingLayerFillStyle) + { + if(pEntry->aType == cppu::UnoType<sal_Int16>::get() && pEntry->aType != aTarget.getValueType()) + { + // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here + sal_Int32 nValue = 0; + if (aTarget >>= nValue) + { + aTarget <<= static_cast<sal_Int16>(nValue); + } + } + + // check for needed metric translation + if(pEntry->nMoreFlags & PropertyMoreFlags::METRIC_ITEM) + { + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == pEntry->nWID || XATTR_FILLBMP_SIZEY == pEntry->nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(aTarget >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const SfxItemPool& rPool = mrDoc.GetAttrPool(); + const MapUnit eMapUnit(rPool.GetMetric(pEntry->nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertToMM(eMapUnit, aTarget); + } + } + } + } + + // add value + pValues[i] = aTarget; + } + + return aRet; +} + +uno::Sequence< uno::Any > SwXAutoStyle::getPropertyValues ( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Any > aValues; + + // workaround for bad designed API + try + { + aValues = GetPropertyValues_Impl( rPropertyNames ); + } + catch (beans::UnknownPropertyException &) + { + css::uno::Any exc = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("Unknown property exception caught", getXWeak(), exc ); + } + catch (lang::WrappedTargetException &) + { + css::uno::Any exc = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("WrappedTargetException caught", getXWeak(), exc ); + } + + return aValues; +} + +void SwXAutoStyle::addPropertiesChangeListener( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ +} + +void SwXAutoStyle::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ +} + +void SwXAutoStyle::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ +} + +beans::PropertyState SwXAutoStyle::getPropertyState( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + + uno::Sequence< OUString > aNames { rPropertyName }; + uno::Sequence< beans::PropertyState > aStates = getPropertyStates(aNames); + return aStates.getConstArray()[0]; +} + +void SwXAutoStyle::setPropertyToDefault( const OUString& /*PropertyName*/ ) +{ +} + +uno::Any SwXAutoStyle::getPropertyDefault( const OUString& rPropertyName ) +{ + const uno::Sequence < OUString > aSequence ( &rPropertyName, 1 ); + return getPropertyDefaults ( aSequence ).getConstArray()[0]; +} + +uno::Sequence< beans::PropertyState > SwXAutoStyle::getPropertyStates( + const uno::Sequence< OUString >& rPropertyNames ) +{ + if (!mpSet) + { + throw uno::RuntimeException(); + } + + SolarMutexGuard aGuard; + uno::Sequence< beans::PropertyState > aRet(rPropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + const OUString* pNames = rPropertyNames.getConstArray(); + + sal_uInt16 nPropSetId = PROPERTY_MAP_CHAR_AUTO_STYLE; + switch(meFamily) + { + case IStyleAccess::AUTO_STYLE_CHAR : nPropSetId = PROPERTY_MAP_CHAR_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_RUBY : nPropSetId = PROPERTY_MAP_RUBY_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_PARA : nPropSetId = PROPERTY_MAP_PARA_AUTO_STYLE; break; + default: ; + } + + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap(); + const bool bTakeCareOfDrawingLayerFillStyle(IStyleAccess::AUTO_STYLE_PARA == meFamily); + + for(sal_Int32 i = 0; i < rPropertyNames.getLength(); i++) + { + const OUString sPropName = pNames[i]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(sPropName); + if(!pEntry) + { + throw beans::UnknownPropertyException("Unknown property: " + sPropName, getXWeak() ); + } + + bool bDone(false); + + if(bTakeCareOfDrawingLayerFillStyle) + { + // DrawingLayer PropertyStyle support + switch(pEntry->nWID) + { + case OWN_ATTR_FILLBMP_MODE: + { + if(SfxItemState::SET == mpSet->GetItemState(XATTR_FILLBMP_STRETCH, false) + || SfxItemState::SET == mpSet->GetItemState(XATTR_FILLBMP_TILE, false)) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_AMBIGUOUS_VALUE; + } + + bDone = true; + break; + } + case RES_BACKGROUND: + { + if (SWUnoHelper::needToMapFillItemsToSvxBrushItemTypes(*mpSet, + pEntry->nMemberId)) + { + pStates[i] = beans::PropertyState_DIRECT_VALUE; + } + else + { + pStates[i] = beans::PropertyState_DEFAULT_VALUE; + } + bDone = true; + + break; + } + } + } + + if(!bDone) + { + pStates[i] = pPropSet->getPropertyState(*pEntry, *mpSet ); + } + } + + return aRet; +} + +void SwXAutoStyle::setAllPropertiesToDefault( ) +{ +} + +void SwXAutoStyle::setPropertiesToDefault( + const uno::Sequence< OUString >& /*rPropertyNames*/ ) +{ +} + +uno::Sequence< uno::Any > SwXAutoStyle::getPropertyDefaults( + const uno::Sequence< OUString >& /*aPropertyNames*/ ) +{ + return { }; +} + +uno::Sequence< beans::PropertyValue > SwXAutoStyle::getProperties() +{ + if( !mpSet ) + throw uno::RuntimeException(); + SolarMutexGuard aGuard; + std::vector< beans::PropertyValue > aPropertyVector; + + sal_uInt16 nPropSetId = 0; + switch(meFamily) + { + case IStyleAccess::AUTO_STYLE_CHAR : nPropSetId = PROPERTY_MAP_CHAR_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_RUBY : nPropSetId = PROPERTY_MAP_RUBY_AUTO_STYLE; break; + case IStyleAccess::AUTO_STYLE_PARA : nPropSetId = PROPERTY_MAP_PARA_AUTO_STYLE; break; + default: ; + } + + const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId); + const SfxItemPropertyMap &rMap = pPropSet->getPropertyMap(); + + SfxItemSet& rSet = *mpSet; + SfxItemIter aIter(rSet); + + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + const sal_uInt16 nWID = pItem->Which(); + + // TODO: Optimize - and fix! the old iteration filled each WhichId + // only once but there are more properties than WhichIds + for( const auto pEntry : rMap.getPropertyEntries() ) + { + if ( pEntry->nWID == nWID ) + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name = pEntry->aName; + pItem->QueryValue( aPropertyValue.Value, pEntry->nMemberId ); + aPropertyVector.push_back( aPropertyValue ); + } + } + } + + const sal_Int32 nCount = aPropertyVector.size(); + uno::Sequence< beans::PropertyValue > aRet( nCount ); + beans::PropertyValue* pProps = aRet.getArray(); + + for ( int i = 0; i < nCount; ++i, pProps++ ) + { + *pProps = aPropertyVector[i]; + } + + return aRet; +} + +SwXTextTableStyle::SwXTextTableStyle(SwDocShell* pDocShell, SwTableAutoFormat* pTableAutoFormat) : + m_pDocShell(pDocShell), m_pTableAutoFormat(pTableAutoFormat), m_bPhysical(true) +{ + UpdateCellStylesMapping(); +} + +SwXTextTableStyle::SwXTextTableStyle(SwDocShell* pDocShell, const OUString& rTableAutoFormatName) : + m_pDocShell(pDocShell), m_pTableAutoFormat_Impl(new SwTableAutoFormat(rTableAutoFormatName)), m_bPhysical(false) +{ + m_pTableAutoFormat = m_pTableAutoFormat_Impl.get(); + UpdateCellStylesMapping(); +} + +uno::Reference<style::XStyle> SwXTextTableStyle::CreateXTextTableStyle(SwDocShell* pDocShell, const OUString& rTableAutoFormatName) +{ + SolarMutexGuard aGuard; + rtl::Reference<SwXTextTableStyle> xTextTableStyle; + SwTableAutoFormat* pAutoFormat = GetTableAutoFormat(pDocShell, rTableAutoFormatName); + if (pAutoFormat && pAutoFormat->GetName() == rTableAutoFormatName) + { + xTextTableStyle = pAutoFormat->GetXObject(); + if (!xTextTableStyle.is()) + { + xTextTableStyle.set(new SwXTextTableStyle(pDocShell, pAutoFormat)); + pAutoFormat->SetXObject(xTextTableStyle); + } + } + + // If corresponding AutoFormat doesn't exist create a non physical style. + if (!xTextTableStyle.is()) + { + xTextTableStyle.set(new SwXTextTableStyle(pDocShell, rTableAutoFormatName)); + SAL_INFO("sw.uno", "creating SwXTextTableStyle for non existing SwTableAutoFormat"); + } + + return xTextTableStyle; +} + +void SwXTextTableStyle::UpdateCellStylesMapping() +{ + const std::vector<sal_Int32> aTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap(); + assert(aTableTemplateMap.size() == STYLE_COUNT && "can not map SwTableAutoFormat to a SwXTextTableStyle"); + for (sal_Int32 i=0; i<STYLE_COUNT; ++i) + { + SwBoxAutoFormat* pBoxFormat = &m_pTableAutoFormat->GetBoxFormat(aTableTemplateMap[i]); + rtl::Reference<SwXTextCellStyle> xCellStyle(pBoxFormat->GetXObject()); + if (!xCellStyle.is()) + { + xCellStyle.set(new SwXTextCellStyle(m_pDocShell, pBoxFormat, m_pTableAutoFormat->GetName())); + pBoxFormat->SetXObject(xCellStyle); + } + m_aCellStyles[i] = xCellStyle; + } +} + +const CellStyleNameMap& SwXTextTableStyle::GetCellStyleNameMap() +{ + static CellStyleNameMap const aMap + { + { "first-row" , FIRST_ROW_STYLE }, + { "last-row" , LAST_ROW_STYLE }, + { "first-column" , FIRST_COLUMN_STYLE }, + { "last-column" , LAST_COLUMN_STYLE }, + { "body" , BODY_STYLE }, + { "even-rows" , EVEN_ROWS_STYLE }, + { "odd-rows" , ODD_ROWS_STYLE }, + { "even-columns" , EVEN_COLUMNS_STYLE }, + { "odd-columns" , ODD_COLUMNS_STYLE }, + { "background" , BACKGROUND_STYLE }, + // loext namespace + { "first-row-start-column" , FIRST_ROW_START_COLUMN_STYLE }, + { "first-row-end-column" , FIRST_ROW_END_COLUMN_STYLE }, + { "last-row-start-column" , LAST_ROW_START_COLUMN_STYLE }, + { "last-row-end-column" , LAST_ROW_END_COLUMN_STYLE }, + { "first-row-even-column" , FIRST_ROW_EVEN_COLUMN_STYLE }, + { "last-row-even-column" , LAST_ROW_EVEN_COLUMN_STYLE }, + }; + return aMap; +} + +SwTableAutoFormat* SwXTextTableStyle::GetTableFormat() +{ + return m_pTableAutoFormat; +} + +SwTableAutoFormat* SwXTextTableStyle::GetTableAutoFormat(SwDocShell* pDocShell, std::u16string_view sName) +{ + const size_t nStyles = pDocShell->GetDoc()->GetTableStyles().size(); + for(size_t i=0; i < nStyles; ++i) + { + SwTableAutoFormat* pAutoFormat = &pDocShell->GetDoc()->GetTableStyles()[i]; + if (pAutoFormat->GetName() == sName) + { + return pAutoFormat; + } + } + // not found + return nullptr; +} + +void SwXTextTableStyle::SetPhysical() +{ + if (!m_bPhysical) + { + // find table format in doc + SwTableAutoFormat* pTableAutoFormat = GetTableAutoFormat(m_pDocShell, m_pTableAutoFormat->GetName()); + if (pTableAutoFormat) + { + m_bPhysical = true; + /// take care of children, make SwXTextCellStyles use new core SwBoxAutoFormats + const std::vector<sal_Int32> aTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap(); + for (size_t i=0; i<aTableTemplateMap.size(); ++i) + { + SwBoxAutoFormat* pOldBoxFormat = &m_pTableAutoFormat->GetBoxFormat(aTableTemplateMap[i]); + rtl::Reference<SwXTextCellStyle> xCellStyle(pOldBoxFormat->GetXObject()); + if (!xCellStyle.is()) + continue; + SwBoxAutoFormat& rNewBoxFormat = pTableAutoFormat->GetBoxFormat(aTableTemplateMap[i]); + xCellStyle->SetBoxFormat(&rNewBoxFormat); + rNewBoxFormat.SetXObject(xCellStyle); + } + m_pTableAutoFormat_Impl = nullptr; + m_pTableAutoFormat = pTableAutoFormat; + m_pTableAutoFormat->SetXObject(this); + } + else + SAL_WARN("sw.uno", "setting style physical, but SwTableAutoFormat in document not found"); + } + else + SAL_WARN("sw.uno", "calling SetPhysical on a physical SwXTextTableStyle"); +} + +// XStyle +sal_Bool SAL_CALL SwXTextTableStyle::isUserDefined() +{ + SolarMutexGuard aGuard; + // only first style is not user defined + if (m_pDocShell->GetDoc()->GetTableStyles()[0].GetName() == m_pTableAutoFormat->GetName()) + return false; + + return true; +} + +sal_Bool SAL_CALL SwXTextTableStyle::isInUse() +{ + SolarMutexGuard aGuard; + if (!m_bPhysical) + return false; + + for (const SwTableFormat* pFormat : *m_pDocShell->GetDoc()->GetTableFrameFormats()) + { + if(pFormat->IsUsed()) + { + SwTable* pTable = SwTable::FindTable(pFormat); + if(pTable->GetTableStyleName() == m_pTableAutoFormat->GetName()) + return true; + } + } + return false; +} + +OUString SAL_CALL SwXTextTableStyle::getParentStyle() +{ + return OUString(); +} + +void SAL_CALL SwXTextTableStyle::setParentStyle(const OUString& /*aParentStyle*/) +{ } + +//XNamed +OUString SAL_CALL SwXTextTableStyle::getName() +{ + SolarMutexGuard aGuard; + OUString sProgName; + SwStyleNameMapper::FillProgName(m_pTableAutoFormat->GetName(), sProgName, SwGetPoolIdFromName::TabStyle); + return sProgName; +} + +void SAL_CALL SwXTextTableStyle::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + m_pTableAutoFormat->SetName(rName); +} + +//XPropertySet +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL SwXTextTableStyle::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRef(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_STYLE)->getPropertySetInfo()); + return xRef; +} + +void SAL_CALL SwXTextTableStyle::setPropertyValue(const OUString& /*rPropertyName*/, const css::uno::Any& /*aValue*/) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +css::uno::Any SAL_CALL SwXTextTableStyle::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + bool bIsRow = false; + + if (rPropertyName == UNO_NAME_TABLE_FIRST_ROW_END_COLUMN) + bIsRow = m_pTableAutoFormat->FirstRowEndColumnIsRow(); + else if (rPropertyName == UNO_NAME_TABLE_FIRST_ROW_START_COLUMN) + bIsRow = m_pTableAutoFormat->FirstRowStartColumnIsRow(); + else if (rPropertyName == UNO_NAME_TABLE_LAST_ROW_END_COLUMN) + bIsRow = m_pTableAutoFormat->LastRowEndColumnIsRow(); + else if (rPropertyName == UNO_NAME_TABLE_LAST_ROW_START_COLUMN) + bIsRow = m_pTableAutoFormat->LastRowStartColumnIsRow(); + else if (rPropertyName == UNO_NAME_DISPLAY_NAME) + return uno::Any(m_pTableAutoFormat->GetName()); + else + throw css::beans::UnknownPropertyException(rPropertyName); + + return uno::Any(bIsRow ? OUString("row") : OUString("column")); +} + +void SAL_CALL SwXTextTableStyle::addPropertyChangeListener( const OUString& /*aPropertyName*/, const css::uno::Reference< css::beans::XPropertyChangeListener >& /*xListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextTableStyle::removePropertyChangeListener( const OUString& /*aPropertyName*/, const css::uno::Reference< css::beans::XPropertyChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextTableStyle::addVetoableChangeListener( const OUString& /*PropertyName*/, const css::uno::Reference< css::beans::XVetoableChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextTableStyle::removeVetoableChangeListener( const OUString& /*PropertyName*/, const css::uno::Reference< css::beans::XVetoableChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +//XNameAccess +uno::Any SAL_CALL SwXTextTableStyle::getByName(const OUString& rName) +{ + SolarMutexGuard aGuard; + const CellStyleNameMap& rMap = GetCellStyleNameMap(); + CellStyleNameMap::const_iterator iter = rMap.find(rName); + if(iter == rMap.end()) + throw css::container::NoSuchElementException(); + + auto nIdx = (*iter).second; + return css::uno::Any(uno::Reference(cppu::getXWeak(m_aCellStyles[nIdx].get()))); +} + +css::uno::Sequence<OUString> SAL_CALL SwXTextTableStyle::getElementNames() +{ + return comphelper::mapKeysToSequence(GetCellStyleNameMap()); +} + +sal_Bool SAL_CALL SwXTextTableStyle::hasByName(const OUString& rName) +{ + const CellStyleNameMap& rMap = GetCellStyleNameMap(); + CellStyleNameMap::const_iterator iter = rMap.find(rName); + return iter != rMap.end(); +} + +//XNameContainer +void SAL_CALL SwXTextTableStyle::insertByName(const OUString& /*Name*/, const uno::Any& /*Element*/) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextTableStyle::replaceByName(const OUString& rName, const uno::Any& rElement) +{ + SolarMutexGuard aGuard; + const CellStyleNameMap& rMap = GetCellStyleNameMap(); + CellStyleNameMap::const_iterator iter = rMap.find(rName); + if(iter == rMap.end()) + throw container::NoSuchElementException(); + const sal_Int32 nCellStyle = iter->second; + + rtl::Reference<SwXTextCellStyle> xStyleToReplaceWith = dynamic_cast<SwXTextCellStyle*>(rElement.get<uno::Reference<style::XStyle>>().get()); + if (!xStyleToReplaceWith.is()) + throw lang::IllegalArgumentException(); + + // replace only with physical ... + if (!xStyleToReplaceWith->IsPhysical()) + throw lang::IllegalArgumentException(); + + const auto& rTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap(); + const sal_Int32 nBoxFormat = rTableTemplateMap[nCellStyle]; + + // move SwBoxAutoFormat to dest. SwTableAutoFormat + m_pTableAutoFormat->SetBoxFormat(*xStyleToReplaceWith->GetBoxFormat(), nBoxFormat); + // remove unassigned SwBoxAutoFormat, which is not anymore in use anyways + m_pDocShell->GetDoc()->GetCellStyles().RemoveBoxFormat(xStyleToReplaceWith->getName()); + // make SwXTextCellStyle use new, moved SwBoxAutoFormat + xStyleToReplaceWith->SetBoxFormat(&m_pTableAutoFormat->GetBoxFormat(nBoxFormat)); + m_pTableAutoFormat->GetBoxFormat(nBoxFormat).SetXObject(xStyleToReplaceWith); + // make this SwXTextTableStyle use new SwXTextCellStyle + m_aCellStyles[nCellStyle] = xStyleToReplaceWith; +} + +void SAL_CALL SwXTextTableStyle::removeByName(const OUString& /*Name*/) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +//XElementAccess +uno::Type SAL_CALL SAL_CALL SwXTextTableStyle::getElementType() +{ + return cppu::UnoType<style::XStyle>::get(); +} + +sal_Bool SAL_CALL SAL_CALL SwXTextTableStyle::hasElements() +{ + return true; +} + +//XServiceInfo +OUString SAL_CALL SwXTextTableStyle::getImplementationName() +{ + return {"SwXTextTableStyle"}; +} + +sal_Bool SAL_CALL SwXTextTableStyle::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL SwXTextTableStyle::getSupportedServiceNames() +{ + return {"com.sun.star.style.Style"}; +} + +// SwXTextCellStyle +SwXTextCellStyle::SwXTextCellStyle(SwDocShell* pDocShell, SwBoxAutoFormat* pBoxAutoFormat, OUString sParentStyle) : + m_pDocShell(pDocShell), + m_pBoxAutoFormat(pBoxAutoFormat), + m_sParentStyle(std::move(sParentStyle)), + m_bPhysical(true) +{ } + +SwXTextCellStyle::SwXTextCellStyle(SwDocShell* pDocShell, OUString sName) : + m_pDocShell(pDocShell), + m_pBoxAutoFormat_Impl(std::make_shared<SwBoxAutoFormat>()), + m_sName(std::move(sName)), + m_bPhysical(false) +{ + m_pBoxAutoFormat = m_pBoxAutoFormat_Impl.get(); +} + +SwBoxAutoFormat* SwXTextCellStyle::GetBoxFormat() +{ + return m_pBoxAutoFormat; +} + +void SwXTextCellStyle::SetBoxFormat(SwBoxAutoFormat* pBoxFormat) +{ + if (m_bPhysical) + m_pBoxAutoFormat = pBoxFormat; + else + SAL_INFO("sw.uno", "trying to call SwXTextCellStyle::SetBoxFormat on non physical style"); +} + +void SwXTextCellStyle::SetPhysical() +{ + if (!m_bPhysical) + { + SwBoxAutoFormat* pBoxAutoFormat = GetBoxAutoFormat(m_pDocShell, m_sName, &m_sParentStyle); + if (pBoxAutoFormat) + { + m_bPhysical = true; + m_pBoxAutoFormat_Impl = nullptr; + m_pBoxAutoFormat = pBoxAutoFormat; + m_pBoxAutoFormat->SetXObject(this); + } + else + SAL_WARN("sw.uno", "setting style physical, but SwBoxAutoFormat in document not found"); + } + else + SAL_WARN("sw.uno", "calling SetPhysical on a physical SwXTextCellStyle"); +} + +bool SwXTextCellStyle::IsPhysical() const +{ + return m_bPhysical; +} + +SwBoxAutoFormat* SwXTextCellStyle::GetBoxAutoFormat(SwDocShell* pDocShell, std::u16string_view sName, OUString* pParentName) +{ + if (sName.empty()) + return nullptr; + + SwBoxAutoFormat* pBoxAutoFormat = pDocShell->GetDoc()->GetCellStyles().GetBoxFormat(sName); + if (!pBoxAutoFormat) + { + sal_Int32 nTemplateIndex; + OUString sParentName; + std::u16string_view sCellSubName; + + size_t nSeparatorIndex = sName.rfind('.'); + if (nSeparatorIndex == std::u16string_view::npos) + return nullptr; + + sParentName = sName.substr(0, nSeparatorIndex); + sCellSubName = sName.substr(nSeparatorIndex+1); + nTemplateIndex = o3tl::toInt32(sCellSubName)-1; // -1 because cell styles names start from 1, but internally are indexed from 0 + if (0 > nTemplateIndex) + return nullptr; + + const auto& rTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap(); + if (rTableTemplateMap.size() <= o3tl::make_unsigned(nTemplateIndex)) + return nullptr; + + SwStyleNameMapper::FillUIName(sParentName, sParentName, SwGetPoolIdFromName::TabStyle); + SwTableAutoFormat* pTableAutoFormat = pDocShell->GetDoc()->GetTableStyles().FindAutoFormat(sParentName); + if (!pTableAutoFormat) + return nullptr; + + if (pParentName) + *pParentName = sParentName; + sal_uInt32 nBoxIndex = rTableTemplateMap[nTemplateIndex]; + pBoxAutoFormat = &pTableAutoFormat->GetBoxFormat(nBoxIndex); + } + + return pBoxAutoFormat; +} + +css::uno::Reference<css::style::XStyle> SwXTextCellStyle::CreateXTextCellStyle(SwDocShell* pDocShell, const OUString& sName) +{ + rtl::Reference<SwXTextCellStyle> xTextCellStyle; + + if (!sName.isEmpty()) // create a cell style for a physical box + { + OUString sParentName; + SwBoxAutoFormat* pBoxFormat = GetBoxAutoFormat(pDocShell, sName, &sParentName); + + // something went wrong but we don't want a crash + if (!pBoxFormat) + { + // return a default-dummy style to prevent crash + static SwBoxAutoFormat aDefaultBoxFormat; + pBoxFormat = &aDefaultBoxFormat; + } + + xTextCellStyle = pBoxFormat->GetXObject(); + if (!xTextCellStyle.is()) + { + xTextCellStyle.set(new SwXTextCellStyle(pDocShell, pBoxFormat, sParentName)); + pBoxFormat->SetXObject(xTextCellStyle); + } + } + else // create a non physical style + xTextCellStyle.set(new SwXTextCellStyle(pDocShell, sName)); + + return xTextCellStyle; +} + +// XStyle +sal_Bool SAL_CALL SwXTextCellStyle::isUserDefined() +{ + SolarMutexGuard aGuard; + // if this cell belong to first table style then its default style + if (&m_pDocShell->GetDoc()->GetTableStyles()[0] == m_pDocShell->GetDoc()->GetTableStyles().FindAutoFormat(m_sParentStyle)) + return false; + + return true; +} + +sal_Bool SAL_CALL SwXTextCellStyle::isInUse() +{ + SolarMutexGuard aGuard; + uno::Reference<style::XStyleFamiliesSupplier> xFamiliesSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY); + if (!xFamiliesSupplier.is()) + return false; + + uno::Reference<container::XNameAccess> xFamilies = xFamiliesSupplier->getStyleFamilies(); + if (!xFamilies.is()) + return false; + + uno::Reference<container::XNameAccess> xTableStyles; + xFamilies->getByName("TableStyles") >>= xTableStyles; + if (!xTableStyles.is()) + return false; + + uno::Reference<style::XStyle> xStyle; + xTableStyles->getByName(m_sParentStyle) >>= xStyle; + if (!xStyle.is()) + return false; + + return xStyle->isInUse(); +} + +OUString SAL_CALL SwXTextCellStyle::getParentStyle() +{ + // Do not return name of the parent (which is a table style) because the parent should be a cell style. + return OUString(); +} + +void SAL_CALL SwXTextCellStyle::setParentStyle(const OUString& /*sParentStyle*/) +{ + // Changing parent to one which is unaware of it will lead to a something unexpected. getName() rely on a parent. + SAL_INFO("sw.uno", "Changing SwXTextCellStyle parent"); +} + +//XNamed +OUString SAL_CALL SwXTextCellStyle::getName() +{ + SolarMutexGuard aGuard; + OUString sName; + + // if style is physical then we request a name from doc + if (m_bPhysical) + { + SwTableAutoFormat* pTableFormat = m_pDocShell->GetDoc()->GetTableStyles().FindAutoFormat(m_sParentStyle); + if (!pTableFormat) + { + // if auto format is not found as a child of table formats, look in SwDoc cellstyles + sName = m_pDocShell->GetDoc()->GetCellStyles().GetBoxFormatName(*m_pBoxAutoFormat); + } + else + { + OUString sParentStyle; + SwStyleNameMapper::FillProgName(m_sParentStyle, sParentStyle, SwGetPoolIdFromName::TabStyle); + sName = sParentStyle + pTableFormat->GetTableTemplateCellSubName(*m_pBoxAutoFormat); + } + } + else + sName = m_sName; + + return sName; +} + +void SAL_CALL SwXTextCellStyle::setName(const OUString& sName) +{ + SolarMutexGuard aGuard; + // if style is physical then we can not rename it. + if (!m_bPhysical) + m_sName = sName; + // change name if style is unassigned (name is not generated automatically) + m_pDocShell->GetDoc()->GetCellStyles().ChangeBoxFormatName(getName(), sName); +} + +//XPropertySet +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL SwXTextCellStyle::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRef(aSwMapProvider.GetPropertySet(PROPERTY_MAP_CELL_STYLE)->getPropertySetInfo()); + return xRef; +} + +void SAL_CALL SwXTextCellStyle::setPropertyValue(const OUString& rPropertyName, const css::uno::Any& aValue) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry *const pEntry = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CELL_STYLE)->getPropertyMap().getByName(rPropertyName); + if(pEntry) + { + switch(pEntry->nWID) + { + case RES_BACKGROUND: + { + SvxBrushItem rBrush = m_pBoxAutoFormat->GetBackground(); + rBrush.PutValue(aValue, 0); + m_pBoxAutoFormat->SetBackground(rBrush); + return; + } + case RES_BOX: + { + SvxBoxItem rBox = m_pBoxAutoFormat->GetBox(); + rBox.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetBox(rBox); + return; + } + case RES_VERT_ORIENT: + { + SwFormatVertOrient rVertOrient = m_pBoxAutoFormat->GetVerticalAlignment(); + rVertOrient.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetVerticalAlignment(rVertOrient); + return; + } + case RES_FRAMEDIR: + { + SvxFrameDirectionItem rDirItem = m_pBoxAutoFormat->GetTextOrientation(); + rDirItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetTextOrientation(rDirItem); + return; + } + case RES_BOXATR_FORMAT: + { + sal_uInt32 nKey; + if (aValue >>= nKey) + { + // FIXME: It's not working for old "automatic" currency formats, which are still in use by autotbl.fmt. + // Scenario: + // 1) Mark all styles present by default in autotbl.fmt as default. + // 2) convert all currencies present in autotbl.fmt before calling this code + const SvNumberformat* pNumFormat = m_pDocShell->GetDoc()->GetNumberFormatter()->GetEntry(nKey); + if (pNumFormat) + m_pBoxAutoFormat->SetValueFormat(pNumFormat->GetFormatstring(), pNumFormat->GetLanguage(), GetAppLanguage()); + } + return; + } + // Paragraph attributes + case RES_PARATR_ADJUST: + { + SvxAdjustItem rAdjustItem = m_pBoxAutoFormat->GetAdjust(); + rAdjustItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetAdjust(rAdjustItem); + return; + } + case RES_CHRATR_COLOR: + { + SvxColorItem rColorItem = m_pBoxAutoFormat->GetColor(); + rColorItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetColor(rColorItem); + return; + } + case RES_CHRATR_SHADOWED: + { + SvxShadowedItem rShadowedItem = m_pBoxAutoFormat->GetShadowed(); + bool bValue = false; aValue >>= bValue; + rShadowedItem.SetValue(bValue); + m_pBoxAutoFormat->SetShadowed(rShadowedItem); + return; + } + case RES_CHRATR_CONTOUR: + { + SvxContourItem rContourItem = m_pBoxAutoFormat->GetContour(); + bool bValue = false; aValue >>= bValue; + rContourItem.SetValue(bValue); + m_pBoxAutoFormat->SetContour(rContourItem); + return; + } + case RES_CHRATR_CROSSEDOUT: + { + SvxCrossedOutItem rCrossedOutItem = m_pBoxAutoFormat->GetCrossedOut(); + rCrossedOutItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCrossedOut(rCrossedOutItem); + return; + } + case RES_CHRATR_UNDERLINE: + { + SvxUnderlineItem rUnderlineItem = m_pBoxAutoFormat->GetUnderline(); + rUnderlineItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetUnderline(rUnderlineItem); + return; + } + case RES_CHRATR_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetHeight(); + rFontHeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetHeight(rFontHeightItem); + return; + } + case RES_CHRATR_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetWeight(); + rWeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetWeight(rWeightItem); + return; + } + case RES_CHRATR_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetPosture(); + rPostureItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetPosture(rPostureItem); + return; + } + case RES_CHRATR_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetFont(); + rFontItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetFont(rFontItem); + return; + } + case RES_CHRATR_CJK_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCJKHeight(); + rFontHeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKHeight(rFontHeightItem); + return; + } + case RES_CHRATR_CJK_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetCJKWeight(); + rWeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKWeight(rWeightItem); + return; + } + case RES_CHRATR_CJK_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetCJKPosture(); + rPostureItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKPosture(rPostureItem); + return; + } + case RES_CHRATR_CJK_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetCJKFont(); + rFontItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKFont(rFontItem); + return; + } + case RES_CHRATR_CTL_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCTLHeight(); + rFontHeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLHeight(rFontHeightItem); + return; + } + case RES_CHRATR_CTL_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetCTLWeight(); + rWeightItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLWeight(rWeightItem); + return; + } + case RES_CHRATR_CTL_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetCTLPosture(); + rPostureItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLPosture(rPostureItem); + return; + } + case RES_CHRATR_CTL_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetCTLFont(); + rFontItem.PutValue(aValue, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLFont(rFontItem); + return; + } + default: + SAL_WARN("sw.uno", "SwXTextCellStyle unknown nWID"); + throw css::uno::RuntimeException(); + } + } + + throw css::beans::UnknownPropertyException(rPropertyName); +} + +css::uno::Any SAL_CALL SwXTextCellStyle::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + const SfxItemPropertyMapEntry *const pEntry = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CELL_STYLE)->getPropertyMap().getByName(rPropertyName); + if(pEntry) + { + switch(pEntry->nWID) + { + case RES_BACKGROUND: + { + const SvxBrushItem& rBrush = m_pBoxAutoFormat->GetBackground(); + rBrush.QueryValue(aRet); + return aRet; + } + case RES_BOX: + { + const SvxBoxItem& rBox = m_pBoxAutoFormat->GetBox(); + rBox.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_VERT_ORIENT: + { + const SwFormatVertOrient& rVertOrient = m_pBoxAutoFormat->GetVerticalAlignment(); + rVertOrient.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_FRAMEDIR: + { + const SvxFrameDirectionItem& rDirItem = m_pBoxAutoFormat->GetTextOrientation(); + rDirItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_BOXATR_FORMAT: + { + OUString sFormat; + LanguageType eLng, eSys; + m_pBoxAutoFormat->GetValueFormat(sFormat, eLng, eSys); + if(!sFormat.isEmpty()) + { + SvNumFormatType nType; bool bNew; sal_Int32 nCheckPos; + sal_uInt32 nKey = m_pDocShell->GetDoc()->GetNumberFormatter()->GetIndexPuttingAndConverting(sFormat, eLng, eSys, nType, bNew, nCheckPos); + aRet <<= nKey; + } + return aRet; + } + // Paragraph attributes + case RES_PARATR_ADJUST: + { + const SvxAdjustItem& rAdjustItem = m_pBoxAutoFormat->GetAdjust(); + rAdjustItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_COLOR: + { + const SvxColorItem& rColorItem = m_pBoxAutoFormat->GetColor(); + rColorItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_SHADOWED: + { + const SvxShadowedItem& rShadowedItem = m_pBoxAutoFormat->GetShadowed(); + aRet <<= rShadowedItem.GetValue(); + return aRet; + } + case RES_CHRATR_CONTOUR: + { + const SvxContourItem& rContourItem = m_pBoxAutoFormat->GetContour(); + aRet <<= rContourItem.GetValue(); + return aRet; + } + case RES_CHRATR_CROSSEDOUT: + { + const SvxCrossedOutItem& rCrossedOutItem = m_pBoxAutoFormat->GetCrossedOut(); + rCrossedOutItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_UNDERLINE: + { + const SvxUnderlineItem& rUnderlineItem = m_pBoxAutoFormat->GetUnderline(); + rUnderlineItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_FONTSIZE: + { + const SvxFontHeightItem& rFontHeightItem = m_pBoxAutoFormat->GetHeight(); + rFontHeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_WEIGHT: + { + const SvxWeightItem& rWeightItem = m_pBoxAutoFormat->GetWeight(); + rWeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_POSTURE: + { + const SvxPostureItem& rPostureItem = m_pBoxAutoFormat->GetPosture(); + rPostureItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_FONT: + { + const SvxFontItem rFontItem = m_pBoxAutoFormat->GetFont(); + rFontItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CJK_FONTSIZE: + { + const SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCJKHeight(); + rFontHeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CJK_WEIGHT: + { + const SvxWeightItem& rWeightItem = m_pBoxAutoFormat->GetCJKWeight(); + rWeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CJK_POSTURE: + { + const SvxPostureItem& rPostureItem = m_pBoxAutoFormat->GetCJKPosture(); + rPostureItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CJK_FONT: + { + const SvxFontItem rFontItem = m_pBoxAutoFormat->GetCJKFont(); + rFontItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CTL_FONTSIZE: + { + const SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCTLHeight(); + rFontHeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CTL_WEIGHT: + { + const SvxWeightItem& rWeightItem = m_pBoxAutoFormat->GetCTLWeight(); + rWeightItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CTL_POSTURE: + { + const SvxPostureItem& rPostureItem = m_pBoxAutoFormat->GetCTLPosture(); + rPostureItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + case RES_CHRATR_CTL_FONT: + { + const SvxFontItem rFontItem = m_pBoxAutoFormat->GetCTLFont(); + rFontItem.QueryValue(aRet, pEntry->nMemberId); + return aRet; + } + default: + SAL_WARN("sw.uno", "SwXTextCellStyle unknown nWID"); + throw css::uno::RuntimeException(); + } + } + + throw css::beans::UnknownPropertyException(rPropertyName); +} + +void SAL_CALL SwXTextCellStyle::addPropertyChangeListener( const OUString& /*aPropertyName*/, const css::uno::Reference< css::beans::XPropertyChangeListener >& /*xListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextCellStyle::removePropertyChangeListener( const OUString& /*aPropertyName*/, const css::uno::Reference< css::beans::XPropertyChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextCellStyle::addVetoableChangeListener( const OUString& /*PropertyName*/, const css::uno::Reference< css::beans::XVetoableChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +void SAL_CALL SwXTextCellStyle::removeVetoableChangeListener( const OUString& /*PropertyName*/, const css::uno::Reference< css::beans::XVetoableChangeListener >& /*aListener*/ ) +{ + SAL_WARN("sw.uno", "not implemented"); +} + +//XPropertyState +css::beans::PropertyState SAL_CALL SwXTextCellStyle::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Sequence<OUString> aNames { rPropertyName }; + uno::Sequence<beans::PropertyState> aStates = getPropertyStates(aNames); + return aStates.getConstArray()[0]; +} + +css::uno::Sequence<css::beans::PropertyState> SAL_CALL SwXTextCellStyle::getPropertyStates(const css::uno::Sequence<OUString>& aPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + const SwBoxAutoFormat& rDefaultBoxFormat = SwTableAutoFormat::GetDefaultBoxFormat(); + const SfxItemPropertyMap& rMap = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CELL_STYLE)->getPropertyMap(); + const OUString* pNames = aPropertyNames.getConstArray(); + for(sal_Int32 i=0; i < aPropertyNames.getLength(); ++i) + { + const OUString sPropName = pNames[i]; + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(sPropName); + if(pEntry) + { + uno::Any aAny1, aAny2; + switch(pEntry->nWID) + { + case RES_BACKGROUND: + m_pBoxAutoFormat->GetBackground().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetBackground().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_BOX: + m_pBoxAutoFormat->GetBox().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetBox().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_VERT_ORIENT: + m_pBoxAutoFormat->GetVerticalAlignment().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetVerticalAlignment().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_FRAMEDIR: + m_pBoxAutoFormat->GetTextOrientation().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetTextOrientation().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_BOXATR_FORMAT: + { + OUString sFormat; + LanguageType eLng, eSys; + m_pBoxAutoFormat->GetValueFormat(sFormat, eLng, eSys); + pStates[i] = sFormat.isEmpty() ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + } + case RES_PARATR_ADJUST: + m_pBoxAutoFormat->GetAdjust().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetAdjust().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_COLOR: + m_pBoxAutoFormat->GetColor().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetColor().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_SHADOWED: + m_pBoxAutoFormat->GetShadowed().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetShadowed().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CONTOUR: + m_pBoxAutoFormat->GetContour().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetContour().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CROSSEDOUT: + m_pBoxAutoFormat->GetCrossedOut().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCrossedOut().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_UNDERLINE: + m_pBoxAutoFormat->GetUnderline().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetUnderline().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_FONTSIZE: + m_pBoxAutoFormat->GetHeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetHeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_WEIGHT: + m_pBoxAutoFormat->GetWeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetWeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_POSTURE: + m_pBoxAutoFormat->GetPosture().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetPosture().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_FONT: + m_pBoxAutoFormat->GetFont().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetFont().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CJK_FONTSIZE: + m_pBoxAutoFormat->GetCJKHeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCJKHeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CJK_WEIGHT: + m_pBoxAutoFormat->GetCJKWeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCJKWeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CJK_POSTURE: + m_pBoxAutoFormat->GetCJKPosture().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCJKPosture().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CJK_FONT: + m_pBoxAutoFormat->GetCJKFont().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCJKFont().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CTL_FONTSIZE: + m_pBoxAutoFormat->GetCTLHeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCTLHeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CTL_WEIGHT: + m_pBoxAutoFormat->GetCTLWeight().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCTLWeight().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CTL_POSTURE: + m_pBoxAutoFormat->GetCTLPosture().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCTLPosture().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + case RES_CHRATR_CTL_FONT: + m_pBoxAutoFormat->GetCTLFont().QueryValue(aAny1, pEntry->nMemberId); + rDefaultBoxFormat.GetCTLFont().QueryValue(aAny2, pEntry->nMemberId); + pStates[i] = aAny1 == aAny2 ? beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + break; + default: + // fallthrough to DIRECT_VALUE, to export properties for which getPropertyStates is not implemented + pStates[i] = beans::PropertyState_DIRECT_VALUE; + SAL_WARN("sw.uno", "SwXTextCellStyle getPropertyStates unknown nWID"); + } + } + else + { + SAL_WARN("sw.uno", "SwXTextCellStyle unknown property:" + sPropName); + throw css::beans::UnknownPropertyException(sPropName); + } + } + return aRet; +} + +void SAL_CALL SwXTextCellStyle::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + const SwBoxAutoFormat& rDefaultBoxFormat = SwTableAutoFormat::GetDefaultBoxFormat(); + const SfxItemPropertyMap& rMap = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CELL_STYLE)->getPropertyMap(); + const SfxItemPropertyMapEntry* pEntry = rMap.getByName(rPropertyName); + if(!pEntry) + return; + + uno::Any aAny; + switch(pEntry->nWID) + { + case RES_BACKGROUND: + { + SvxBrushItem rBrush = m_pBoxAutoFormat->GetBackground(); + rDefaultBoxFormat.GetBackground().QueryValue(aAny, pEntry->nMemberId); + rBrush.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetBackground(rBrush); + break; + } + case RES_BOX: + { + SvxBoxItem rBox = m_pBoxAutoFormat->GetBox(); + rDefaultBoxFormat.GetBox().QueryValue(aAny, pEntry->nMemberId); + rBox.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetBox(rBox); + break; + } + case RES_VERT_ORIENT: + { + SwFormatVertOrient rVertOrient = m_pBoxAutoFormat->GetVerticalAlignment(); + rDefaultBoxFormat.GetVerticalAlignment().QueryValue(aAny, pEntry->nMemberId); + rVertOrient.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetVerticalAlignment(rVertOrient); + break; + } + case RES_FRAMEDIR: + { + SvxFrameDirectionItem rFrameDirectionItem = m_pBoxAutoFormat->GetTextOrientation(); + rDefaultBoxFormat.GetTextOrientation().QueryValue(aAny, pEntry->nMemberId); + rFrameDirectionItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetTextOrientation(rFrameDirectionItem); + break; + } + case RES_BOXATR_FORMAT: + { + OUString sFormat; + LanguageType eLng, eSys; + rDefaultBoxFormat.GetValueFormat(sFormat, eLng, eSys); + m_pBoxAutoFormat->SetValueFormat(sFormat, eLng, eSys); + break; + } + case RES_PARATR_ADJUST: + { + SvxAdjustItem rAdjustItem = m_pBoxAutoFormat->GetAdjust(); + rDefaultBoxFormat.GetAdjust().QueryValue(aAny, pEntry->nMemberId); + rAdjustItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetAdjust(rAdjustItem); + break; + } + case RES_CHRATR_COLOR: + { + SvxColorItem rColorItem = m_pBoxAutoFormat->GetColor(); + rDefaultBoxFormat.GetColor().QueryValue(aAny, pEntry->nMemberId); + rColorItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetColor(rColorItem); + break; + } + case RES_CHRATR_SHADOWED: + { + SvxShadowedItem rShadowedItem = m_pBoxAutoFormat->GetShadowed(); + rDefaultBoxFormat.GetShadowed().QueryValue(aAny, pEntry->nMemberId); + rShadowedItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetShadowed(rShadowedItem); + break; + } + case RES_CHRATR_CONTOUR: + { + SvxContourItem rContourItem = m_pBoxAutoFormat->GetContour(); + rDefaultBoxFormat.GetContour().QueryValue(aAny, pEntry->nMemberId); + rContourItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetContour(rContourItem); + break; + } + case RES_CHRATR_CROSSEDOUT: + { + SvxCrossedOutItem rCrossedOutItem = m_pBoxAutoFormat->GetCrossedOut(); + rDefaultBoxFormat.GetCrossedOut().QueryValue(aAny, pEntry->nMemberId); + rCrossedOutItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCrossedOut(rCrossedOutItem); + break; + } + case RES_CHRATR_UNDERLINE: + { + SvxUnderlineItem rUnderlineItem = m_pBoxAutoFormat->GetUnderline(); + rDefaultBoxFormat.GetUnderline().QueryValue(aAny, pEntry->nMemberId); + rUnderlineItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetUnderline(rUnderlineItem); + break; + } + case RES_CHRATR_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetHeight(); + rDefaultBoxFormat.GetHeight().QueryValue(aAny, pEntry->nMemberId); + rFontHeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetHeight(rFontHeightItem); + break; + } + case RES_CHRATR_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetWeight(); + rDefaultBoxFormat.GetWeight().QueryValue(aAny, pEntry->nMemberId); + rWeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetWeight(rWeightItem); + break; + } + case RES_CHRATR_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetPosture(); + rDefaultBoxFormat.GetPosture().QueryValue(aAny, pEntry->nMemberId); + rPostureItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetPosture(rPostureItem); + break; + } + case RES_CHRATR_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetFont(); + rDefaultBoxFormat.GetFont().QueryValue(aAny, pEntry->nMemberId); + rFontItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetFont(rFontItem); + break; + } + case RES_CHRATR_CJK_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCJKHeight(); + rDefaultBoxFormat.GetCJKHeight().QueryValue(aAny, pEntry->nMemberId); + rFontHeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKHeight(rFontHeightItem); + break; + } + case RES_CHRATR_CJK_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetCJKWeight(); + rDefaultBoxFormat.GetCJKWeight().QueryValue(aAny, pEntry->nMemberId); + rWeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKWeight(rWeightItem); + break; + } + case RES_CHRATR_CJK_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetCJKPosture(); + rDefaultBoxFormat.GetCJKPosture().QueryValue(aAny, pEntry->nMemberId); + rPostureItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKPosture(rPostureItem); + break; + } + case RES_CHRATR_CJK_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetCJKFont(); + rDefaultBoxFormat.GetCJKFont().QueryValue(aAny, pEntry->nMemberId); + rFontItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCJKFont(rFontItem); + break; + } + case RES_CHRATR_CTL_FONTSIZE: + { + SvxFontHeightItem rFontHeightItem = m_pBoxAutoFormat->GetCTLHeight(); + rDefaultBoxFormat.GetCTLHeight().QueryValue(aAny, pEntry->nMemberId); + rFontHeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLHeight(rFontHeightItem); + break; + } + case RES_CHRATR_CTL_WEIGHT: + { + SvxWeightItem rWeightItem = m_pBoxAutoFormat->GetCTLWeight(); + rDefaultBoxFormat.GetCTLWeight().QueryValue(aAny, pEntry->nMemberId); + rWeightItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLWeight(rWeightItem); + break; + } + case RES_CHRATR_CTL_POSTURE: + { + SvxPostureItem rPostureItem = m_pBoxAutoFormat->GetCTLPosture(); + rDefaultBoxFormat.GetCTLPosture().QueryValue(aAny, pEntry->nMemberId); + rPostureItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLPosture(rPostureItem); + break; + } + case RES_CHRATR_CTL_FONT: + { + SvxFontItem rFontItem = m_pBoxAutoFormat->GetCTLFont(); + rDefaultBoxFormat.GetCTLFont().QueryValue(aAny, pEntry->nMemberId); + rFontItem.PutValue(aAny, pEntry->nMemberId); + m_pBoxAutoFormat->SetCTLFont(rFontItem); + break; + } + default: + SAL_WARN("sw.uno", "SwXTextCellStyle setPropertyToDefault unknown nWID"); + } +} + +css::uno::Any SAL_CALL SwXTextCellStyle::getPropertyDefault(const OUString& /*aPropertyName*/) +{ + SAL_WARN("sw.uno", "not implemented"); + uno::Any aRet; + return aRet; +} + +//XServiceInfo +OUString SAL_CALL SwXTextCellStyle::getImplementationName() +{ + return {"SwXTextCellStyle"}; +} + +sal_Bool SAL_CALL SwXTextCellStyle::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL SwXTextCellStyle::getSupportedServiceNames() +{ + return {"com.sun.star.style.Style"}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unotbl.cxx b/sw/source/core/unocore/unotbl.cxx new file mode 100644 index 0000000000..c2f92df7f1 --- /dev/null +++ b/sw/source/core/unocore/unotbl.cxx @@ -0,0 +1,4116 @@ +/* -*- 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 <tuple> +#include <utility> +#include <memory> +#include <vector> +#include <algorithm> +#include <limits> + +#include <comphelper/interfacecontainer4.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <tools/UnitConversion.hxx> +#include <editeng/memberids.h> +#include <float.h> +#include <swtypes.hxx> +#include <cmdid.h> +#include <unocoll.hxx> +#include <unomid.h> +#include <unomap.hxx> +#include <unotbl.hxx> +#include <section.hxx> +#include <unocrsr.hxx> +#include <hints.hxx> +#include <swtblfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentContentOperations.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentState.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <shellres.hxx> +#include <docary.hxx> +#include <ndole.hxx> +#include <ndtxt.hxx> +#include <frame.hxx> +#include <vcl/svapp.hxx> +#include <fmtfsize.hxx> +#include <tblafmt.hxx> +#include <tabcol.hxx> +#include <cellatr.hxx> +#include <fmtpdsc.hxx> +#include <pagedesc.hxx> +#include <viewsh.hxx> +#include <rootfrm.hxx> +#include <tabfrm.hxx> +#include <redline.hxx> +#include <unoport.hxx> +#include <unocrsrhelper.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/TableColumnSeparator.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/XTextSection.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <com/sun/star/table/TableBorder2.hpp> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/table/TableBorderDistances.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/chart/XChartDataChangeEventListener.hpp> +#include <com/sun/star/chart/ChartDataChangeEvent.hpp> +#include <com/sun/star/table/CellContentType.hpp> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unoparagraph.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <fmtornt.hxx> +#include <editeng/keepitem.hxx> +#include <fmtlsplt.hxx> +#include <swundo.hxx> +#include <SwStyleNameMapper.hxx> +#include <frmatr.hxx> +#include <sortopt.hxx> +#include <sal/log.hxx> +#include <editeng/frmdiritem.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <swtable.hxx> +#include <docsh.hxx> +#include <fesh.hxx> +#include <itabenum.hxx> +#include <frameformats.hxx> +#include <o3tl/string_view.hxx> + +using namespace ::com::sun::star; +using ::editeng::SvxBorderLine; + +namespace +{ + template<typename Tcoretype, typename Tunotype> + struct FindUnoInstanceHint final : SfxHint + { + FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {}; + const Tcoretype* const m_pCore; + mutable rtl::Reference<Tunotype> m_pResult; + }; + SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject) + { + if(!pFormat) + throw uno::RuntimeException("Lost connection to core objects", pObject); + return pFormat; + } + SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject) + { + if(pTable->IsTableComplex()) + throw uno::RuntimeException("Table too complex", pObject); + return pTable; + } + + chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource) + { + //TODO: find appropriate settings of the Event + chart::ChartDataChangeEvent event; + event.Source = xSource; + event.Type = chart::ChartDataChangeType_ALL; + event.StartColumn = 0; + event.EndColumn = 1; + event.StartRow = 0; + event.EndRow = 1; + return event; + } + + void lcl_SendChartEvent(std::unique_lock<std::mutex>& rGuard, + uno::Reference<uno::XInterface> const& xSource, + ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners) + { + if (rListeners.getLength(rGuard)) + rListeners.notifyEach(rGuard, + &chart::XChartDataChangeEventListener::chartDataChanged, + createChartEvent(xSource)); + } +} + +#define UNO_TABLE_COLUMN_SUM 10000 + + +static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine) +{ + rSvxLine.SetColor(Color(ColorTransparency, rLine.Color)); + + rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE, + o3tl::toTwips(rLine.OuterLineWidth, o3tl::Length::mm100), + o3tl::toTwips(rLine.InnerLineWidth, o3tl::Length::mm100), + o3tl::toTwips(rLine.LineDistance, o3tl::Length::mm100) ); + + return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0; +} + +/// @throws lang::IllegalArgumentException +/// @throws uno::RuntimeException +static void lcl_SetSpecialProperty(SwFrameFormat* pFormat, + const SfxItemPropertyMapEntry* pEntry, + const uno::Any& aValue) +{ + // special treatment for "non-items" + switch(pEntry->nWID) + { + case FN_TABLE_HEADLINE_REPEAT: + case FN_TABLE_HEADLINE_COUNT: + { + SwTable* pTable = SwTable::FindTable( pFormat ); + UnoActionContext aAction(pFormat->GetDoc()); + if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT) + { + pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 ); + } + else + { + sal_Int32 nRepeat = 0; + aValue >>= nRepeat; + if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 ) + pFormat->GetDoc()->SetRowsToRepeat( *pTable, o3tl::narrowing<sal_uInt16>(nRepeat) ); + } + } + break; + + case FN_TABLE_IS_RELATIVE_WIDTH: + case FN_TABLE_WIDTH: + case FN_TABLE_RELATIVE_WIDTH: + { + SwFormatFrameSize aSz( pFormat->GetFrameSize() ); + if(FN_TABLE_WIDTH == pEntry->nWID) + { + sal_Int32 nWidth = 0; + aValue >>= nWidth; + aSz.SetWidthPercent(0); + aSz.SetWidth ( o3tl::toTwips(nWidth, o3tl::Length::mm100) ); + } + else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID) + { + sal_Int16 nSet = 0; + aValue >>= nSet; + if(nSet && nSet <=100) + aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) ); + } + else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID) + { + if(!aValue.get<bool>()) + aSz.SetWidthPercent(0); + else + { + throw lang::IllegalArgumentException("relative width cannot be switched on with this property", nullptr, 0); + } + } + pFormat->GetDoc()->SetAttr(aSz, *pFormat); + } + break; + + case RES_PAGEDESC: + { + OUString sPageStyle; + aValue >>= sPageStyle; + const SwPageDesc* pDesc = nullptr; + if (!sPageStyle.isEmpty()) + { + SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc); + pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle); + } + SwFormatPageDesc aDesc( pDesc ); + pFormat->GetDoc()->SetAttr(aDesc, *pFormat); + } + break; + + default: + throw lang::IllegalArgumentException(); + } +} + +static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertyMapEntry* pEntry ) +{ + switch(pEntry->nWID) + { + case FN_TABLE_HEADLINE_REPEAT: + case FN_TABLE_HEADLINE_COUNT: + { + SwTable* pTable = SwTable::FindTable( pFormat ); + const sal_uInt16 nRepeat = pTable->GetRowsToRepeat(); + if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT) + return uno::Any(nRepeat > 0); + return uno::Any(sal_Int32(nRepeat)); + } + + case FN_TABLE_WIDTH: + case FN_TABLE_IS_RELATIVE_WIDTH: + case FN_TABLE_RELATIVE_WIDTH: + { + uno::Any aRet; + const SwFormatFrameSize& rSz = pFormat->GetFrameSize(); + if(FN_TABLE_WIDTH == pEntry->nWID) + rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS); + else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID) + rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH); + else + aRet <<= (0 != rSz.GetWidthPercent()); + return aRet; + } + + case RES_PAGEDESC: + { + const SfxItemSet& rSet = pFormat->GetAttrSet(); + if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet(RES_PAGEDESC, false)) + { + const SwPageDesc* pDsc = pItem->GetPageDesc(); + if(pDsc) + return uno::Any(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc )); + } + return uno::Any(OUString()); + } + + case RES_ANCHOR: + return uno::Any(text::TextContentAnchorType_AT_PARAGRAPH); + + case FN_UNO_ANCHOR_TYPES: + { + uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH}; + return uno::Any(aTypes); + } + + case FN_UNO_WRAP : + return uno::Any(text::WrapTextMode_NONE); + + case FN_PARAM_LINK_DISPLAY_NAME : + return uno::Any(pFormat->GetName()); + + case FN_UNO_REDLINE_NODE_START: + case FN_UNO_REDLINE_NODE_END: + { + SwTable* pTable = SwTable::FindTable( pFormat ); + SwNode* pTableNode = pTable->GetTableNode(); + if(FN_UNO_REDLINE_NODE_END == pEntry->nWID) + pTableNode = pTableNode->EndOfSectionNode(); + for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable()) + { + const SwNode& rRedPointNode = pRedline->GetPointNode(); + const SwNode& rRedMarkNode = pRedline->GetMarkNode(); + if(rRedPointNode == *pTableNode || rRedMarkNode == *pTableNode) + { + const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ? + rRedPointNode : rRedMarkNode; + bool bIsStart = &rStartOfRedline == pTableNode; + return uno::Any(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart)); + } + } + } + } + return uno::Any(); +} + +/** get position of a cell with a given name + * + * If everything was OK, the indices for column and row are changed (both >= 0). + * In case of errors, at least one of them is < 0. + * + * Also since the implementations of tables does not really have columns using + * this function is appropriate only for tables that are not complex (i.e. + * where IsTableComplex() returns false). + * + * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ... + * @param [IN,OUT] o_rColumn (0-based) + * @param [IN,OUT] o_rRow (0-based) + */ +//TODO: potential for throwing proper exceptions instead of having every caller to check for errors +void SwXTextTable::GetCellPosition(std::u16string_view aCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow) +{ + o_rColumn = o_rRow = -1; // default return values indicating failure + const sal_Int32 nLen = aCellName.size(); + if(!nLen) + { + SAL_WARN("sw.uno", "failed to get column or row index"); + return; + } + sal_Int32 nRowPos = 0; + while (nRowPos<nLen) + { + if (aCellName[nRowPos]>='0' && aCellName[nRowPos]<='9') + { + break; + } + ++nRowPos; + } + if (nRowPos<=0 || nRowPos>=nLen) + return; + + sal_Int32 nColIdx = 0; + for (sal_Int32 i = 0; i < nRowPos; ++i) + { + nColIdx *= 52; + if (i < nRowPos - 1) + ++nColIdx; + const sal_Unicode cChar = aCellName[i]; + if ('A' <= cChar && cChar <= 'Z') + nColIdx += cChar - 'A'; + else if ('a' <= cChar && cChar <= 'z') + nColIdx += 26 + cChar - 'a'; + else + { + nColIdx = -1; // sth failed + break; + } + } + + o_rColumn = nColIdx; + o_rRow = o3tl::toInt32(aCellName.substr(nRowPos)) - 1; // - 1 because indices ought to be 0 based +} + +/** compare position of two cells (check rows first) + * + * @note this function probably also make sense only + * for cell names of non-complex tables + * + * @param rCellName1 e.g. "A1" (non-empty string with valid cell name) + * @param rCellName2 e.g. "A1" (non-empty string with valid cell name) + * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2 + */ +int sw_CompareCellsByRowFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 ) +{ + sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; + SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 ); + SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 ); + + if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2)) + return -1; + else if (nCol1 == nCol2 && nRow1 == nRow2) + return 0; + else + return +1; +} + +/** compare position of two cells (check columns first) + * + * @note this function probably also make sense only + * for cell names of non-complex tables + * + * @param rCellName1 e.g. "A1" (non-empty string with valid cell name) + * @param rCellName2 e.g. "A1" (non-empty string with valid cell name) + * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2 + */ +int sw_CompareCellsByColFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 ) +{ + sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; + SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 ); + SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 ); + + if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2)) + return -1; + else if (nRow1 == nRow2 && nCol1 == nCol2) + return 0; + else + return +1; +} + +/** compare position of two cell ranges + * + * @note this function probably also make sense only + * for cell names of non-complex tables + * + * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name) + * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name) + * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name) + * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name) + * @param bCmpColsFirst if <true> position in columns will be compared first before rows + * + * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2 + */ +int sw_CompareCellRanges( + std::u16string_view aRange1StartCell, std::u16string_view aRange1EndCell, + std::u16string_view aRange2StartCell, std::u16string_view aRange2EndCell, + bool bCmpColsFirst ) +{ + int (*pCompareCells)( std::u16string_view, std::u16string_view ) = + bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst; + + int nCmpResStartCells = pCompareCells( aRange1StartCell, aRange2StartCell ); + if ((-1 == nCmpResStartCells ) || + ( 0 == nCmpResStartCells && + -1 == pCompareCells( aRange1EndCell, aRange2EndCell ) )) + return -1; + else if (0 == nCmpResStartCells && + 0 == pCompareCells( aRange1EndCell, aRange2EndCell )) + return 0; + else + return +1; +} + +/** get cell name at a specified coordinate + * + * @param nColumn column index (0-based) + * @param nRow row index (0-based) + * @return the cell name + */ +OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow ) +{ + if (nColumn < 0 || nRow < 0) + return OUString(); + OUString sCellName; + sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName ); + return sCellName + OUString::number( nRow + 1 ); +} + +/** Find the top left or bottom right corner box in given table. + Consider nested lines when finding the box. + + @param rTableLines the table + @param i_bTopLeft if true, find top left box, otherwise find bottom + right box + */ +static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft) +{ + const SwTableLines* pLines(&rTableLines); + while(true) + { + assert(!pLines->empty()); + if(pLines->empty()) + return nullptr; + const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back()); + assert(pLine); + const SwTableBoxes& rBoxes(pLine->GetTabBoxes()); + assert(rBoxes.size() != 0); + const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back(); + assert(pBox); + if (pBox->GetSttNd()) + return pBox; + pLines = &pBox->GetTabLines(); + } +} + +/** cleanup order in a range + * + * Sorts the input to a uniform format. I.e. for the four possible representation + * A1:C5, C5:A1, A5:C1, C1:A5 + * the result will be always A1:C5. + * + * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name) + * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name) + */ +void sw_NormalizeRange(OUString &rCell1, OUString &rCell2) +{ + sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; + SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 ); + SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 ); + if (nCol2 < nCol1 || nRow2 < nRow1) + { + rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) ); + rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) ); + } +} + +void SwRangeDescriptor::Normalize() +{ + if (nTop > nBottom) + std::swap(nBottom, nTop); + if (nLeft > nRight) + std::swap(nLeft, nRight); +} + +static rtl::Reference<SwXCell> lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow) +{ + const OUString sCellName = sw_GetCellName(nColumn, nRow); + SwTable* pTable = SwTable::FindTable(pFormat); + SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); + if(!pBox) + return nullptr; + return SwXCell::CreateXCell(pFormat, pBox, pTable); +} + +static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames) +{ + for(auto pLine : rLines) + { + for(auto pBox : pLine->GetTabBoxes()) + { + if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0) + rAllNames.push_back(pBox->GetName()); + SwTableLines& rBoxLines = pBox->GetTabLines(); + if(!rBoxLines.empty()) + lcl_InspectLines(rBoxLines, rAllNames); + } + } +} + +static bool lcl_FormatTable(SwFrameFormat const * pTableFormat) +{ + bool bHasFrames = false; + SwIterator<SwFrame,SwFormat> aIter( *pTableFormat ); + for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next()) + { + vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut(); + // mba: no TYPEINFO for SwTabFrame + if(!pFrame->IsTabFrame()) + continue; + DisableCallbackAction a(*pFrame->getRootFrame()); + SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame); + if(pTabFrame->isFrameAreaDefinitionValid()) + pTabFrame->InvalidatePos(); + pTabFrame->SetONECalcLowers(); + pTabFrame->Calc(pRenderContext); + bHasFrames = true; + } + return bHasFrames; +} + +static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand) +{ + if(bExpand) + { + if(!rCursor.HasMark()) + rCursor.SetMark(); + } + else if(rCursor.HasMark()) + rCursor.DeleteMark(); +} + +static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow) +{ + SwTabCols aCols; + aCols.SetLeftMin ( 0 ); + aCols.SetLeft ( 0 ); + aCols.SetRight ( UNO_TABLE_COLUMN_SUM ); + aCols.SetRightMax( UNO_TABLE_COLUMN_SUM ); + + pTable->GetTabCols( aCols, pBox, false, bRow ); + + const size_t nSepCount = aCols.Count(); + uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount); + text::TableColumnSeparator* pArray = aColSeq.getArray(); + bool bError = false; + for(size_t i = 0; i < nSepCount; ++i) + { + pArray[i].Position = static_cast< sal_Int16 >(aCols[i]); + pArray[i].IsVisible = !aCols.IsHidden(i); + if(!bRow && !pArray[i].IsVisible) + { + bError = true; + break; + } + } + if(!bError) + rRet <<= aColSeq; + +} + +static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc) +{ + SwTabCols aOldCols; + + aOldCols.SetLeftMin ( 0 ); + aOldCols.SetLeft ( 0 ); + aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM ); + aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM ); + + pTable->GetTabCols( aOldCols, pBox, false, bRow ); + const size_t nOldCount = aOldCols.Count(); + // there is no use in setting tab cols if there is only one column + if( !nOldCount ) + return; + + auto pSepSeq = + o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal); + if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount) + return; + SwTabCols aCols(aOldCols); + const text::TableColumnSeparator* pArray = pSepSeq->getConstArray(); + tools::Long nLastValue = 0; + //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft(); + for(size_t i = 0; i < nOldCount; ++i) + { + aCols[i] = pArray[i].Position; + if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) || + (!bRow && aCols.IsHidden(i)) || + aCols[i] < nLastValue || + UNO_TABLE_COLUMN_SUM < aCols[i] ) + return; // probably this should assert() + nLastValue = aCols[i]; + } + pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow ); +} + +/* non UNO function call to set string in SwXCell */ +void sw_setString( SwXCell &rCell, const OUString &rText, + bool bKeepNumberFormat = false ) +{ + if(rCell.IsValid()) + { + SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat(); + pBoxFormat->LockModify(); + pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA ); + pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE ); + if (!bKeepNumberFormat) + pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) ); + pBoxFormat->UnlockModify(); + } + rCell.SwXText::setString(rText); +} + + +/* non UNO function call to set value in SwXCell */ +void sw_setValue( SwXCell &rCell, double nVal ) +{ + if(!rCell.IsValid()) + return; + // first this text (maybe) needs to be deleted + SwNodeOffset nNdPos = rCell.m_pBox->IsValidNumTextNd(); + if(NODE_OFFSET_MAX != nNdPos) + sw_setString( rCell, OUString(), true ); // true == keep number format + SwDoc* pDoc = rCell.GetDoc(); + UnoActionContext aAction(pDoc); + SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat(); + SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aSet(pDoc->GetAttrPool()); + + //!! do we need to set a new number format? Yes, if + // - there is no current number format + // - the current number format is not a number format according to the number formatter, but rather a text format + const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT); + if(!pNumFormat + || pDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue())) + { + aSet.Put(SwTableBoxNumFormat(0)); + } + + SwTableBoxValue aVal(nVal); + aSet.Put(aVal); + pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet ); + // update table + pDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(rCell.GetFrameFormat())); +} + + +SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) : + SwXText(pTableFormat->GetDoc(), CursorType::TableText), + m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)), + m_pBox(pBx), + m_pStartNode(nullptr), + m_pTableFormat(pTableFormat), + m_nFndPos(nPos) +{ + StartListening(pTableFormat->GetNotifier()); +} + +SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) : + SwXText(pTableFormat->GetDoc(), CursorType::TableText), + m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)), + m_pBox(nullptr), + m_pStartNode(&rStartNode), + m_pTableFormat(pTableFormat), + m_nFndPos(NOTFOUND) +{ + StartListening(pTableFormat->GetNotifier()); +} + +SwXCell::~SwXCell() +{ + SolarMutexGuard aGuard; + EndListeningAll(); +} + +uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( ) +{ + return comphelper::concatSequences( + SwXCellBaseClass::getTypes(), + SwXText::getTypes() + ); +} + +uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +void SAL_CALL SwXCell::acquire( ) noexcept +{ + SwXCellBaseClass::acquire(); +} + +void SAL_CALL SwXCell::release( ) noexcept +{ + SolarMutexGuard aGuard; + + SwXCellBaseClass::release(); +} + +uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType ) +{ + uno::Any aRet = SwXText::queryInterface(aType); + if(aRet.getValueType() == cppu::UnoType<void>::get()) + aRet = SwXCellBaseClass::queryInterface(aType); + return aRet; +} + +const SwStartNode *SwXCell::GetStartNode() const +{ + const SwStartNode* pSttNd = nullptr; + + if( m_pStartNode || IsValid() ) + pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); + + return pSttNd; +} + +bool SwXCell::IsValid() const +{ + // FIXME: this is now a const method, to make SwXText::IsValid invisible + // but the const_cast here are still ridiculous. TODO: find a better way. + SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr; + if(!pTableFormat) + { + const_cast<SwXCell*>(this)->m_pBox = nullptr; + } + else + { + SwTable* pTable = SwTable::FindTable( pTableFormat ); + SwTableBox const*const pFoundBox = + const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox); + if (!pFoundBox) + { + const_cast<SwXCell*>(this)->m_pBox = nullptr; + } + } + return nullptr != m_pBox; +} + +OUString SwXCell::getFormula() +{ + SolarMutexGuard aGuard; + if(!IsValid()) + return OUString(); + SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() ); + SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); + aFormula.PtrToBoxNm( pTable ); + return aFormula.GetFormula(); +} + +///@see sw_setValue (TODO: seems to be copy and paste programming here) +void SwXCell::setFormula(const OUString& rFormula) +{ + SolarMutexGuard aGuard; + if(!IsValid()) + return; + // first this text (maybe) needs to be deleted + SwNodeOffset nNdPos = m_pBox->IsValidNumTextNd(); + if(SwNodeOffset(USHRT_MAX) == nNdPos) + sw_setString( *this, OUString(), true ); + OUString sFormula(comphelper::string::stripStart(rFormula, ' ')); + if( !sFormula.isEmpty() && '=' == sFormula[0] ) + sFormula = sFormula.copy( 1 ); + SwTableBoxFormula aFormula( sFormula ); + SwDoc* pMyDoc = GetDoc(); + UnoActionContext aAction(pMyDoc); + SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA> aSet(pMyDoc->GetAttrPool()); + SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat(); + const SwTableBoxNumFormat* pNumFormat = + pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT); + if(!pNumFormat + || pMyDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue())) + { + aSet.Put(SwTableBoxNumFormat(0)); + } + aSet.Put(aFormula); + GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet ); + // update table + pMyDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(GetFrameFormat())); +} + +double SwXCell::getValue() +{ + SolarMutexGuard aGuard; + // #i112652# a table cell may contain NaN as a value, do not filter that + if(IsValid() && !getString().isEmpty()) + return m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue(); + return std::numeric_limits<double>::quiet_NaN(); +} + +void SwXCell::setValue(double rValue) +{ + SolarMutexGuard aGuard; + sw_setValue( *this, rValue ); +} + +table::CellContentType SwXCell::getType() +{ + SolarMutexGuard aGuard; + + table::CellContentType nRes = table::CellContentType_EMPTY; + sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox(); + switch (nNdPos) + { + case 0 : nRes = table::CellContentType_TEXT; break; + case USHRT_MAX : nRes = table::CellContentType_EMPTY; break; + case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break; + case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break; + default : + OSL_FAIL( "unexpected case" ); + } + return nRes; +} + +void SwXCell::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + sw_setString( *this, aString ); +} + +sal_Int32 SwXCell::getError() +{ + SolarMutexGuard aGuard; + OUString sContent = getString(); + return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error); +} + +rtl::Reference< SwXTextCursor > SwXCell::createXTextCursor() +{ + if(!m_pStartNode && !IsValid()) + throw uno::RuntimeException(); + const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); + SwPosition aPos(*pSttNd); + rtl::Reference<SwXTextCursor> const pXCursor = + new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos); + auto& rUnoCursor(pXCursor->GetCursor()); + rUnoCursor.Move(fnMoveForward, GoInNode); + return pXCursor; +} + +rtl::Reference<SwXTextCursor> SwXCell::createXTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition) +{ + SwUnoInternalPaM aPam(*GetDoc()); + if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition)) + throw uno::RuntimeException(); + const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); + // skip sections + SwStartNode* p1 = aPam.GetPointNode().StartOfSectionNode(); + while(p1->IsSectionNode()) + p1 = p1->StartOfSectionNode(); + if( p1 != pSttNd ) + return nullptr; + return new SwXTextCursor(*GetDoc(), this, CursorType::TableText, + *aPam.GetPoint(), aPam.GetMark()); +} + +uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + if(!IsValid()) + return; + // Hack to support hidden property to transfer textDirection + if(rPropertyName == "FRMDirection") + { + SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR); + aItem.PutValue(aValue, 0); + m_pBox->GetFrameFormat()->SetFormatAttr(aItem); + } + else if(rPropertyName == "TableRedlineParams") + { + // Get the table row properties + uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >(); + comphelper::SequenceAsHashMap aPropMap(tableCellProperties); + OUString sRedlineType; + if(!(aPropMap.getValue("RedlineType") >>= sRedlineType)) + throw beans::UnknownPropertyException("No redline type property: ", getXWeak()); + + // Create a 'Table Cell Redline' object + SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties); + + + } + else if (rPropertyName == "VerticalMerge") + { + //Hack to allow clearing of numbering from the paragraphs in the merged cells. + SwNodeIndex aIdx(*GetStartNode(), 1); + const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode(); + while (&aIdx.GetNode() != pEndNd) + { + SwTextNode* pNd = aIdx.GetNode().GetTextNode(); + if (pNd) + pNd->SetCountedInList(false); + ++aIdx; + } + } + else + { + auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); + if ( !pEntry ) + { + // not a table property: ignore it, if it is a paragraph/character property + const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH); + pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName); + + if ( pEntry ) + return; + } + + if(!pEntry) + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN) + { + SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat(); + SwAttrSet aSet(pBoxFormat->GetAttrSet()); + m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet); + pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat); + } + else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get())) + m_pBox->setRowSpan(aValue.get<sal_Int32>()); + } +} + +uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + if(!IsValid()) + return uno::Any(); + auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); + if(!pEntry) + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + switch(pEntry->nWID) + { + case FN_UNO_CELL_ROW_SPAN: + return uno::Any(m_pBox->getRowSpan()); + case FN_UNO_TEXT_SECTION: + { + SwFrameFormat* pTableFormat = GetFrameFormat(); + SwTable* pTable = SwTable::FindTable(pTableFormat); + SwTableNode* pTableNode = pTable->GetTableNode(); + SwSectionNode* pSectionNode = pTableNode->FindSectionNode(); + if(!pSectionNode) + return uno::Any(); + SwSection& rSect = pSectionNode->GetSection(); + return uno::Any(SwXTextSections::GetObject(*rSect.GetFormat())); + } + break; + case FN_UNO_CELL_NAME: + return uno::Any(m_pBox->GetName()); + case FN_UNO_REDLINE_NODE_START: + case FN_UNO_REDLINE_NODE_END: + { + //redline can only be returned if it's a living object + return SwXText::getPropertyValue(rPropertyName); + } + break; + case FN_UNO_PARENT_TEXT: + { + if (!m_xParentText.is()) + { + const SwStartNode* pSttNd = m_pBox->GetSttNd(); + if (!pSttNd) + return uno::Any(); + + const SwTableNode* pTableNode = pSttNd->FindTableNode(); + if (!pTableNode) + return uno::Any(); + + SwPosition aPos(*pTableNode); + SwDoc& rDoc = aPos.GetDoc(); + m_xParentText = sw::CreateParentXText(rDoc, aPos); + } + + return uno::Any(m_xParentText); + } + break; + default: + { + const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet(); + uno::Any aResult; + m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult); + return aResult; + } + } +} + +void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +uno::Reference<container::XEnumeration> SwXCell::createEnumeration() +{ + SolarMutexGuard aGuard; + if(!IsValid()) + return uno::Reference<container::XEnumeration>(); + const SwStartNode* pSttNd = m_pBox->GetSttNd(); + SwPosition aPos(*pSttNd); + auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); + pUnoCursor->Move(fnMoveForward, GoInNode); + // remember table and start node for later travelling + // (used in export of tables in tables) + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::TableText, m_pBox); +} + +uno::Type SAL_CALL SwXCell::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SwXCell::hasElements() +{ + return true; +} + +void SwXCell::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pTableFormat = nullptr; + } + else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint)) + { + if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox()) + pFindHint->m_pResult = this; + } +} + +rtl::Reference<SwXCell> SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable ) +{ + if(!pTableFormat || !pBox) + return nullptr; + if(!pTable) + pTable = SwTable::FindTable(pTableFormat); + SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find(pBox); + if(it == pTable->GetTabSortBoxes().end()) + return nullptr; + size_t const nPos = it - pTable->GetTabSortBoxes().begin(); + FindUnoInstanceHint<SwTableBox, SwXCell> aHint{pBox}; + pTableFormat->GetNotifier().Broadcast(aHint); + return aHint.m_pResult ? aHint.m_pResult.get() : new SwXCell(pTableFormat, pBox, nPos); +} + +/** search if a box exists in a table + * + * @param pTable the table to search in + * @param pBox2 box model to find + * @return the box if existent in pTable, 0 (!!!) if not found + */ +SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2) +{ + // check if nFndPos happens to point to the right table box + if( m_nFndPos < pTable->GetTabSortBoxes().size() && + pBox2 == pTable->GetTabSortBoxes()[ m_nFndPos ] ) + return pBox2; + + // if not, seek the entry (and return, if successful) + SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find( pBox2 ); + if( it != pTable->GetTabSortBoxes().end() ) + { + m_nFndPos = it - pTable->GetTabSortBoxes().begin(); + return pBox2; + } + + // box not found: reset nFndPos pointer + m_nFndPos = NOTFOUND; + return nullptr; +} + +double SwXCell::GetForcedNumericalValue() const +{ + if(table::CellContentType_TEXT != const_cast<SwXCell*>(this)->getType()) + return getValue(); + // now we'll try to get a useful numerical value + // from the text in the cell... + sal_uInt32 nFIndex; + SvNumberFormatter* pNumFormatter(const_cast<SvNumberFormatter*>(GetDoc()->GetNumberFormatter())); + // look for SwTableBoxNumFormat value in parents as well + auto pBoxFormat(GetTableBox()->GetFrameFormat()); + const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT); + + if (pNumFormat) + { + // please note that the language of the numberformat + // is implicitly coded into the below value as well + nFIndex = pNumFormat->GetValue(); + + // since the current value indicates a text format but the call + // to 'IsNumberFormat' below won't work for text formats + // we need to get rid of the part that indicates the text format. + // According to ER this can be done like this: + nFIndex -= (nFIndex % SV_COUNTRY_LANGUAGE_OFFSET); + } + else + { + // system language is probably not the best possible choice + // but since we have to guess anyway (because the language of at + // the text is NOT the one used for the number format!) + // it is at least conform to what is used in + // SwTableShell::Execute when + // SID_ATTR_NUMBERFORMAT_VALUE is set... + LanguageType eLang = LANGUAGE_SYSTEM; + nFIndex = pNumFormatter->GetStandardIndex( eLang ); + } + double fTmp; + if (!const_cast<SwDoc*>(GetDoc())->IsNumberFormat(const_cast<SwXCell*>(this)->getString(), nFIndex, fTmp)) + return std::numeric_limits<double>::quiet_NaN(); + return fTmp; +} + +uno::Any SwXCell::GetAny() const +{ + if(!m_pBox) + throw uno::RuntimeException(); + // check if table box value item is set + auto pBoxFormat(m_pBox->GetFrameFormat()); + const bool bIsNum = pBoxFormat->GetItemState(RES_BOXATR_VALUE, false) == SfxItemState::SET; + return bIsNum ? uno::Any(getValue()) : uno::Any(const_cast<SwXCell*>(this)->getString()); +} + +OUString SwXCell::getImplementationName() + { return "SwXCell"; } + +sal_Bool SwXCell::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence< OUString > SwXCell::getSupportedServiceNames() + { return {"com.sun.star.text.CellProperties"}; } + +OUString SwXTextTableRow::getImplementationName() + { return "SwXTextTableRow"; } + +sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames() + { return {"com.sun.star.text.TextTableRow"}; } + + +SwXTextTableRow::SwXTextTableRow(SwFrameFormat* pFormat, SwTableLine* pLn) : + m_pFormat(pFormat), + m_pLine(pLn), + m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_ROW)) +{ + StartListening(m_pFormat->GetNotifier()); +} + +SwXTextTableRow::~SwXTextTableRow() +{ + SolarMutexGuard aGuard; + EndListeningAll(); +} + +uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine); + if(!pLn) + return; + + // Check for a specific property + if ( rPropertyName == "TableRedlineParams" ) + { + // Get the table row properties + uno::Sequence< beans::PropertyValue > tableRowProperties = aValue.get< uno::Sequence< beans::PropertyValue > >(); + comphelper::SequenceAsHashMap aPropMap( tableRowProperties ); + OUString sRedlineType; + if( !(aPropMap.getValue("RedlineType") >>= sRedlineType) ) + { + throw beans::UnknownPropertyException("No redline type property: ", getXWeak() ); + } + + // Create a 'Table Row Redline' object + SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties); + + } + else + { + const SfxItemPropertyMapEntry* pEntry = + m_pPropSet->getPropertyMap().getByName(rPropertyName); + SwDoc* pDoc = pFormat->GetDoc(); + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + + switch(pEntry->nWID) + { + case FN_UNO_ROW_HEIGHT: + case FN_UNO_ROW_AUTO_HEIGHT: + { + SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize()); + if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID) + { + bool bSet = *o3tl::doAccess<bool>(aValue); + aFrameSize.SetHeightSizeType(bSet ? SwFrameSize::Variable : SwFrameSize::Fixed); + } + else + { + sal_Int32 nHeight = 0; + aValue >>= nHeight; + Size aSz(aFrameSize.GetSize()); + aSz.setHeight( o3tl::toTwips(nHeight, o3tl::Length::mm100) ); + aFrameSize.SetSize(aSz); + } + pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat()); + } + break; + + case FN_UNO_TABLE_COLUMN_SEPARATORS: + { + UnoActionContext aContext(pDoc); + SwTable* pTable2 = SwTable::FindTable( pFormat ); + lcl_SetTableSeparators(aValue, pTable2, m_pLine->GetTabBoxes()[0], true, pDoc); + } + break; + + default: + { + SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat(); + SwAttrSet aSet(pLnFormat->GetAttrSet()); + m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + pDoc->SetAttr(aSet, *pLnFormat); + } + } + } +} + +uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine); + if(pLn) + { + const SfxItemPropertyMapEntry* pEntry = + m_pPropSet->getPropertyMap().getByName(rPropertyName); + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + switch(pEntry->nWID) + { + case FN_UNO_ROW_HEIGHT: + case FN_UNO_ROW_AUTO_HEIGHT: + { + const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize(); + if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID) + { + aRet <<= SwFrameSize::Variable == rSize.GetHeightSizeType(); + } + else + aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height())); + } + break; + + case FN_UNO_TABLE_COLUMN_SEPARATORS: + { + lcl_GetTableSeparators(aRet, pTable, m_pLine->GetTabBoxes()[0], true); + } + break; + + default: + { + const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet(); + m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); + } + } + } + return aRet; +} + +void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableRow::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pFormat = nullptr; + } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint)) + { + if(!pFindHint->m_pCore && pFindHint->m_pCore == m_pLine) + pFindHint->m_pResult = this; + } +} + +SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine) +{ + for(const auto& pCurrentLine : pTable->GetTabLines()) + if(pCurrentLine == pLine) + return pCurrentLine; + return nullptr; +} + +// SwXTextTableCursor + +OUString SwXTextTableCursor::getImplementationName() + { return "SwXTextTableCursor"; } + +sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +void SwXTextTableCursor::release() noexcept +{ + SolarMutexGuard aGuard; + SwXTextTableCursor_Base::release(); +} + +const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); } +SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); } +const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); } +SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); } +const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; } +SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; } + +uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames() + { return {"com.sun.star.text.TextTableCursor"}; } + +SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox) + : m_pFrameFormat(pFrameFormat) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR)) +{ + StartListening(m_pFrameFormat->GetNotifier()); + SwDoc* pDoc = m_pFrameFormat->GetDoc(); + const SwStartNode* pSttNd = pBox->GetSttNd(); + SwPosition aPos(*pSttNd); + m_pUnoCursor = pDoc->CreateUnoCursor(aPos, true); + m_pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor); + rTableCursor.MakeBoxSels(); +} + +SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection) + : m_pFrameFormat(&rTableFormat) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR)) +{ + StartListening(m_pFrameFormat->GetNotifier()); + m_pUnoCursor = pTableSelection->GetDoc().CreateUnoCursor(*pTableSelection->GetPoint(), true); + if(pTableSelection->HasMark()) + { + m_pUnoCursor->SetMark(); + *m_pUnoCursor->GetMark() = *pTableSelection->GetMark(); + } + const SwSelBoxes& rBoxes = pTableSelection->GetSelectedBoxes(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor); + for(auto pBox : rBoxes) + rTableCursor.InsertBox(*pBox); + rTableCursor.MakeBoxSels(); +} + +OUString SwXTextTableCursor::getRangeName() +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor* pTableCursor = dynamic_cast<SwUnoTableCursor*>(&rUnoCursor); + //!! see also SwChartDataSequence::getSourceRangeRepresentation + if(!pTableCursor) + return OUString(); + pTableCursor->MakeBoxSels(); + const SwStartNode* pNode = pTableCursor->GetPoint()->GetNode().FindTableBoxStartNode(); + const SwTable* pTable = SwTable::FindTable(GetFrameFormat()); + const SwTableBox* pEndBox = pTable->GetTableBox(pNode->GetIndex()); + if(pTableCursor->HasMark()) + { + pNode = pTableCursor->GetMark()->GetNode().FindTableBoxStartNode(); + const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex()); + if(pEndBox != pStartBox) + { + // need to switch start and end? + if(*pTableCursor->GetPoint() < *pTableCursor->GetMark()) + std::swap(pStartBox, pEndBox); + return pStartBox->GetName() + ":" + pEndBox->GetName(); + } + } + return pEndBox->GetName(); +} + +sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + return rTableCursor.GotoTableBox(sCellName); +} + +sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + return rTableCursor.Left(Count); +} + +sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + return rTableCursor.Right(Count); +} + +sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + return rTableCursor.UpDown(true, Count, nullptr, 0, + *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()); +} + +sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + return rTableCursor.UpDown(false, Count, nullptr, 0, + *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()); +} + +void SwXTextTableCursor::gotoStart(sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + rTableCursor.MoveTable(GotoCurrTable, fnTableStart); +} + +void SwXTextTableCursor::gotoEnd(sal_Bool bExpand) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + lcl_CursorSelect(rTableCursor, bExpand); + rTableCursor.MoveTable(GotoCurrTable, fnTableEnd); +} + +sal_Bool SwXTextTableCursor::mergeRange() +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + { + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rTableCursor); + } + rTableCursor.MakeBoxSels(); + bool bResult; + { + UnoActionContext aContext(&rUnoCursor.GetDoc()); + bResult = TableMergeErr::Ok == rTableCursor.GetDoc().MergeTable(rTableCursor); + } + if(bResult) + { + size_t nCount = rTableCursor.GetSelectedBoxesCount(); + while (nCount--) + rTableCursor.DeleteBox(nCount); + } + rTableCursor.MakeBoxSels(); + return bResult; +} + +sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal) +{ + SolarMutexGuard aGuard; + if (Count <= 0) + throw uno::RuntimeException("Illegal first argument: needs to be > 0", getXWeak()); + SwUnoCursor& rUnoCursor = GetCursor(); + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + { + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rTableCursor); + } + rTableCursor.MakeBoxSels(); + bool bResult; + { + UnoActionContext aContext(&rUnoCursor.GetDoc()); + bResult = rTableCursor.GetDoc().SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count); + } + rTableCursor.MakeBoxSels(); + return bResult; +} + +uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak()); + if(pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak()); + { + auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode(); + const SwTableNode* pTableNode = pSttNode->FindTableNode(); + lcl_FormatTable(pTableNode->GetTable().GetFrameFormat()); + } + auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + rTableCursor.MakeBoxSels(); + SwDoc& rDoc = rUnoCursor.GetDoc(); + switch(pEntry->nWID) + { + case FN_UNO_TABLE_CELL_BACKGROUND: + { + std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + SwDoc::GetBoxAttr(rUnoCursor, aBrush); + aBrush->PutValue(aValue, pEntry->nMemberId); + rDoc.SetBoxAttr(rUnoCursor, *aBrush); + + } + break; + case RES_BOXATR_FORMAT: + { + SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT); + aNumberFormat.PutValue(aValue, 0); + rDoc.SetBoxAttr(rUnoCursor, aNumberFormat); + } + break; + case FN_UNO_PARA_STYLE: + SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor); + break; + default: + { + SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID); + SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), + aItemSet); + + if (!SwUnoCursorHelper::SetCursorPropertyValue( + *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet)) + { + m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet); + } + SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(), + aItemSet, SetAttrMode::DEFAULT, true); + } + } +} + +uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + SwUnoCursor& rUnoCursor = GetCursor(); + { + auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode(); + const SwTableNode* pTableNode = pSttNode->FindTableNode(); + lcl_FormatTable(pTableNode->GetTable().GetFrameFormat()); + } + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); + auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak()); + rTableCursor.MakeBoxSels(); + uno::Any aResult; + switch(pEntry->nWID) + { + case FN_UNO_TABLE_CELL_BACKGROUND: + { + std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + if (SwDoc::GetBoxAttr(rUnoCursor, aBrush)) + aBrush->QueryValue(aResult, pEntry->nMemberId); + } + break; + case RES_BOXATR_FORMAT: + // TODO: GetAttr for table selections in a Doc is missing + throw uno::RuntimeException("Unknown property: " + rPropertyName, getXWeak()); + break; + case FN_UNO_PARA_STYLE: + { + auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false)); + if(pFormat) + aResult <<= pFormat->GetName(); + } + break; + default: + { + SfxItemSetFixed + <RES_CHRATR_BEGIN, RES_FRMATR_END-1, + RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER> + aSet(rTableCursor.GetDoc().GetAttrPool()); + SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), aSet); + m_pPropSet->getPropertyValue(*pEntry, aSet, aResult); + } + } + return aResult; +} + +void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("not implemented", getXWeak()); }; + +void SwXTextTableCursor::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFrameFormat = nullptr; +} + + +// SwXTextTable =========================================================== + +namespace { + +class SwTableProperties_Impl +{ + SwUnoCursorHelper::SwAnyMapHelper m_aAnyMap; + +public: + SwTableProperties_Impl(); + + void SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& aVal); + bool GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny); + void AddItemToSet(SfxItemSet& rSet, std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory, + sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips = false); + void ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc); +}; + +} + +SwTableProperties_Impl::SwTableProperties_Impl() + { } + +void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal) + { + m_aAnyMap.SetValue(nWhichId, nMemberId, rVal); + } + +bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny ) + { + return m_aAnyMap.FillValue(nWhichId, nMemberId, rpAny); + } + +void SwTableProperties_Impl::AddItemToSet(SfxItemSet& rSet, + std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory, + sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips) +{ + std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny; + for(sal_uInt16 nMember : vMember) + { + const uno::Any* pAny = nullptr; + GetProperty(nWhich, nMember, pAny); + if(pAny) + vMemberAndAny.emplace_back(nMember, pAny); + } + if(!vMemberAndAny.empty()) + { + std::unique_ptr<SfxPoolItem> aItem(aItemFactory()); + for(const auto& aMemberAndAny : vMemberAndAny) + aItem->PutValue(*aMemberAndAny.second, aMemberAndAny.first | (bAddTwips ? CONVERT_TWIPS : 0) ); + rSet.Put(std::move(aItem)); + } +} +void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc) +{ + SfxItemSetFixed< + RES_FRM_SIZE, RES_BREAK, + RES_HORI_ORIENT, RES_HORI_ORIENT, + RES_BACKGROUND, RES_BACKGROUND, + RES_SHADOW, RES_SHADOW, + RES_KEEP, RES_KEEP, + RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT> + aSet(rDoc.GetAttrPool()); + const uno::Any* pRepHead; + const SwFrameFormat &rFrameFormat = *rTable.GetFrameFormat(); + if(GetProperty(FN_TABLE_HEADLINE_REPEAT, 0xff, pRepHead )) + { + bool bVal(pRepHead->get<bool>()); + const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER + } + + AddItemToSet(aSet, [&rFrameFormat]() { return rFrameFormat.makeBackgroundBrushItem(); }, RES_BACKGROUND, { + MID_BACK_COLOR, + MID_GRAPHIC_TRANSPARENT, + MID_GRAPHIC_POSITION, + MID_GRAPHIC, + MID_GRAPHIC_FILTER }); + + bool bPutBreak = true; + const uno::Any* pPage; + if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage)) + { + OUString sPageStyle = pPage->get<OUString>(); + if(!sPageStyle.isEmpty()) + { + SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc); + const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle); + if(pDesc) + { + SwFormatPageDesc aDesc(pDesc); + const uno::Any* pPgNo; + if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo)) + { + aDesc.SetNumOffset(pPgNo->get<sal_Int16>()); + } + aSet.Put(aDesc); + bPutBreak = false; + } + + } + } + + if(bPutBreak) + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetBreak().Clone()); }, RES_BREAK, {0}); + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetShadow().Clone()); }, RES_SHADOW, {0}, true); + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetKeep().Clone()); }, RES_KEEP, {0}); + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetHoriOrient().Clone()); }, RES_HORI_ORIENT, {MID_HORIORIENT_ORIENT}, true); + + const uno::Any* pSzRel(nullptr); + GetProperty(FN_TABLE_IS_RELATIVE_WIDTH, 0xff, pSzRel); + const uno::Any* pRelWidth(nullptr); + GetProperty(FN_TABLE_RELATIVE_WIDTH, 0xff, pRelWidth); + const uno::Any* pWidth(nullptr); + GetProperty(FN_TABLE_WIDTH, 0xff, pWidth); + + bool bPutSize = pWidth != nullptr; + SwFormatFrameSize aSz(SwFrameSize::Variable); + if(pWidth) + { + aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH); + bPutSize = true; + } + if(pSzRel && pSzRel->get<bool>() && pRelWidth) + { + aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS); + bPutSize = true; + } + if(bPutSize) + { + if(!aSz.GetWidth()) + aSz.SetWidth(MINLAY); + aSet.Put(aSz); + } + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetLRSpace().Clone()); }, RES_LR_SPACE, { + MID_L_MARGIN|CONVERT_TWIPS, + MID_R_MARGIN|CONVERT_TWIPS }); + AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetULSpace().Clone()); }, RES_UL_SPACE, { + MID_UP_MARGIN|CONVERT_TWIPS, + MID_LO_MARGIN|CONVERT_TWIPS }); + const::uno::Any* pSplit(nullptr); + if(GetProperty(RES_LAYOUT_SPLIT, 0, pSplit)) + { + SwFormatLayoutSplit aSp(pSplit->get<bool>()); + aSet.Put(aSp); + } + if(aSet.Count()) + { + rDoc.SetAttr(aSet, *rTable.GetFrameFormat()); + } +} + +class SwXTextTable::Impl + : public SvtListener +{ +private: + SwFrameFormat* m_pFrameFormat; + +public: + unotools::WeakReference<SwXTextTable> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners; + + const SfxItemPropertySet * m_pPropSet; + + css::uno::WeakReference<css::table::XTableRows> m_xRows; + css::uno::WeakReference<css::table::XTableColumns> m_xColumns; + + bool m_bFirstRowAsLabel; + bool m_bFirstColumnAsLabel; + + // Descriptor-interface + std::unique_ptr<SwTableProperties_Impl> m_pTableProps; + OUString m_sTableName; + unsigned short m_nRows; + unsigned short m_nColumns; + + explicit Impl(SwFrameFormat* const pFrameFormat) + : m_pFrameFormat(pFrameFormat) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE)) + , m_bFirstRowAsLabel(false) + , m_bFirstColumnAsLabel(false) + , m_pTableProps(pFrameFormat ? nullptr : new SwTableProperties_Impl) + , m_nRows(pFrameFormat ? 0 : 2) + , m_nColumns(pFrameFormat ? 0 : 2) + { + if(m_pFrameFormat) + StartListening(m_pFrameFormat->GetNotifier()); + } + + SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } + void SetFrameFormat(SwFrameFormat& rFrameFormat) + { + EndListeningAll(); + m_pFrameFormat = &rFrameFormat; + StartListening(m_pFrameFormat->GetNotifier()); + } + + bool IsDescriptor() const { return m_pTableProps != nullptr; } + + // note: lock mutex before calling this to avoid concurrent update + static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis) + { + sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount()); + sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount()); + if (!nRowCount || !nColCount) + { + throw uno::RuntimeException("Table too complex", rThis.getXWeak()); + } + return std::make_pair(nRowCount, nColCount); + } + + sal_uInt16 GetRowCount(); + sal_uInt16 GetColumnCount(); + + virtual void Notify(const SfxHint&) override; + +}; + +SwXTextTable::SwXTextTable() + : m_pImpl(new Impl(nullptr)) +{ +} + +SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat) + : m_pImpl(new Impl(&rFrameFormat)) +{ +} + +SwXTextTable::~SwXTextTable() +{ +} + +rtl::Reference<SwXTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat) +{ + rtl::Reference<SwXTextTable> xTable; + if(pFrameFormat) + xTable = dynamic_cast<SwXTextTable*>(pFrameFormat->GetXObject().get().get()); // cached? + if(xTable.is()) + return xTable; + xTable = pFrameFormat ? new SwXTextTable(*pFrameFormat) : new SwXTextTable(); + if(pFrameFormat) + pFrameFormat->SetXObject(xTable->getXWeak()); + // need a permanent Reference to initialize m_wThis + xTable->m_pImpl->m_wThis = xTable.get(); + return xTable; +} + +SwFrameFormat* SwXTextTable::GetFrameFormat() +{ + return m_pImpl->GetFrameFormat(); +} + +void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC) +{ + if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16) + throw uno::RuntimeException(); + m_pImpl->m_nRows = o3tl::narrowing<sal_uInt16>(nR); + m_pImpl->m_nColumns = o3tl::narrowing<sal_uInt16>(nC); +} + +uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows() +{ + SolarMutexGuard aGuard; + uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows); + if(xResult.is()) + return xResult; + if(SwFrameFormat* pFormat = GetFrameFormat()) + m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat); + if(!xResult.is()) + throw uno::RuntimeException(); + return xResult; +} + +uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns() +{ + SolarMutexGuard aGuard; + uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns); + if(xResult.is()) + return xResult; + if(SwFrameFormat* pFormat = GetFrameFormat()) + m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat); + if(!xResult.is()) + throw uno::RuntimeException(); + return xResult; +} + +uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = SwTable::FindTable(pFormat); + SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); + if(!pBox) + return nullptr; + return SwXCell::CreateXCell(pFormat, pBox); +} + +uno::Sequence<OUString> SwXTextTable::getCellNames() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat(GetFrameFormat()); + if(!pFormat) + return {}; + SwTable* pTable = SwTable::FindTable(pFormat); + // exists at the table and at all boxes + SwTableLines& rTableLines = pTable->GetTabLines(); + std::vector<OUString> aAllNames; + lcl_InspectLines(rTableLines, aAllNames); + return comphelper::containerToSequence(aAllNames); +} + +uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = SwTable::FindTable(pFormat); + SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); + if(!pBox || pBox->getRowSpan() == 0) + throw uno::RuntimeException(); + return new SwXTextTableCursor(pFormat, pBox); +} + +void SAL_CALL +SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange) +{ + SolarMutexGuard aGuard; + + // attach() must only be called once + if (!m_pImpl->IsDescriptor()) /* already attached ? */ + throw uno::RuntimeException("SwXTextTable: already attached to range.", getXWeak()); + + SwXTextRange* pRange(dynamic_cast<SwXTextRange*>(xTextRange.get())); + OTextCursorHelper* pCursor(dynamic_cast<OTextCursorHelper*>(xTextRange.get())); + SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr; + if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns) + throw lang::IllegalArgumentException(); + SwUnoInternalPaM aPam(*pDoc); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + { + UnoActionContext aCont(pDoc); + + pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); + const SwTable* pTable(nullptr); + if( 0 != aPam.Start()->GetContentIndex() ) + { + pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false); + } + //TODO: if it is the last paragraph than add another one! + if(aPam.HasMark()) + { + pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); + aPam.DeleteMark(); + } + + OUString tableName; + if (const::uno::Any* pName; + m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName)) + { + tableName = pName->get<OUString>(); + } + else if (!m_pImpl->m_sTableName.isEmpty()) + { + sal_uInt16 nIndex = 1; + tableName = m_pImpl->m_sTableName; + while (pDoc->FindTableFormatByName(tableName, true) && nIndex < USHRT_MAX) + tableName = m_pImpl->m_sTableName + OUString::number(nIndex++); + } + + pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ), + *aPam.GetPoint(), + m_pImpl->m_nRows, + m_pImpl->m_nColumns, + text::HoriOrientation::FULL, + nullptr, nullptr, false, true, + tableName); + if(pTable) + { + // here, the properties of the descriptor need to be analyzed + m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc); + SwFrameFormat* pTableFormat(pTable->GetFrameFormat()); + lcl_FormatTable(pTableFormat); + + m_pImpl->SetFrameFormat(*pTableFormat); + + m_pImpl->m_pTableProps.reset(); + } + pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } +} + +uno::Reference<text::XTextRange> SwXTextTable::getAnchor() +{ + SolarMutexGuard aGuard; + SwTableFormat *const pFormat = static_cast<SwTableFormat*>( + lcl_EnsureCoreConnected(GetFrameFormat(), this)); + return new SwXTextRange(*pFormat); +} + +void SwXTextTable::dispose() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = SwTable::FindTable(pFormat); + SwSelBoxes aSelBoxes; + for(auto& rBox : pTable->GetTabSortBoxes() ) + aSelBoxes.insert(rBox); + pFormat->GetDoc()->DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected); +} + +void SAL_CALL SwXTextTable::addEventListener( + const uno::Reference<lang::XEventListener> & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXTextTable::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat(GetFrameFormat()); + // sheet is unimportant + if(nColumn >= 0 && nRow >= 0 && pFormat) + { + auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow); + if(pXCell) + return pXCell; + } + throw lang::IndexOutOfBoundsException(); +} + +namespace { + +rtl::Reference<SwXCellRange> GetRangeByName( + SwFrameFormat* pFormat, SwTable const * pTable, + const OUString& rTLName, const OUString& rBRName, + SwRangeDescriptor const & rDesc) +{ + const SwTableBox* pTLBox = pTable->GetTableBox(rTLName); + if(!pTLBox) + return nullptr; + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to the upper-left cell of the range + auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true)); + pUnoCursor->Move(fnMoveForward, GoInNode); + pUnoCursor->SetRemainInSection(false); + const SwTableBox* pBRBox(pTable->GetTableBox(rBRName)); + if(!pBRBox) + return nullptr; + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() ); + pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + rCursor.MakeBoxSels(); + // pUnoCursor will be provided and will not be deleted + return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc); +} + +} // namespace + +uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat(GetFrameFormat()); + if(pFormat && + nLeft <= nRight && nTop <= nBottom && + nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 ) + { + SwTable* pTable = SwTable::FindTable(pFormat); + if(!pTable->IsTableComplex()) + { + SwRangeDescriptor aDesc; + aDesc.nTop = nTop; + aDesc.nBottom = nBottom; + aDesc.nLeft = nLeft; + aDesc.nRight = nRight; + const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop); + const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom); + // please note that according to the 'if' statement at the begin + // sTLName:sBRName already denotes the normalized range string + return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc); + } + } + throw lang::IndexOutOfBoundsException(); +} + +uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this); + sal_Int32 nPos = 0; + const OUString sTLName(sRange.getToken(0, ':', nPos)); + const OUString sBRName(sRange.getToken(0, ':', nPos)); + if(sTLName.isEmpty() || sBRName.isEmpty()) + throw uno::RuntimeException(); + SwRangeDescriptor aDesc; + aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1; + SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop ); + SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom ); + + // we should normalize the range now (e.g. A5:C1 will become A1:C5) + // since (depending on what is done later) it will be troublesome + // elsewhere when the cursor in the implementation does not + // point to the top-left and bottom-right cells + aDesc.Normalize(); + return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc); +} + +uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray() +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<sheet::XCellRangeData> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + return xAllRange->getDataArray(); +} + +void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray) +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<sheet::XCellRangeData> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + return xAllRange->setDataArray(rArray); +} + +uno::Sequence< uno::Sequence< double > > SwXTextTable::getData() +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + return xAllRange->getData(); +} + +void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData) +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + xAllRange->setData(rData); + // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not + std::unique_lock aGuard2(m_pImpl->m_Mutex); + lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners); +} + +uno::Sequence<OUString> SwXTextTable::getRowDescriptions() +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + return xAllRange->getRowDescriptions(); +} + +void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc) +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + xAllRange->setRowDescriptions(rRowDesc); +} + +uno::Sequence<OUString> SwXTextTable::getColumnDescriptions() +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + return xAllRange->getColumnDescriptions(); +} + +void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc) +{ + SolarMutexGuard aGuard; + std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); + uno::Reference<chart::XChartDataArray> const xAllRange( + getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), + uno::UNO_QUERY_THROW); + static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( + m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); + return xAllRange->setColumnDescriptions(rColumnDesc); +} + +void SAL_CALL SwXTextTable::addChartDataChangeEventListener( + const uno::Reference<chart::XChartDataChangeEventListener> & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_ChartListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXTextTable::removeChartDataChangeEventListener( + const uno::Reference<chart::XChartDataChangeEventListener> & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener); +} + +sal_Bool SwXTextTable::isNotANumber(double nNumber) +{ + // We use DBL_MIN because starcalc does (which uses it because chart + // wants it that way!) + return ( nNumber == DBL_MIN ); +} + +double SwXTextTable::getNotANumber() +{ + // We use DBL_MIN because starcalc does (which uses it because chart + // wants it that way!) + return DBL_MIN; +} + +uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor() +{ + SolarMutexGuard aGuard; + + return SwUnoCursorHelper::CreateSortDescriptor(true); +} + +void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor) +{ + SolarMutexGuard aGuard; + SwSortOptions aSortOpt; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!(pFormat && + SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))) + return; + + SwTable* pTable = SwTable::FindTable( pFormat ); + SwSelBoxes aBoxes; + const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes(); + for (size_t n = 0; n < rTBoxes.size(); ++n) + { + SwTableBox* pBox = rTBoxes[ n ]; + aBoxes.insert( pBox ); + } + UnoActionContext aContext( pFormat->GetDoc() ); + pFormat->GetDoc()->SortTable(aBoxes, aSortOpt); +} + +void SwXTextTable::autoFormat(const OUString& sAutoFormatName) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this); + SwTableAutoFormatTable aAutoFormatTable; + aAutoFormatTable.Load(); + for (size_t i = aAutoFormatTable.size(); i;) + if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() ) + { + SwSelBoxes aBoxes; + const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes(); + for (size_t n = 0; n < rTBoxes.size(); ++n) + { + SwTableBox* pBox = rTBoxes[ n ]; + aBoxes.insert( pBox ); + } + UnoActionContext aContext( pFormat->GetDoc() ); + pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] ); + break; + } +} + +uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!aValue.hasValue()) + throw lang::IllegalArgumentException(); + const SfxItemPropertyMapEntry* pEntry = + m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); + if( !pEntry ) + throw lang::IllegalArgumentException(); + if(pFormat) + { + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + + if(0xBF == pEntry->nMemberId) + { + lcl_SetSpecialProperty(pFormat, pEntry, aValue); + } + else + { + switch(pEntry->nWID) + { + case FN_UNO_TABLE_NAME : + { + OUString sName; + aValue >>= sName; + setName( sName ); + } + break; + + case FN_UNO_RANGE_ROW_LABEL: + { + bool bTmp = *o3tl::doAccess<bool>(aValue); + if (m_pImpl->m_bFirstRowAsLabel != bTmp) + { + std::unique_lock aGuard2(m_pImpl->m_Mutex); + lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners); + m_pImpl->m_bFirstRowAsLabel = bTmp; + } + } + break; + + case FN_UNO_RANGE_COL_LABEL: + { + bool bTmp = *o3tl::doAccess<bool>(aValue); + if (m_pImpl->m_bFirstColumnAsLabel != bTmp) + { + std::unique_lock aGuard2(m_pImpl->m_Mutex); + lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners); + m_pImpl->m_bFirstColumnAsLabel = bTmp; + } + } + break; + + case FN_UNO_TABLE_BORDER: + case FN_UNO_TABLE_BORDER2: + { + table::TableBorder oldBorder; + table::TableBorder2 aBorder; + SvxBorderLine aTopLine; + SvxBorderLine aBottomLine; + SvxBorderLine aLeftLine; + SvxBorderLine aRightLine; + SvxBorderLine aHoriLine; + SvxBorderLine aVertLine; + if (aValue >>= oldBorder) + { + aBorder.IsTopLineValid = oldBorder.IsTopLineValid; + aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid; + aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid; + aBorder.IsRightLineValid = oldBorder.IsRightLineValid; + aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid; + aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid; + aBorder.Distance = oldBorder.Distance; + aBorder.IsDistanceValid = oldBorder.IsDistanceValid; + lcl_LineToSvxLine( + oldBorder.TopLine, aTopLine); + lcl_LineToSvxLine( + oldBorder.BottomLine, aBottomLine); + lcl_LineToSvxLine( + oldBorder.LeftLine, aLeftLine); + lcl_LineToSvxLine( + oldBorder.RightLine, aRightLine); + lcl_LineToSvxLine( + oldBorder.HorizontalLine, aHoriLine); + lcl_LineToSvxLine( + oldBorder.VerticalLine, aVertLine); + } + else if (aValue >>= aBorder) + { + SvxBoxItem::LineToSvxLine( + aBorder.TopLine, aTopLine, true); + SvxBoxItem::LineToSvxLine( + aBorder.BottomLine, aBottomLine, true); + SvxBoxItem::LineToSvxLine( + aBorder.LeftLine, aLeftLine, true); + SvxBoxItem::LineToSvxLine( + aBorder.RightLine, aRightLine, true); + SvxBoxItem::LineToSvxLine( + aBorder.HorizontalLine, aHoriLine, true); + SvxBoxItem::LineToSvxLine( + aBorder.VerticalLine, aVertLine, true); + } + else + { + break; // something else + } + SwDoc* pDoc = pFormat->GetDoc(); + if(!lcl_FormatTable(pFormat)) + break; + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableLines &rLines = pTable->GetTabLines(); + + const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to top left cell + auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true)); + pUnoCursor->Move( fnMoveForward, GoInNode ); + pUnoCursor->SetRemainInSection( false ); + + const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false); + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() ); + pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + rCursor.MakeBoxSels(); + + SfxItemSetFixed<RES_BOX, RES_BOX, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> + aSet(pDoc->GetAttrPool()); + + SvxBoxItem aBox( RES_BOX ); + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + + aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid); + + aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid); + + aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid); + + aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid); + + aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid); + + aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid); + + aBox.SetAllDistances(o3tl::toTwips(aBorder.Distance, o3tl::Length::mm100)); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid); + + aSet.Put(aBox); + aSet.Put(aBoxInfo); + + pDoc->SetTabBorders(rCursor, aSet); + } + break; + + case FN_UNO_TABLE_BORDER_DISTANCES: + { + table::TableBorderDistances aTableBorderDistances; + if( !(aValue >>= aTableBorderDistances) || + (!aTableBorderDistances.IsLeftDistanceValid && + !aTableBorderDistances.IsRightDistanceValid && + !aTableBorderDistances.IsTopDistanceValid && + !aTableBorderDistances.IsBottomDistanceValid )) + break; + + const sal_uInt16 nLeftDistance = o3tl::toTwips(aTableBorderDistances.LeftDistance, o3tl::Length::mm100); + const sal_uInt16 nRightDistance = o3tl::toTwips(aTableBorderDistances.RightDistance, o3tl::Length::mm100); + const sal_uInt16 nTopDistance = o3tl::toTwips(aTableBorderDistances.TopDistance, o3tl::Length::mm100); + const sal_uInt16 nBottomDistance = o3tl::toTwips(aTableBorderDistances.BottomDistance, o3tl::Length::mm100); + SwDoc* pDoc = pFormat->GetDoc(); + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableLines &rLines = pTable->GetTabLines(); + pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr); + for(size_t i = 0; i < rLines.size(); ++i) + { + SwTableLine* pLine = rLines[i]; + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for(size_t k = 0; k < rBoxes.size(); ++k) + { + SwTableBox* pBox = rBoxes[k]; + const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat(); + const SvxBoxItem& rBox = pBoxFormat->GetBox(); + if( + (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) || + (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) || + (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) || + (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM ))) + { + SvxBoxItem aSetBox( rBox ); + SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat(); + if( aTableBorderDistances.IsLeftDistanceValid ) + aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT ); + if( aTableBorderDistances.IsRightDistanceValid ) + aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT ); + if( aTableBorderDistances.IsTopDistanceValid ) + aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP ); + if( aTableBorderDistances.IsBottomDistanceValid ) + aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM ); + pDoc->SetAttr( aSetBox, *pSetBoxFormat ); + } + } + } + pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); + } + break; + + case FN_UNO_TABLE_COLUMN_SEPARATORS: + { + UnoActionContext aContext(pFormat->GetDoc()); + SwTable* pTable = SwTable::FindTable( pFormat ); + lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc()); + } + break; + + case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break; + + case FN_UNO_TABLE_TEMPLATE_NAME: + { + SwTable* pTable = SwTable::FindTable(pFormat); + OUString sName; + if (!(aValue >>= sName)) + break; + SwStyleNameMapper::FillUIName(sName, sName, SwGetPoolIdFromName::TabStyle); + pTable->SetTableStyleName(sName); + SwDoc* pDoc = pFormat->GetDoc(); + if (SwFEShell* pFEShell = pDoc->GetDocShell()->GetFEShell()) + pFEShell->UpdateTableStyleFormatting(pTable->GetTableNode()); + } + break; + + default: + { + SwAttrSet aSet(pFormat->GetAttrSet()); + m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + pFormat->GetDoc()->SetAttr(aSet, *pFormat); + } + } + } + } + else if (m_pImpl->IsDescriptor()) + { + m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue); + } + else + throw uno::RuntimeException(); +} + +uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat* pFormat = GetFrameFormat(); + const SfxItemPropertyMapEntry* pEntry = + m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); + + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if(pFormat) + { + if(0xBF == pEntry->nMemberId) + { + aRet = lcl_GetSpecialProperty(pFormat, pEntry ); + } + else + { + switch(pEntry->nWID) + { + case FN_UNO_TABLE_NAME: + { + aRet <<= getName(); + } + break; + + case FN_UNO_ANCHOR_TYPES: + case FN_UNO_TEXT_WRAP: + case FN_UNO_ANCHOR_TYPE: + ::sw::GetDefaultTextContentValue( + aRet, u"", pEntry->nWID); + break; + + case FN_UNO_RANGE_ROW_LABEL: + { + aRet <<= m_pImpl->m_bFirstRowAsLabel; + } + break; + + case FN_UNO_RANGE_COL_LABEL: + aRet <<= m_pImpl->m_bFirstColumnAsLabel; + break; + + case FN_UNO_TABLE_BORDER: + case FN_UNO_TABLE_BORDER2: + { + SwDoc* pDoc = pFormat->GetDoc(); + // tables without layout (invisible header/footer?) + if(!lcl_FormatTable(pFormat)) + break; + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableLines &rLines = pTable->GetTabLines(); + + const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to top left cell + auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true)); + pUnoCursor->Move( fnMoveForward, GoInNode ); + pUnoCursor->SetRemainInSection( false ); + + const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false); + pUnoCursor->SetMark(); + const SwStartNode* pLastNd = pBRBox->GetSttNd(); + pUnoCursor->GetPoint()->Assign( *pLastNd ); + + pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + rCursor.MakeBoxSels(); + + SfxItemSetFixed<RES_BOX, RES_BOX, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> + aSet(pDoc->GetAttrPool()); + aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER )); + SwDoc::GetTabBorders(rCursor, aSet); + const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER); + const SvxBoxItem& rBox = aSet.Get(RES_BOX); + + if (FN_UNO_TABLE_BORDER == pEntry->nWID) + { + table::TableBorder aTableBorder; + aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true); + aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP); + aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true); + aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM); + aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true); + aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT); + aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true); + aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT ); + aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true); + aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI); + aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true); + aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT); + aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance()); + aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE); + aRet <<= aTableBorder; + } + else + { + table::TableBorder2 aTableBorder; + aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true); + aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP); + aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true); + aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM); + aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true); + aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT); + aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true); + aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT ); + aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true); + aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI); + aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true); + aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT); + aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance()); + aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE); + aRet <<= aTableBorder; + } + } + break; + + case FN_UNO_TABLE_BORDER_DISTANCES : + { + table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ; + SwTable* pTable = SwTable::FindTable( pFormat ); + const SwTableLines &rLines = pTable->GetTabLines(); + bool bFirst = true; + sal_uInt16 nLeftDistance = 0; + sal_uInt16 nRightDistance = 0; + sal_uInt16 nTopDistance = 0; + sal_uInt16 nBottomDistance = 0; + + for(size_t i = 0; i < rLines.size(); ++i) + { + const SwTableLine* pLine = rLines[i]; + const SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for(size_t k = 0; k < rBoxes.size(); ++k) + { + const SwTableBox* pBox = rBoxes[k]; + SwFrameFormat* pBoxFormat = pBox->GetFrameFormat(); + const SvxBoxItem& rBox = pBoxFormat->GetBox(); + if( bFirst ) + { + nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )); + nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )); + nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )); + nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )); + bFirst = false; + } + else + { + if( aTableBorderDistances.IsLeftDistanceValid && + nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ))) + aTableBorderDistances.IsLeftDistanceValid = false; + if( aTableBorderDistances.IsRightDistanceValid && + nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ))) + aTableBorderDistances.IsRightDistanceValid = false; + if( aTableBorderDistances.IsTopDistanceValid && + nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ))) + aTableBorderDistances.IsTopDistanceValid = false; + if( aTableBorderDistances.IsBottomDistanceValid && + nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ))) + aTableBorderDistances.IsBottomDistanceValid = false; + } + + } + if( !aTableBorderDistances.IsLeftDistanceValid && + !aTableBorderDistances.IsRightDistanceValid && + !aTableBorderDistances.IsTopDistanceValid && + !aTableBorderDistances.IsBottomDistanceValid ) + break; + } + if( aTableBorderDistances.IsLeftDistanceValid) + aTableBorderDistances.LeftDistance = nLeftDistance; + if( aTableBorderDistances.IsRightDistanceValid) + aTableBorderDistances.RightDistance = nRightDistance; + if( aTableBorderDistances.IsTopDistanceValid) + aTableBorderDistances.TopDistance = nTopDistance; + if( aTableBorderDistances.IsBottomDistanceValid) + aTableBorderDistances.BottomDistance = nBottomDistance; + + aRet <<= aTableBorderDistances; + } + break; + + case FN_UNO_TABLE_COLUMN_SEPARATORS: + { + SwTable* pTable = SwTable::FindTable( pFormat ); + lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false); + } + break; + + case FN_UNO_TABLE_COLUMN_RELATIVE_SUM: + aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM); + break; + + case RES_ANCHOR: + // AnchorType is readonly and might be void (no return value) + break; + + case FN_UNO_TEXT_SECTION: + { + SwTable* pTable = SwTable::FindTable( pFormat ); + SwTableNode* pTableNode = pTable->GetTableNode(); + SwSectionNode* pSectionNode = pTableNode->FindSectionNode(); + if(pSectionNode) + { + SwSection& rSect = pSectionNode->GetSection(); + uno::Reference< text::XTextSection > xSect = + SwXTextSections::GetObject( *rSect.GetFormat() ); + aRet <<= xSect; + } + } + break; + + case FN_UNO_TABLE_TEMPLATE_NAME: + { + SwTable* pTable = SwTable::FindTable(pFormat); + OUString sName; + SwStyleNameMapper::FillProgName(pTable->GetTableStyleName(), sName, SwGetPoolIdFromName::TabStyle); + aRet <<= sName; + } + break; + + default: + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + m_pImpl->m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); + } + } + } + } + else if (m_pImpl->IsDescriptor()) + { + const uno::Any* pAny = nullptr; + if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny)) + throw lang::IllegalArgumentException(); + else if(pAny) + aRet = *pAny; + } + else + throw uno::RuntimeException(); + return aRet; +} + +void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +OUString SwXTextTable::getName() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if (!pFormat && !m_pImpl->IsDescriptor()) + throw uno::RuntimeException(); + if(pFormat) + { + return pFormat->GetName(); + } + return m_pImpl->m_sTableName; +} + +void SwXTextTable::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if ((!pFormat && !m_pImpl->IsDescriptor()) || + rName.isEmpty() || + rName.indexOf('.')>=0 || + rName.indexOf(' ')>=0 ) + throw uno::RuntimeException(); + + if(pFormat) + { + const OUString aOldName( pFormat->GetName() ); + const sw::TableFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats(); + for (size_t i = pFrameFormats->size(); i;) + { + const SwTableFormat* pTmpFormat = (*pFrameFormats)[--i]; + if( !pTmpFormat->IsDefault() && + pTmpFormat->GetName() == rName && + pFormat->GetDoc()->IsUsed( *pTmpFormat )) + { + throw uno::RuntimeException(); + } + } + + pFormat->SetFormatName( rName ); + + SwStartNode *pStNd; + SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) ) + { + ++aIdx; + SwNode *const pNd = & aIdx.GetNode(); + if ( pNd->IsOLENode() && + aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() ) + { + static_cast<SwOLENode*>(pNd)->SetChartTableName( rName ); + + SwTable* pTable = SwTable::FindTable( pFormat ); + //TL_CHART2: chart needs to be notified about name changes + pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() ); + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } + pFormat->GetDoc()->getIDocumentState().SetModified(); + } + else + m_pImpl->m_sTableName = rName; +} + +sal_uInt16 SwXTextTable::Impl::GetRowCount() +{ + sal_uInt16 nRet = 0; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + SwTable* pTable = SwTable::FindTable( pFormat ); + if(!pTable->IsTableComplex()) + { + nRet = pTable->GetTabLines().size(); + } + } + return nRet; +} + +sal_uInt16 SwXTextTable::Impl::GetColumnCount() +{ + SwFrameFormat* pFormat = GetFrameFormat(); + sal_uInt16 nRet = 0; + if(pFormat) + { + SwTable* pTable = SwTable::FindTable( pFormat ); + if(!pTable->IsTableComplex()) + { + SwTableLines& rLines = pTable->GetTabLines(); + SwTableLine* pLine = rLines.front(); + nRet = pLine->GetTabBoxes().size(); + } + } + return nRet; +} + +void SwXTextTable::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pFrameFormat = nullptr; + EndListeningAll(); + } + std::unique_lock aGuard(m_Mutex); + if (m_EventListeners.getLength(aGuard) == 0 && m_ChartListeners.getLength(aGuard) == 0) + return; + uno::Reference<uno::XInterface> const xThis(m_wThis); + // fdo#72695: if UNO object is already dead, don't revive it with event + if (!xThis) + return; + if(!m_pFrameFormat) + { + lang::EventObject const ev(xThis); + m_EventListeners.disposeAndClear(aGuard, ev); + m_ChartListeners.disposeAndClear(aGuard, ev); + } + else + { + lcl_SendChartEvent(aGuard, xThis, m_ChartListeners); + } +} + +OUString SAL_CALL SwXTextTable::getImplementationName() + { return "SwXTextTable"; } + +sal_Bool SwXTextTable::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames() +{ + return { + "com.sun.star.document.LinkTarget", + "com.sun.star.text.TextTable", + "com.sun.star.text.TextContent", + "com.sun.star.text.TextSortable" }; +} + + +class SwXCellRange::Impl + : public SvtListener +{ +private: + SwFrameFormat* m_pFrameFormat; + +public: + uno::WeakReference<uno::XInterface> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners; + + sw::UnoCursorPointer m_pTableCursor; + + SwRangeDescriptor m_RangeDescriptor; + const SfxItemPropertySet* m_pPropSet; + + bool m_bFirstRowAsLabel; + bool m_bFirstColumnAsLabel; + + Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc) + : m_pFrameFormat(&rFrameFormat) + , m_pTableCursor(pCursor) + , m_RangeDescriptor(rDesc) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE)) + , m_bFirstRowAsLabel(false) + , m_bFirstColumnAsLabel(false) + { + StartListening(rFrameFormat.GetNotifier()); + m_RangeDescriptor.Normalize(); + } + + SwFrameFormat* GetFrameFormat() + { + return m_pFrameFormat; + } + + std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow); + + uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow); + + void SetLabelDescriptions(SwXCellRange & rThis, + const css::uno::Sequence<OUString>& rDesc, bool bRow); + + sal_Int32 GetRowCount() const; + sal_Int32 GetColumnCount() const; + + virtual void Notify(const SfxHint& ) override; + +}; + +OUString SwXCellRange::getImplementationName() + { return "SwXCellRange"; } + +sal_Bool SwXCellRange::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames() +{ + return { + "com.sun.star.text.CellRange", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" }; +} + +SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor, + SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc) + : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc)) +{ +} + +SwXCellRange::~SwXCellRange() +{ +} + +rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange( + sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, + SwRangeDescriptor const & rDesc) +{ + rtl::Reference<SwXCellRange> pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc)); + // need a permanent Reference to initialize m_wThis + pCellRange->m_pImpl->m_wThis = uno::Reference<table::XCellRange>(pCellRange); + return pCellRange; +} + +void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel) +{ + m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel; + m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel; +} + +std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells() +{ + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + const sal_Int32 nRowCount(m_pImpl->GetRowCount()); + const sal_Int32 nColCount(m_pImpl->GetColumnCount()); + std::vector< uno::Reference< table::XCell > > vResult; + vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount)); + for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow) + for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol) + vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow)); + return vResult; +} + +uno::Reference<table::XCell> SAL_CALL +SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow) +{ + SolarMutexGuard aGuard; + uno::Reference< table::XCell > aRet; + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if(pFormat) + { + if(nColumn >= 0 && nRow >= 0 && + m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow ) + { + rtl::Reference<SwXCell> pXCell = lcl_CreateXCell(pFormat, + m_pImpl->m_RangeDescriptor.nLeft + nColumn, + m_pImpl->m_RangeDescriptor.nTop + nRow); + if(pXCell) + aRet = pXCell; + } + } + if(!aRet.is()) + throw lang::IndexOutOfBoundsException(); + return aRet; +} + +uno::Reference<table::XCellRange> SAL_CALL +SwXCellRange::getCellRangeByPosition( + sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom) +{ + SolarMutexGuard aGuard; + rtl::Reference< SwXCellRange > aRet; + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if (pFormat && m_pImpl->GetColumnCount() > nRight + && m_pImpl->GetRowCount() > nBottom && + nLeft <= nRight && nTop <= nBottom + && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 ) + { + SwTable* pTable = SwTable::FindTable( pFormat ); + if(!pTable->IsTableComplex()) + { + SwRangeDescriptor aNewDesc; + aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop; + aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop; + aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft; + aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft; + aNewDesc.Normalize(); + const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop); + const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom); + const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); + if(pTLBox) + { + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor in the upper-left cell of the range + auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true)); + pUnoCursor->Move( fnMoveForward, GoInNode ); + pUnoCursor->SetRemainInSection( false ); + const SwTableBox* pBRBox = pTable->GetTableBox( sBRName ); + if(pBRBox) + { + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() ); + pUnoCursor->Move( fnMoveForward, GoInNode ); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + rCursor.MakeBoxSels(); + // pUnoCursor will be provided and will not be deleted + aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get(); + } + } + } + } + if(!aRet.is()) + throw lang::IndexOutOfBoundsException(); + return aRet; +} + +uno::Reference<table::XCellRange> SAL_CALL +SwXCellRange::getCellRangeByName(const OUString& rRange) +{ + SolarMutexGuard aGuard; + sal_Int32 nPos = 0; + const OUString sTLName(rRange.getToken(0, ':', nPos)); + const OUString sBRName(rRange.getToken(0, ':', nPos)); + if(sTLName.isEmpty() || sBRName.isEmpty()) + throw uno::RuntimeException(); + SwRangeDescriptor aDesc; + aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1; + SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop ); + SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom ); + aDesc.Normalize(); + return getCellRangeByPosition( + aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft, + aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop, + aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft, + aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop); +} + +uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo(); + return xRef; +} + +void SAL_CALL +SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if(!pFormat) + return; + + const SfxItemPropertyMapEntry *const pEntry = + m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() ); + + SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc(); + SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor)); + { + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + } + rCursor.MakeBoxSels(); + switch(pEntry->nWID ) + { + case FN_UNO_TABLE_CELL_BACKGROUND: + { + std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush); + aBrush->PutValue(aValue, pEntry->nMemberId); + rDoc.SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush); + + } + break; + case RES_BOX : + { + SfxItemSetFixed<RES_BOX, RES_BOX, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> + aSet(rDoc.GetAttrPool()); + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false); + SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE; + switch(pEntry->nMemberId & ~CONVERT_TWIPS) + { + case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break; + case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break; + case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break; + case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break; + case LEFT_BORDER_DISTANCE : + case RIGHT_BORDER_DISTANCE: + case TOP_BORDER_DISTANCE : + case BOTTOM_BORDER_DISTANCE: + nValid = SvxBoxInfoItemValidFlags::DISTANCE; + break; + } + aBoxInfo.SetValid(nValid); + + aSet.Put(aBoxInfo); + SwDoc::GetTabBorders(rCursor, aSet); + + aSet.Put(aBoxInfo); + SvxBoxItem aBoxItem(aSet.Get(RES_BOX)); + static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId); + aSet.Put(aBoxItem); + rDoc.SetTabBorders(*m_pImpl->m_pTableCursor, aSet); + } + break; + case RES_BOXATR_FORMAT: + { + SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT); + static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0); + rDoc.SetBoxAttr(rCursor, aNumberFormat); + } + break; + case FN_UNO_RANGE_ROW_LABEL: + { + bool bTmp = *o3tl::doAccess<bool>(aValue); + if (m_pImpl->m_bFirstRowAsLabel != bTmp) + { + std::unique_lock aGuard2(m_pImpl->m_Mutex); + lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners); + m_pImpl->m_bFirstRowAsLabel = bTmp; + } + } + break; + case FN_UNO_RANGE_COL_LABEL: + { + bool bTmp = *o3tl::doAccess<bool>(aValue); + if (m_pImpl->m_bFirstColumnAsLabel != bTmp) + { + std::unique_lock aGuard2(m_pImpl->m_Mutex); + lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners); + m_pImpl->m_bFirstColumnAsLabel = bTmp; + } + } + break; + case RES_VERT_ORIENT: + { + sal_Int16 nAlign = -1; + aValue >>= nAlign; + if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM) + rDoc.SetBoxAlign( rCursor, nAlign ); + } + break; + default: + { + SfxItemSet aItemSet( rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID ); + SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), + aItemSet); + + if (!SwUnoCursorHelper::SetCursorPropertyValue( + *pEntry, aValue, rCursor.GetSelRing(), aItemSet)) + { + m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet); + } + SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(), + aItemSet, SetAttrMode::DEFAULT, true); + } + } +} + +uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if(pFormat) + { + const SfxItemPropertyMapEntry *const pEntry = + m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); + if(!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() ); + + switch(pEntry->nWID ) + { + case FN_UNO_TABLE_CELL_BACKGROUND: + { + std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush)) + aBrush->QueryValue(aRet, pEntry->nMemberId); + + } + break; + case RES_BOX : + { + SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc(); + SfxItemSetFixed<RES_BOX, RES_BOX, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> + aSet(rDoc.GetAttrPool()); + aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER )); + SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet); + const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX); + rBoxItem.QueryValue(aRet, pEntry->nMemberId); + } + break; + case RES_BOXATR_FORMAT: + OSL_FAIL("not implemented"); + break; + case FN_UNO_PARA_STYLE: + { + SwFormatColl *const pTmpFormat = + SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false); + OUString sRet; + if (pTmpFormat) + sRet = pTmpFormat->GetName(); + aRet <<= sRet; + } + break; + case FN_UNO_RANGE_ROW_LABEL: + aRet <<= m_pImpl->m_bFirstRowAsLabel; + break; + case FN_UNO_RANGE_COL_LABEL: + aRet <<= m_pImpl->m_bFirstColumnAsLabel; + break; + case RES_VERT_ORIENT: + { + std::unique_ptr<SfxPoolItem> aVertOrient( + std::make_unique<SwFormatVertOrient>(RES_VERT_ORIENT)); + if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient)) + { + aVertOrient->QueryValue( aRet, pEntry->nMemberId ); + } + } + break; + default: + { + SfxItemSetFixed< + RES_CHRATR_BEGIN, RES_FRMATR_END - 1, + RES_UNKNOWNATR_CONTAINER, + RES_UNKNOWNATR_CONTAINER> + aSet(m_pImpl->m_pTableCursor->GetDoc().GetAttrPool()); + // first look at the attributes of the cursor + SwUnoTableCursor& rCursor = + dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor); + SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), aSet); + m_pImpl->m_pPropSet->getPropertyValue(*pEntry, aSet, aRet); + } + } + + } + return aRet; +} + +void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +///@see SwXCellRange::getData +uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray() +{ + SolarMutexGuard aGuard; + const sal_Int32 nRowCount = m_pImpl->GetRowCount(); + const sal_Int32 nColCount = m_pImpl->GetColumnCount(); + if(!nRowCount || !nColCount) + throw uno::RuntimeException("Table too complex", getXWeak()); + lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this); + uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount); + auto vCells(GetCells()); + auto pCurrentCell(vCells.begin()); + for(auto& rRow : asNonConstRange(aRowSeq)) + { + rRow = uno::Sequence< uno::Any >(nColCount); + for(auto& rCellAny : asNonConstRange(rRow)) + { + auto pCell(static_cast<SwXCell*>(pCurrentCell->get())); + if(!pCell) + throw uno::RuntimeException("Table too complex", getXWeak()); + rCellAny = pCell->GetAny(); + ++pCurrentCell; + } + } + return aRowSeq; +} + +///@see SwXCellRange::setData +void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray) +{ + SolarMutexGuard aGuard; + const sal_Int32 nRowCount = m_pImpl->GetRowCount(); + const sal_Int32 nColCount = m_pImpl->GetColumnCount(); + if(!nRowCount || !nColCount) + throw uno::RuntimeException("Table too complex", getXWeak()); + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if(!pFormat) + return; + if(rArray.getLength() != nRowCount) + throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), getXWeak()); + auto vCells(GetCells()); + auto pCurrentCell(vCells.begin()); + for(const auto& rColSeq : rArray) + { + if(rColSeq.getLength() != nColCount) + throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), getXWeak()); + for(const auto& aValue : rColSeq) + { + auto pCell(static_cast<SwXCell*>(pCurrentCell->get())); + if(!pCell || !pCell->GetTableBox()) + throw uno::RuntimeException("Box for cell missing", getXWeak()); + if(aValue.isExtractableTo(cppu::UnoType<OUString>::get())) + sw_setString(*pCell, aValue.get<OUString>()); + else if(aValue.isExtractableTo(cppu::UnoType<double>::get())) + sw_setValue(*pCell, aValue.get<double>()); + else + sw_setString(*pCell, OUString(), true); + ++pCurrentCell; + } + } +} + +uno::Sequence<uno::Sequence<double>> SAL_CALL +SwXCellRange::getData() +{ + SolarMutexGuard aGuard; + const sal_Int32 nRowCount = m_pImpl->GetRowCount(); + const sal_Int32 nColCount = m_pImpl->GetColumnCount(); + if(!nRowCount || !nColCount) + throw uno::RuntimeException("Table too complex", getXWeak()); + if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel) + { + uno::Reference<chart::XChartDataArray> const xDataRange( + getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0, + (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0, + nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW); + return xDataRange->getData(); + } + uno::Sequence< uno::Sequence< double > > vRows(nRowCount); + auto vCells(GetCells()); + auto pCurrentCell(vCells.begin()); + for(auto& rRow : asNonConstRange(vRows)) + { + rRow = uno::Sequence<double>(nColCount); + for(auto& rValue : asNonConstRange(rRow)) + { + if(!(*pCurrentCell)) + throw uno::RuntimeException("Table too complex", getXWeak()); + rValue = (*pCurrentCell)->getValue(); + ++pCurrentCell; + } + } + return vRows; +} + +void SAL_CALL +SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData) +{ + SolarMutexGuard aGuard; + const sal_Int32 nRowCount = m_pImpl->GetRowCount(); + const sal_Int32 nColCount = m_pImpl->GetColumnCount(); + if(!nRowCount || !nColCount) + throw uno::RuntimeException("Table too complex", getXWeak()); + if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel) + { + uno::Reference<chart::XChartDataArray> const xDataRange( + getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0, + (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0, + nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW); + return xDataRange->setData(rData); + } + lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this); + if(rData.getLength() != nRowCount) + throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), getXWeak()); + auto vCells(GetCells()); + auto pCurrentCell(vCells.begin()); + for(const auto& rRow : rData) + { + if(rRow.getLength() != nColCount) + throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), getXWeak()); + for(const auto& rValue : rRow) + { + uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue); + ++pCurrentCell; + } + } +} + +std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> +SwXCellRange::Impl::GetLabelCoordinates(bool bRow) +{ + sal_uInt32 nLeft, nTop, nRight, nBottom; + nLeft = nTop = nRight = nBottom = 0; + if(bRow) + { + nTop = m_bFirstRowAsLabel ? 1 : 0; + nBottom = GetRowCount() - 1; + } + else + { + nLeft = m_bFirstColumnAsLabel ? 1 : 0; + nRight = GetColumnCount() - 1; + } + return std::make_tuple(nLeft, nTop, nRight, nBottom); +} + +uno::Sequence<OUString> +SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow) +{ + SolarMutexGuard aGuard; + sal_uInt32 nLeft, nTop, nRight, nBottom; + std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow); + if(!nRight && !nBottom) + throw uno::RuntimeException("Table too complex", rThis.getXWeak()); + lcl_EnsureCoreConnected(GetFrameFormat(), &rThis); + if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel)) + return {}; // without labels we have no descriptions + auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom)); + auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells()); + uno::Sequence<OUString> vResult(vCells.size()); + std::transform(vCells.begin(), vCells.end(), vResult.getArray(), + [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); }); + return vResult; +} + +uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions() +{ + return m_pImpl->GetLabelDescriptions(*this, true); +} + +uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions() +{ + return m_pImpl->GetLabelDescriptions(*this, false); +} + +void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis, + const uno::Sequence<OUString>& rDesc, bool bRow) +{ + SolarMutexGuard aGuard; + lcl_EnsureCoreConnected(GetFrameFormat(), &rThis); + if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel)) + return; // if there are no labels we cannot set descriptions + sal_uInt32 nLeft, nTop, nRight, nBottom; + std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow); + if(!nRight && !nBottom) + throw uno::RuntimeException("Table too complex", rThis.getXWeak()); + auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom)); + if (!xLabelRange.is()) + throw uno::RuntimeException("Missing Cell Range", rThis.getXWeak()); + auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells()); + if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size()) + throw uno::RuntimeException("Too few or too many descriptions", rThis.getXWeak()); + auto pDescIterator(rDesc.begin()); + for(auto& xCell : vCells) + uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++); +} + +void SAL_CALL SwXCellRange::setRowDescriptions( + const uno::Sequence<OUString>& rRowDesc) +{ + m_pImpl->SetLabelDescriptions(*this, rRowDesc, true); +} + +void SAL_CALL SwXCellRange::setColumnDescriptions( + const uno::Sequence<OUString>& rColumnDesc) +{ + m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false); +} + +void SAL_CALL SwXCellRange::addChartDataChangeEventListener( + const uno::Reference<chart::XChartDataChangeEventListener> & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_ChartListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXCellRange::removeChartDataChangeEventListener( + const uno::Reference<chart::XChartDataChangeEventListener> & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener); +} + +sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/) + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +double SwXCellRange::getNotANumber() + { throw uno::RuntimeException("Not implemented", getXWeak()); } + +uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor() +{ + SolarMutexGuard aGuard; + return SwUnoCursorHelper::CreateSortDescriptor(true); +} + +void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor) +{ + SolarMutexGuard aGuard; + SwSortOptions aSortOpt; + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)) + { + SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor); + rTableCursor.MakeBoxSels(); + UnoActionContext aContext(pFormat->GetDoc()); + pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt); + } +} + +sal_Int32 SwXCellRange::Impl::GetColumnCount() const +{ + return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1; +} + +sal_Int32 SwXCellRange::Impl::GetRowCount() const +{ + return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1; +} + +const SwUnoCursor* SwXCellRange::GetTableCursor() const +{ + SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); + return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr; +} + +void SwXCellRange::Impl::Notify( const SfxHint& rHint ) +{ + uno::Reference<uno::XInterface> const xThis(m_wThis); + if(rHint.GetId() == SfxHintId::Dying) + { + m_pFrameFormat = nullptr; + m_pTableCursor.reset(nullptr); + } + if (xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + if(m_pFrameFormat) + { + std::unique_lock aGuard(m_Mutex); + lcl_SendChartEvent(aGuard, xThis, m_ChartListeners); + } + else + { + std::unique_lock aGuard(m_Mutex); + m_ChartListeners.disposeAndClear(aGuard, lang::EventObject(xThis)); + } + } +} + +class SwXTableRows::Impl : public SvtListener +{ +private: + SwFrameFormat* m_pFrameFormat; + +public: + explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat) + { + StartListening(rFrameFormat.GetNotifier()); + } + SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } + virtual void Notify(const SfxHint&) override; +}; + +// SwXTableRows + +OUString SwXTableRows::getImplementationName() + { return "SwXTableRows"; } + +sal_Bool SwXTableRows::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames() + { return { "com.sun.star.text.TableRows" }; } + + +SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) : + m_pImpl(new SwXTableRows::Impl(rFrameFormat)) +{ } + +SwXTableRows::~SwXTableRows() +{ } + +SwFrameFormat* SwXTableRows::GetFrameFormat() +{ + return m_pImpl->GetFrameFormat(); +} + +sal_Int32 SwXTableRows::getCount() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFrameFormat = GetFrameFormat(); + if(!pFrameFormat) + throw uno::RuntimeException(); + SwTable* pTable = SwTable::FindTable(pFrameFormat); + return pTable->GetTabLines().size(); +} + +///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here) +uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + if(nIndex < 0) + throw lang::IndexOutOfBoundsException(); + SwTable* pTable = SwTable::FindTable( pFrameFormat ); + if(o3tl::make_unsigned(nIndex) >= pTable->GetTabLines().size()) + throw lang::IndexOutOfBoundsException(); + SwTableLine* pLine = pTable->GetTabLines()[nIndex]; + FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine}; + pFrameFormat->GetNotifier().Broadcast(aHint); + if(!aHint.m_pResult) + aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine); + uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult.get()); + return uno::Any(xRet); +} + +uno::Type SAL_CALL SwXTableRows::getElementType() +{ + return cppu::UnoType<beans::XPropertySet>::get(); +} + +sal_Bool SwXTableRows::hasElements() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFrameFormat = GetFrameFormat(); + if(!pFrameFormat) + throw uno::RuntimeException(); + // a table always has rows + return true; +} + +void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount) +{ + SolarMutexGuard aGuard; + if (nCount == 0) + return; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this); + const size_t nRowCount = pTable->GetTabLines().size(); + if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nRowCount) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + const OUString sTLName = sw_GetCellName(0, nIndex); + const SwTableBox* pTLBox = pTable->GetTableBox(sTLName); + bool bAppend = false; + if(!pTLBox) + { + bAppend = true; + // to append at the end the cursor must be in the last line + SwTableLines& rLines = pTable->GetTabLines(); + SwTableLine* pLine = rLines.back(); + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + pTLBox = rBoxes.front(); + } + if(!pTLBox) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to the upper-left cell of the range + UnoActionContext aAction(pFrameFormat->GetDoc()); + std::shared_ptr<SwUnoTableCursor> const pUnoCursor( + std::dynamic_pointer_cast<SwUnoTableCursor>( + pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true))); + pUnoCursor->Move( fnMoveForward, GoInNode ); + { + // remove actions - TODO: why? + UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc()); + } + pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend); +} + +void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount) +{ + SolarMutexGuard aGuard; + if (nCount == 0) + return; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + if(nIndex < 0 || nCount <=0 ) + throw uno::RuntimeException(); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this); + OUString sTLName = sw_GetCellName(0, nIndex); + const SwTableBox* pTLBox = pTable->GetTableBox(sTLName); + if(!pTLBox) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to the upper-left cell of the range + auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); + pUnoCursor->Move(fnMoveForward, GoInNode); + pUnoCursor->SetRemainInSection( false ); + const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1); + const SwTableBox* pBLBox = pTable->GetTableBox( sBLName ); + if(!pBLBox) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pBLBox->GetSttNd() ); + pUnoCursor->Move(fnMoveForward, GoInNode); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + { + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + } + rCursor.MakeBoxSels(); + { // these braces are important + UnoActionContext aAction(pFrameFormat->GetDoc()); + pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor); + pUnoCursor.reset(); + } + { + // invalidate all actions - TODO: why? + UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc()); + } +} + +void SwXTableRows::Impl::Notify( const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFrameFormat = nullptr; +} + +// SwXTableColumns + +class SwXTableColumns::Impl : public SvtListener +{ + SwFrameFormat* m_pFrameFormat; + public: + explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat) + { + StartListening(rFrameFormat.GetNotifier()); + } + SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } + virtual void Notify(const SfxHint&) override; +}; + +OUString SwXTableColumns::getImplementationName() + { return "SwXTableColumns"; } + +sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName) + { return cppu::supportsService(this, rServiceName); } + +uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames() + { return { "com.sun.star.text.TableColumns"}; } + + +SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) : + m_pImpl(new SwXTableColumns::Impl(rFrameFormat)) +{ } + +SwXTableColumns::~SwXTableColumns() +{ } + +SwFrameFormat* SwXTableColumns::GetFrameFormat() const +{ + return m_pImpl->GetFrameFormat(); +} + +sal_Int32 SwXTableColumns::getCount() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + SwTable* pTable = SwTable::FindTable( pFrameFormat ); +// if(!pTable->IsTableComplex()) +// throw uno::RuntimeException("Table too complex", getXWeak()); + SwTableLines& rLines = pTable->GetTabLines(); + SwTableLine* pLine = rLines.front(); + return pLine->GetTabBoxes().size(); +} + +uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(nIndex < 0 || getCount() <= nIndex) + throw lang::IndexOutOfBoundsException(); + return uno::Any(uno::Reference<uno::XInterface>()); // i#21699 not supported +} + +uno::Type SAL_CALL SwXTableColumns::getElementType() +{ + return cppu::UnoType<uno::XInterface>::get(); +} + +sal_Bool SwXTableColumns::hasElements() +{ + SolarMutexGuard aGuard; + lcl_EnsureCoreConnected(GetFrameFormat(), this); + return true; +} + +///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here) +void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount) +{ + SolarMutexGuard aGuard; + if (nCount == 0) + return; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this); + SwTableLines& rLines = pTable->GetTabLines(); + SwTableLine* pLine = rLines.front(); + const size_t nColCount = pLine->GetTabBoxes().size(); + if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nColCount) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + const OUString sTLName = sw_GetCellName(nIndex, 0); + const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); + bool bAppend = false; + if(!pTLBox) + { + bAppend = true; + // to append at the end the cursor must be in the last line + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + pTLBox = rBoxes.back(); + } + if(!pTLBox) + throw uno::RuntimeException("Illegal arguments", getXWeak()); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + UnoActionContext aAction(pFrameFormat->GetDoc()); + auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); + pUnoCursor->Move(fnMoveForward, GoInNode); + + { + // remove actions - TODO: why? + UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc()); + } + + pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend); +} + +///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here) +void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount) +{ + SolarMutexGuard aGuard; + if (nCount == 0) + return; + SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this)); + if(nIndex < 0 || nCount <=0 ) + throw uno::RuntimeException(); + SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this); + const OUString sTLName = sw_GetCellName(nIndex, 0); + const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); + if(!pTLBox) + throw uno::RuntimeException("Cell not found", getXWeak()); + const SwStartNode* pSttNd = pTLBox->GetSttNd(); + SwPosition aPos(*pSttNd); + // set cursor to the upper-left cell of the range + auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); + pUnoCursor->Move(fnMoveForward, GoInNode); + pUnoCursor->SetRemainInSection(false); + const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0); + const SwTableBox* pTRBox = pTable->GetTableBox(sTRName); + if(!pTRBox) + throw uno::RuntimeException("Cell not found", getXWeak()); + pUnoCursor->SetMark(); + pUnoCursor->GetPoint()->Assign( *pTRBox->GetSttNd() ); + pUnoCursor->Move(fnMoveForward, GoInNode); + SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); + { + // HACK: remove pending actions for selecting old style tables + UnoActionRemoveContext aRemoveContext(rCursor); + } + rCursor.MakeBoxSels(); + { // these braces are important + UnoActionContext aAction(pFrameFormat->GetDoc()); + pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor); + pUnoCursor.reset(); + } + { + // invalidate all actions - TODO: why? + UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc()); + } +} + +void SwXTableColumns::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + m_pFrameFormat = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx new file mode 100644 index 0000000000..f959d6a610 --- /dev/null +++ b/sw/source/core/unocore/unotext.cxx @@ -0,0 +1,2706 @@ +/* -*- 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 <stdlib.h> + +#include <memory> +#include <set> + +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/TableColumnSeparator.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> + +#include <svl/listener.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/profilezone.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <cmdid.h> +#include <unotextbodyhf.hxx> +#include <unotext.hxx> +#include <unotextrange.hxx> +#include <unotextcursor.hxx> +#include <unosection.hxx> +#include <unobookmark.hxx> +#include <unorefmark.hxx> +#include <unoport.hxx> +#include <unotbl.hxx> +#include <unoidx.hxx> +#include <unocoll.hxx> +#include <unoframe.hxx> +#include <unofield.hxx> +#include <unometa.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <unoparagraph.hxx> +#include <unocrsrhelper.hxx> +#include <docary.hxx> +#include <doc.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <IDocumentUndoRedo.hxx> +#include <bookmark.hxx> +#include <redline.hxx> +#include <swundo.hxx> +#include <section.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <ndtxt.hxx> +#include <SwRewriter.hxx> +#include <strings.hrc> +#include <frameformats.hxx> +#include <unocontentcontrol.hxx> + +using namespace ::com::sun::star; + +constexpr OUString cInvalidObject = u"this object is invalid"_ustr; + +class SwXText::Impl +{ + +public: + SwXText & m_rThis; + SfxItemPropertySet const& m_rPropSet; + const CursorType m_eType; + SwDoc * m_pDoc; + bool m_bIsValid; + + Impl( SwXText & rThis, + SwDoc *const pDoc, const CursorType eType) + : m_rThis(rThis) + , m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT)) + , m_eType(eType) + , m_pDoc(pDoc) + , m_bIsValid(nullptr != pDoc) + { + } + + /// @throws lang::IllegalArgumentException + /// @throws uno::RuntimeException + rtl::Reference<SwXParagraph> + finishOrAppendParagraph( + const uno::Sequence< beans::PropertyValue >& + rCharacterAndParagraphProperties, + const uno::Reference< text::XTextRange >& xInsertPosition); + + /// @throws lang::IllegalArgumentException + /// @throws uno::RuntimeException + sal_Int16 ComparePositions( + const uno::Reference<text::XTextRange>& xPos1, + const uno::Reference<text::XTextRange>& xPos2); + + /// @throws lang::IllegalArgumentException + /// @throws uno::RuntimeException + bool CheckForOwnMember(const SwPaM & rPaM); + + void ConvertCell( + const uno::Sequence< uno::Reference< text::XTextRange > > & rCell, + std::vector<SwNodeRange> & rRowNodes, + SwNodeRange *const pLastCell); + +}; + +SwXText::SwXText(SwDoc *const pDoc, const CursorType eType) + : m_pImpl( new SwXText::Impl(*this, pDoc, eType) ) +{ +} + +SwXText::~SwXText() +{ +} + +const SwDoc * SwXText::GetDoc() const +{ + return m_pImpl->m_pDoc; +} + +SwDoc * SwXText::GetDoc() +{ + return m_pImpl->m_pDoc; +} + +bool SwXText::IsValid() const +{ + return m_pImpl->m_bIsValid; +} + +void SwXText::Invalidate() +{ + m_pImpl->m_bIsValid = false; +} + +void SwXText::SetDoc(SwDoc *const pDoc) +{ + OSL_ENSURE(!m_pImpl->m_pDoc || !pDoc, + "SwXText::SetDoc: already have a doc?"); + m_pImpl->m_pDoc = pDoc; + m_pImpl->m_bIsValid = (nullptr != pDoc); +} + +void +SwXText::PrepareForAttach(uno::Reference< text::XTextRange > &, const SwPaM &) +{ +} + +bool SwXText::CheckForOwnMemberMeta(const SwPaM &, const bool) +{ + OSL_ENSURE(CursorType::Meta != m_pImpl->m_eType, "should not be called!"); + return false; +} + +const SwStartNode *SwXText::GetStartNode() const +{ + return GetDoc()->GetNodes().GetEndOfContent().StartOfSectionNode(); +} + +uno::Reference< text::XTextCursor > SAL_CALL SwXText::createTextCursor() +{ + SolarMutexGuard aGuard; + rtl::Reference<SwXTextCursor> xCursor = createXTextCursor(); + if (!xCursor.is()) + throw uno::RuntimeException(cInvalidObject); + return static_cast<text::XWordCursor*>(xCursor.get()); +} + +rtl::Reference< SwXTextCursor > +SwXText::createXTextCursor() +{ + rtl::Reference< SwXTextCursor > xRet; + if(IsValid()) + { + SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); + SwPosition aPos(rNode); + xRet = new SwXTextCursor(*GetDoc(), this, m_pImpl->m_eType, aPos); + xRet->gotoStart(false); + } + return xRet; +} + +css::uno::Reference< css::text::XTextCursor > SAL_CALL SwXText::createTextCursorByRange( + const ::css::uno::Reference< ::css::text::XTextRange >& aTextPosition ) +{ + SolarMutexGuard aGuard; + return static_cast<text::XWordCursor*>(createXTextCursorByRange(aTextPosition).get()); +} + + +uno::Any SAL_CALL +SwXText::queryInterface(const uno::Type& rType) +{ + uno::Any aRet; + if (rType == cppu::UnoType<text::XText>::get()) + { + aRet <<= uno::Reference< text::XText >(this); + } + else if (rType == cppu::UnoType<text::XSimpleText>::get()) + { + aRet <<= uno::Reference< text::XSimpleText >(this); + } + else if (rType == cppu::UnoType<text::XTextRange>::get()) + { + aRet <<= uno::Reference< text::XTextRange>(this); + } + else if (rType == cppu::UnoType<text::XTextRangeCompare>::get()) + { + aRet <<= uno::Reference< text::XTextRangeCompare >(this); + } + else if (rType == cppu::UnoType<lang::XTypeProvider>::get()) + { + aRet <<= uno::Reference< lang::XTypeProvider >(this); + } + else if (rType == cppu::UnoType<text::XRelativeTextContentInsert>::get()) + { + aRet <<= uno::Reference< text::XRelativeTextContentInsert >(this); + } + else if (rType == cppu::UnoType<text::XRelativeTextContentRemove>::get()) + { + aRet <<= uno::Reference< text::XRelativeTextContentRemove >(this); + } + else if (rType == cppu::UnoType<beans::XPropertySet>::get()) + { + aRet <<= uno::Reference< beans::XPropertySet >(this); + } + else if (rType == cppu::UnoType<text::XTextAppendAndConvert>::get()) + { + aRet <<= uno::Reference< text::XTextAppendAndConvert >(this); + } + else if (rType == cppu::UnoType<text::XTextAppend>::get()) + { + aRet <<= uno::Reference< text::XTextAppend >(this); + } + else if (rType == cppu::UnoType<text::XTextPortionAppend>::get()) + { + aRet <<= uno::Reference< text::XTextPortionAppend >(this); + } + else if (rType == cppu::UnoType<text::XParagraphAppend>::get()) + { + aRet <<= uno::Reference< text::XParagraphAppend >(this); + } + else if (rType == cppu::UnoType<text::XTextConvert>::get() ) + { + aRet <<= uno::Reference< text::XTextConvert >(this); + } + else if (rType == cppu::UnoType<text::XTextContentAppend>::get()) + { + aRet <<= uno::Reference< text::XTextContentAppend >(this); + } + else if(rType == cppu::UnoType<text::XTextCopy>::get()) + { + aRet <<= uno::Reference< text::XTextCopy >( this ); + } + return aRet; +} + +uno::Sequence< uno::Type > SAL_CALL +SwXText::getTypes() +{ + static const uno::Sequence< uno::Type > aTypes { + cppu::UnoType<text::XText>::get(), + cppu::UnoType<text::XTextRangeCompare>::get(), + cppu::UnoType<text::XRelativeTextContentInsert>::get(), + cppu::UnoType<text::XRelativeTextContentRemove>::get(), + cppu::UnoType<lang::XUnoTunnel>::get(), + cppu::UnoType<beans::XPropertySet>::get(), + cppu::UnoType<text::XTextPortionAppend>::get(), + cppu::UnoType<text::XParagraphAppend>::get(), + cppu::UnoType<text::XTextContentAppend>::get(), + cppu::UnoType<text::XTextConvert>::get(), + cppu::UnoType<text::XTextAppend>::get(), + cppu::UnoType<text::XTextAppendAndConvert>::get() + }; + return aTypes; +} + +// belongs the range in the text ? insert it then. +void SAL_CALL +SwXText::insertString(const uno::Reference< text::XTextRange >& xTextRange, + const OUString& rString, sal_Bool bAbsorb) +{ + SolarMutexGuard aGuard; + comphelper::ProfileZone aZone("SwXText::insertString"); + + if (!xTextRange.is()) + { + throw uno::RuntimeException(); + } + if (!GetDoc()) + { + throw uno::RuntimeException(); + } + SwXTextRange *const pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + if ((!pRange || &pRange ->GetDoc() != GetDoc()) && + (!pCursor || pCursor->GetDoc() != GetDoc())) + { + throw uno::RuntimeException(); + } + + const SwStartNode *const pOwnStartNode = GetStartNode(); + SwPaM aPam(GetDoc()->GetNodes()); + const SwPaM * pPam(nullptr); + if (pCursor) + { + pPam = pCursor->GetPaM(); + } + else // pRange + { + if (pRange->GetPositions(aPam)) + { + pPam = &aPam; + } + } + if (!pPam) + { + throw uno::RuntimeException(); + } + + const SwStartNode* pTmp(pPam->GetPointNode().StartOfSectionNode()); + while (pTmp && pTmp->IsSectionNode()) + { + pTmp = pTmp->StartOfSectionNode(); + } + if (!pOwnStartNode || (pOwnStartNode != pTmp)) + { + throw uno::RuntimeException(); + } + + bool bForceExpandHints( false ); + if (CursorType::Meta == m_pImpl->m_eType) + { + try + { + bForceExpandHints = CheckForOwnMemberMeta(*pPam, bAbsorb); + } + catch (const lang::IllegalArgumentException& iae) + { + // stupid method not allowed to throw iae + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( iae.Message, + uno::Reference< uno::XInterface >(), anyEx ); + } + } + if (bAbsorb) + { + //!! scan for CR characters and inserting the paragraph breaks + //!! has to be done in the called function. + //!! Implemented in SwXTextRange::DeleteAndInsert + if (pCursor) + { + SwXTextCursor * const pTextCursor( + dynamic_cast<SwXTextCursor*>(pCursor) ); + if (pTextCursor) + { + pTextCursor->DeleteAndInsert(rString, ::sw::DeleteAndInsertMode::ForceReplace + | (bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default)); + } + else + { + xTextRange->setString(rString); + } + } + else + { + pRange->DeleteAndInsert(rString, ::sw::DeleteAndInsertMode::ForceReplace + | (bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default)); + } + } + else + { + // create a PaM positioned before the parameter PaM, + // so the text is inserted before + UnoActionContext aContext(GetDoc()); + SwPaM aInsertPam(*pPam->Start()); + ::sw::GroupUndoGuard const undoGuard(GetDoc()->GetIDocumentUndoRedo()); + SwUnoCursorHelper::DocInsertStringSplitCR( + *GetDoc(), aInsertPam, rString, bForceExpandHints ); + } +} + +void SAL_CALL +SwXText::insertControlCharacter( + const uno::Reference< text::XTextRange > & xTextRange, + sal_Int16 nControlCharacter, sal_Bool bAbsorb) +{ + SolarMutexGuard aGuard; + + if (!xTextRange.is()) + { + throw lang::IllegalArgumentException(); + } + if (!GetDoc()) + { + throw uno::RuntimeException(); + } + + SwUnoInternalPaM aPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(aPam, xTextRange)) + { + throw uno::RuntimeException(); + } + const bool bForceExpandHints(CheckForOwnMemberMeta(aPam, bAbsorb)); + + const SwInsertFlags nInsertFlags = + bForceExpandHints + ? ( SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND) + : SwInsertFlags::EMPTYEXPAND; + + if (bAbsorb && aPam.HasMark()) + { + m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); + aPam.DeleteMark(); + } + + sal_Unicode cIns = 0; + switch (nControlCharacter) + { + case text::ControlCharacter::PARAGRAPH_BREAK : + // a table cell now becomes an ordinary text cell! + m_pImpl->m_pDoc->ClearBoxNumAttrs(aPam.GetPoint()->GetNode()); + m_pImpl->m_pDoc->getIDocumentContentOperations().SplitNode(*aPam.GetPoint(), false); + break; + case text::ControlCharacter::APPEND_PARAGRAPH: + { + m_pImpl->m_pDoc->ClearBoxNumAttrs(aPam.GetPoint()->GetNode()); + m_pImpl->m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPam.GetPoint()); + + SwXTextRange *const pRange = + dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = + dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + if (pRange) + { + pRange->SetPositions(aPam); + } + else if (pCursor) + { + SwPaM *const pCursorPam = pCursor->GetPaM(); + *pCursorPam->GetPoint() = *aPam.GetPoint(); + pCursorPam->DeleteMark(); + } + } + break; + case text::ControlCharacter::LINE_BREAK: cIns = 10; break; + case text::ControlCharacter::SOFT_HYPHEN: cIns = CHAR_SOFTHYPHEN; break; + case text::ControlCharacter::HARD_HYPHEN: cIns = CHAR_HARDHYPHEN; break; + case text::ControlCharacter::HARD_SPACE: cIns = CHAR_HARDBLANK; break; + } + if (cIns) + { + m_pImpl->m_pDoc->getIDocumentContentOperations().InsertString( + aPam, OUString(cIns), nInsertFlags); + } + + if (!bAbsorb) + return; + + SwXTextRange *const pRange = + dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper *const pCursor = + dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + + SwCursor aCursor(*aPam.GetPoint(), nullptr); + SwUnoCursorHelper::SelectPam(aCursor, true); + aCursor.Left(1); + // here, the PaM needs to be moved: + if (pRange) + { + pRange->SetPositions(aCursor); + } + else if (pCursor) + { + SwPaM *const pUnoCursor = pCursor->GetPaM(); + *pUnoCursor->GetPoint() = *aCursor.GetPoint(); + if (aCursor.HasMark()) + { + pUnoCursor->SetMark(); + *pUnoCursor->GetMark() = *aCursor.GetMark(); + } + else + { + pUnoCursor->DeleteMark(); + } + } +} + +void SAL_CALL +SwXText::insertTextContent( + const uno::Reference< text::XTextRange > & xRange, + const uno::Reference< text::XTextContent > & xContent, + sal_Bool bAbsorb) +{ + SolarMutexGuard aGuard; + comphelper::ProfileZone aZone("SwXText::insertTextContent"); + + if (!xRange.is()) + throw lang::IllegalArgumentException("first parameter invalid", nullptr, 0); + if (!xContent.is()) + throw lang::IllegalArgumentException("second parameter invalid", nullptr, 1); + if (!GetDoc()) + throw uno::RuntimeException(cInvalidObject); + + SwUnoInternalPaM aPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(aPam, xRange)) + throw lang::IllegalArgumentException("first parameter invalid", nullptr, 0); + + // first test if the range is at the right position, then call + // xContent->attach + const SwStartNode* pOwnStartNode = GetStartNode(); + SwStartNodeType eSearchNodeType = SwNormalStartNode; + switch (m_pImpl->m_eType) + { + case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break; + case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break; + case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break; + case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break; + case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break; + //case CURSOR_INVALID: + //case CursorType::Body: + default: + break; + } + + const SwStartNode* pTmp = + aPam.GetPointNode().FindSttNodeByType(eSearchNodeType); + + // ignore SectionNodes + while (pTmp && pTmp->IsSectionNode()) + { + pTmp = pTmp->StartOfSectionNode(); + } + // if the document starts with a section + while (pOwnStartNode && pOwnStartNode->IsSectionNode()) + { + pOwnStartNode = pOwnStartNode->StartOfSectionNode(); + } + // this checks if (this) and xRange are in the same text::XText interface + if (pOwnStartNode != pTmp) + throw uno::RuntimeException("text interface and cursor not related"); + + const bool bForceExpandHints(CheckForOwnMemberMeta(aPam, bAbsorb)); + + // special treatment for Contents that do not replace the range, but + // instead are "overlaid" + SwXDocumentIndexMark *const pDocumentIndexMark = + dynamic_cast<SwXDocumentIndexMark*>(xContent.get()); + SwXTextSection *const pSection = + dynamic_cast<SwXTextSection*>(xContent.get()); + SwXBookmark *const pBookmark = + dynamic_cast<SwXBookmark*>(xContent.get()); + SwXReferenceMark *const pReferenceMark = + dynamic_cast<SwXReferenceMark*>(xContent.get()); + SwXMeta *const pMeta = dynamic_cast<SwXMeta*>(xContent.get()); + auto* pContentControl = dynamic_cast<SwXContentControl*>(xContent.get()); + SwXTextField* pTextField = dynamic_cast<SwXTextField*>(xContent.get()); + if (pTextField && pTextField->GetServiceId() != SwServiceType::FieldTypeAnnotation) + pTextField = nullptr; + + const bool bAttribute = pBookmark || pDocumentIndexMark + || pSection || pReferenceMark || pMeta || pContentControl || pTextField; + + if (bAbsorb && !bAttribute) + { + if (SwXTextRange *const pRange = dynamic_cast<SwXTextRange*>(xRange.get())) + { + pRange->DeleteAndInsert(u"", ::sw::DeleteAndInsertMode::ForceReplace + | (bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default)); + } + else if (SwXTextCursor *const pCursor = dynamic_cast<SwXTextCursor*>(dynamic_cast<OTextCursorHelper*>(xRange.get()))) + { + pCursor->DeleteAndInsert(u"", ::sw::DeleteAndInsertMode::ForceReplace + | (bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default)); + } + else + { + xRange->setString(OUString()); + } + } + uno::Reference< text::XTextRange > xTempRange = + (bAttribute && bAbsorb) ? xRange : xRange->getStart(); + if (bForceExpandHints) + { + // if necessary, replace xTempRange with a new SwXTextCursor + PrepareForAttach(xTempRange, aPam); + } + xContent->attach(xTempRange); +} + +void SAL_CALL +SwXText::insertTextContentBefore( + const uno::Reference< text::XTextContent>& xNewContent, + const uno::Reference< text::XTextContent>& xSuccessor) +{ + SolarMutexGuard aGuard; + + if(!GetDoc()) + throw uno::RuntimeException(cInvalidObject); + + SwXParagraph *const pPara = dynamic_cast<SwXParagraph*>(xNewContent.get()); + if (!pPara || !pPara->IsDescriptor() || !xSuccessor.is()) + { + throw lang::IllegalArgumentException(); + } + + bool bRet = false; + SwXTextSection *const pXSection = dynamic_cast<SwXTextSection*>(xSuccessor.get()); + SwXTextTable *const pXTable = dynamic_cast<SwXTextTable*>(xSuccessor.get()); + SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; + SwTextNode * pTextNode = nullptr; + if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) + { + SwTable *const pTable = SwTable::FindTable( pTableFormat ); + SwTableNode *const pTableNode = pTable->GetTableNode(); + + const SwNodeIndex aTableIdx( *pTableNode, -1 ); + SwPosition aBefore(aTableIdx); + bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); + pTextNode = aBefore.GetNode().GetTextNode(); + } + else if (pXSection && pXSection->GetFormat() && + pXSection->GetFormat()->GetDoc() == GetDoc()) + { + SwSectionFormat *const pSectFormat = pXSection->GetFormat(); + SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); + + const SwNodeIndex aSectIdx( *pSectNode, -1 ); + SwPosition aBefore(aSectIdx); + bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); + pTextNode = aBefore.GetNode().GetTextNode(); + } + if (!bRet || !pTextNode) + { + throw lang::IllegalArgumentException(); + } + pPara->attachToText(*this, *pTextNode); +} + +void SAL_CALL +SwXText::insertTextContentAfter( + const uno::Reference< text::XTextContent>& xNewContent, + const uno::Reference< text::XTextContent>& xPredecessor) +{ + SolarMutexGuard aGuard; + + if(!GetDoc()) + { + throw uno::RuntimeException(); + } + + SwXParagraph *const pPara = dynamic_cast<SwXParagraph*>(xNewContent.get()); + if(!pPara || !pPara->IsDescriptor() || !xPredecessor.is()) + { + throw lang::IllegalArgumentException(); + } + + SwXTextSection *const pXSection = dynamic_cast<SwXTextSection*>(xPredecessor.get()); + SwXTextTable *const pXTable = dynamic_cast<SwXTextTable*>(xPredecessor.get()); + SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; + bool bRet = false; + SwTextNode * pTextNode = nullptr; + if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) + { + SwTable *const pTable = SwTable::FindTable( pTableFormat ); + SwTableNode *const pTableNode = pTable->GetTableNode(); + + SwEndNode *const pTableEnd = pTableNode->EndOfSectionNode(); + SwPosition aTableEnd(*pTableEnd); + bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aTableEnd ); + pTextNode = aTableEnd.GetNode().GetTextNode(); + } + else if (pXSection && pXSection->GetFormat() && + pXSection->GetFormat()->GetDoc() == GetDoc()) + { + SwSectionFormat *const pSectFormat = pXSection->GetFormat(); + SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); + SwEndNode *const pEnd = pSectNode->EndOfSectionNode(); + SwPosition aEnd(*pEnd); + bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd ); + pTextNode = aEnd.GetNode().GetTextNode(); + } + if (!bRet || !pTextNode) + { + throw lang::IllegalArgumentException(); + } + pPara->attachToText(*this, *pTextNode); +} + +void SAL_CALL +SwXText::removeTextContentBefore( + const uno::Reference< text::XTextContent>& xSuccessor) +{ + SolarMutexGuard aGuard; + + if(!GetDoc()) + throw uno::RuntimeException(cInvalidObject); + + bool bRet = false; + SwXTextSection *const pXSection = dynamic_cast<SwXTextSection*>(xSuccessor.get()); + SwXTextTable *const pXTable = dynamic_cast<SwXTextTable*>(xSuccessor.get()); + SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; + if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) + { + SwTable *const pTable = SwTable::FindTable( pTableFormat ); + SwTableNode *const pTableNode = pTable->GetTableNode(); + + const SwNodeIndex aTableIdx( *pTableNode, -1 ); + if(aTableIdx.GetNode().IsTextNode()) + { + SwPaM aBefore(aTableIdx); + bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aBefore ); + } + } + else if (pXSection && pXSection->GetFormat() && + pXSection->GetFormat()->GetDoc() == GetDoc()) + { + SwSectionFormat *const pSectFormat = pXSection->GetFormat(); + SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); + + const SwNodeIndex aSectIdx( *pSectNode, -1 ); + if(aSectIdx.GetNode().IsTextNode()) + { + SwPaM aBefore(aSectIdx); + bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aBefore ); + } + } + if(!bRet) + { + throw lang::IllegalArgumentException(); + } +} + +void SAL_CALL +SwXText::removeTextContentAfter( + const uno::Reference< text::XTextContent>& xPredecessor) +{ + SolarMutexGuard aGuard; + + if(!GetDoc()) + throw uno::RuntimeException(cInvalidObject); + + bool bRet = false; + SwXTextSection *const pXSection = dynamic_cast<SwXTextSection*>(xPredecessor.get()); + SwXTextTable *const pXTable = dynamic_cast<SwXTextTable*>(xPredecessor.get()); + SwFrameFormat *const pTableFormat = pXTable ? pXTable->GetFrameFormat() : nullptr; + if(pTableFormat && pTableFormat->GetDoc() == GetDoc()) + { + SwTable *const pTable = SwTable::FindTable( pTableFormat ); + SwTableNode *const pTableNode = pTable->GetTableNode(); + SwEndNode *const pTableEnd = pTableNode->EndOfSectionNode(); + + const SwNodeIndex aTableIdx( *pTableEnd, 1 ); + if(aTableIdx.GetNode().IsTextNode()) + { + SwPaM aPaM(aTableIdx); + bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aPaM ); + } + } + else if (pXSection && pXSection->GetFormat() && + pXSection->GetFormat()->GetDoc() == GetDoc()) + { + SwSectionFormat *const pSectFormat = pXSection->GetFormat(); + SwSectionNode *const pSectNode = pSectFormat->GetSectionNode(); + SwEndNode *const pEnd = pSectNode->EndOfSectionNode(); + const SwNodeIndex aSectIdx( *pEnd, 1 ); + if(aSectIdx.GetNode().IsTextNode()) + { + SwPaM aAfter(aSectIdx); + bRet = GetDoc()->getIDocumentContentOperations().DelFullPara( aAfter ); + } + } + if(!bRet) + { + throw lang::IllegalArgumentException(); + } +} + +void SAL_CALL +SwXText::removeTextContent( + const uno::Reference< text::XTextContent > & xContent) +{ + // forward: need no solar mutex here + if(!xContent.is()) + throw uno::RuntimeException("first parameter invalid"); + xContent->dispose(); +} + +uno::Reference< text::XText > SAL_CALL +SwXText::getText() +{ + SolarMutexGuard aGuard; + comphelper::ProfileZone aZone("SwXText::getText"); + + const uno::Reference< text::XText > xRet(this); + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::getStart() +{ + SolarMutexGuard aGuard; + + const rtl::Reference< SwXTextCursor > xRef = createXTextCursor(); + if(!xRef.is()) + throw uno::RuntimeException(cInvalidObject); + xRef->gotoStart(false); + return static_cast<text::XWordCursor*>(xRef.get()); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::getEnd() +{ + SolarMutexGuard aGuard; + + const rtl::Reference< SwXTextCursor > xRef = createXTextCursor(); + if(!xRef.is()) + throw uno::RuntimeException(cInvalidObject); + xRef->gotoEnd(false); + return static_cast<text::XWordCursor*>(xRef.get()); +} + +OUString SAL_CALL SwXText::getString() +{ + SolarMutexGuard aGuard; + + const rtl::Reference< SwXTextCursor > xRet = createXTextCursor(); + if(!xRet.is()) + { + SAL_WARN("sw.uno", "cursor was not created in getString() call. Returning empty string."); + return OUString(); + } + xRet->gotoEnd(true); + return xRet->getString(); +} + +void SAL_CALL +SwXText::setString(const OUString& rString) +{ + SolarMutexGuard aGuard; + + if (!GetDoc()) + throw uno::RuntimeException(cInvalidObject); + + const SwStartNode* pStartNode = GetStartNode(); + if (!pStartNode) + { + throw uno::RuntimeException(); + } + + GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr); + //insert an empty paragraph at the start and at the end to ensure that + //all tables and sections can be removed by the selecting text::XTextCursor + if (CursorType::Meta != m_pImpl->m_eType) + { + SwPosition aStartPos(*pStartNode); + const SwEndNode* pEnd = pStartNode->EndOfSectionNode(); + SwNodeIndex aEndIdx(*pEnd); + --aEndIdx; + //the inserting of nodes should only be done if really necessary + //to prevent #97924# (removes paragraph attributes when setting the text + //e.g. of a table cell + bool bInsertNodes = false; + SwNodeIndex aStartIdx(*pStartNode); + do + { + ++aStartIdx; + SwNode& rCurrentNode = aStartIdx.GetNode(); + if(rCurrentNode.GetNodeType() == SwNodeType::Section + ||rCurrentNode.GetNodeType() == SwNodeType::Table) + { + bInsertNodes = true; + break; + } + } + while(aStartIdx < aEndIdx); + if(bInsertNodes) + { + GetDoc()->getIDocumentContentOperations().AppendTextNode( aStartPos ); + SwPaM aPam(aEndIdx.GetNode()); + GetDoc()->getIDocumentContentOperations().AppendTextNode( *aPam.Start() ); + } + } + + const rtl::Reference< SwXTextCursor > xRet = createXTextCursor(); + if(!xRet.is()) + { + GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); + throw uno::RuntimeException(cInvalidObject); + } + xRet->gotoEnd(true); + xRet->setString(rString); + GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); +} + +//FIXME why is CheckForOwnMember duplicated in some insert methods? +// Description: Checks if pRange/pCursor are member of the same text interface. +// Only one of the pointers has to be set! +bool SwXText::Impl::CheckForOwnMember( + const SwPaM & rPaM) +{ + const rtl::Reference< SwXTextCursor > xOwnCursor(m_rThis.createXTextCursor()); + const SwStartNode* pOwnStartNode = + xOwnCursor->GetPaM()->GetPointNode().StartOfSectionNode(); + SwStartNodeType eSearchNodeType = SwNormalStartNode; + switch (m_eType) + { + case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break; + case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break; + case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break; + case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break; + case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break; + //case CURSOR_INVALID: + //case CursorType::Body: + default: + ; + } + + const SwNode& rSrcNode = rPaM.GetPointNode(); + const SwStartNode* pTmp = rSrcNode.FindSttNodeByType(eSearchNodeType); + + // skip SectionNodes / TableNodes to be able to compare across table/section boundaries + while (pTmp + && (pTmp->IsSectionNode() || pTmp->IsTableNode() + || (m_eType != CursorType::TableText + && pTmp->GetStartNodeType() == SwTableBoxStartNode))) + { + pTmp = pTmp->StartOfSectionNode(); + } + + while (pOwnStartNode->IsSectionNode() || pOwnStartNode->IsTableNode() + || (m_eType != CursorType::TableText + && pOwnStartNode->GetStartNodeType() == SwTableBoxStartNode)) + { + pOwnStartNode = pOwnStartNode->StartOfSectionNode(); + } + + //this checks if (this) and xRange are in the same text::XText interface + return (pOwnStartNode == pTmp); +} + +sal_Int16 +SwXText::Impl::ComparePositions( + const uno::Reference<text::XTextRange>& xPos1, + const uno::Reference<text::XTextRange>& xPos2) +{ + SwUnoInternalPaM aPam1(*m_pDoc); + SwUnoInternalPaM aPam2(*m_pDoc); + + if (!::sw::XTextRangeToSwPaM(aPam1, xPos1) || + !::sw::XTextRangeToSwPaM(aPam2, xPos2)) + { + throw lang::IllegalArgumentException(); + } + if (!CheckForOwnMember(aPam1) || !CheckForOwnMember(aPam2)) + { + throw lang::IllegalArgumentException(); + } + + sal_Int16 nCompare = 0; + SwPosition const*const pStart1 = aPam1.Start(); + SwPosition const*const pStart2 = aPam2.Start(); + if (*pStart1 < *pStart2) + { + nCompare = 1; + } + else if (*pStart1 > *pStart2) + { + nCompare = -1; + } + else + { + OSL_ENSURE(*pStart1 == *pStart2, + "SwPositions should be equal here"); + nCompare = 0; + } + + return nCompare; +} + +sal_Int16 SAL_CALL +SwXText::compareRegionStarts( + const uno::Reference<text::XTextRange>& xRange1, + const uno::Reference<text::XTextRange>& xRange2) +{ + SolarMutexGuard aGuard; + + if (!xRange1.is() || !xRange2.is()) + { + throw lang::IllegalArgumentException(); + } + const uno::Reference<text::XTextRange> xStart1 = xRange1->getStart(); + const uno::Reference<text::XTextRange> xStart2 = xRange2->getStart(); + + return m_pImpl->ComparePositions(xStart1, xStart2); +} + +sal_Int16 SAL_CALL +SwXText::compareRegionEnds( + const uno::Reference<text::XTextRange>& xRange1, + const uno::Reference<text::XTextRange>& xRange2) +{ + SolarMutexGuard aGuard; + + if (!xRange1.is() || !xRange2.is()) + { + throw lang::IllegalArgumentException(); + } + uno::Reference<text::XTextRange> xEnd1 = xRange1->getEnd(); + uno::Reference<text::XTextRange> xEnd2 = xRange2->getEnd(); + + return m_pImpl->ComparePositions(xEnd1, xEnd2); +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXText::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xInfo = + m_pImpl->m_rPropSet.getPropertySetInfo(); + return xInfo; +} + +void SAL_CALL +SwXText::setPropertyValue(const OUString& /*aPropertyName*/, + const uno::Any& /*aValue*/) +{ + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL +SwXText::getPropertyValue( + const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + if(!IsValid()) + { + throw uno::RuntimeException(); + } + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + throw beans::UnknownPropertyException("Unknown property: " + rPropertyName); + + uno::Any aRet; + switch (pEntry->nWID) + { +// no code necessary - the redline is always located at the end node +// case FN_UNO_REDLINE_NODE_START: +// break; + case FN_UNO_REDLINE_NODE_END: + { + const SwRedlineTable& rRedTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); + const size_t nRedTableCount = rRedTable.size(); + if (nRedTableCount > 0) + { + SwStartNode const*const pStartNode = GetStartNode(); + const SwNode& rOwnIndex = *pStartNode->EndOfSectionNode(); + for (size_t nRed = 0; nRed < nRedTableCount; ++nRed) + { + SwRangeRedline const*const pRedline = rRedTable[nRed]; + SwPosition const*const pRedStart = pRedline->Start(); + const SwNode& rRedNode = pRedStart->GetNode(); + if (rOwnIndex == rRedNode) + { + aRet <<= SwXRedlinePortion::CreateRedlineProperties( + *pRedline, true); + break; + } + } + } + } + break; + } + return aRet; +} + +void SAL_CALL +SwXText::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXText::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXText::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXText::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXText::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXText::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXText::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXText::removeVetoableChangeListener(): not implemented"); +} + +namespace +{ +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::finishParagraph( + const uno::Sequence< beans::PropertyValue > & rProperties) +{ + SolarMutexGuard g; + + return m_pImpl->finishOrAppendParagraph(rProperties, uno::Reference< text::XTextRange >()); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::finishParagraphInsert( + const uno::Sequence< beans::PropertyValue > & rProperties, + const uno::Reference< text::XTextRange >& xInsertPosition) +{ + SolarMutexGuard g; + + return m_pImpl->finishOrAppendParagraph(rProperties, xInsertPosition); +} + +rtl::Reference<SwXParagraph> +SwXText::Impl::finishOrAppendParagraph( + const uno::Sequence< beans::PropertyValue > & rProperties, + const uno::Reference< text::XTextRange >& xInsertPosition) +{ + if (!m_bIsValid) + { + throw uno::RuntimeException(); + } + + const SwStartNode* pStartNode = m_rThis.GetStartNode(); + if(!pStartNode) + { + throw uno::RuntimeException(); + } + + rtl::Reference<SwXParagraph> xRet; + bool bIllegalException = false; + bool bRuntimeException = false; + OUString sMessage; + m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START , nullptr); + // find end node, go backward - don't skip tables because the new + // paragraph has to be the last node + //aPam.Move( fnMoveBackward, GoInNode ); + SwPaM aPam(*pStartNode->EndOfSectionNode(), SwNodeOffset(-1)); + // If we got a position reference, then the insert point is not the end of + // the document. + if (xInsertPosition.is()) + { + SwUnoInternalPaM aStartPam(*m_rThis.GetDoc()); + ::sw::XTextRangeToSwPaM(aStartPam, xInsertPosition); + aPam = aStartPam; + aPam.SetMark(); + } + m_pDoc->getIDocumentContentOperations().AppendTextNode( *aPam.GetPoint() ); + // remove attributes from the previous paragraph + m_pDoc->ResetAttrs(aPam); + // in case of finishParagraph the PaM needs to be moved to the + // previous paragraph + aPam.Move( fnMoveBackward, GoInNode ); + + try + { + SfxItemPropertySet const*const pParaPropSet = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH); + + SwUnoCursorHelper::SetPropertyValues(aPam, *pParaPropSet, rProperties); + + // tdf#127616 keep direct character formatting of empty paragraphs, + // if character style of the paragraph sets also the same attributes + if (aPam.Start()->GetNode().GetTextNode()->Len() == 0) + { + auto itCharStyle = std::find_if(rProperties.begin(), rProperties.end(), [](const beans::PropertyValue& rValue) + { + return rValue.Name == "CharStyleName"; + }); + if ( itCharStyle != rProperties.end() ) + { + for (const auto& rValue : rProperties) + { + if ( rValue != *itCharStyle && rValue.Name.startsWith("Char") ) + { + SwUnoCursorHelper::SetPropertyValue(aPam, *pParaPropSet, rValue.Name, rValue.Value); + } + } + } + } + } + catch (const lang::IllegalArgumentException& rIllegal) + { + sMessage = rIllegal.Message; + bIllegalException = true; + } + catch (const uno::RuntimeException& rRuntime) + { + sMessage = rRuntime.Message; + bRuntimeException = true; + } + catch (const uno::Exception& rEx) + { + sMessage = rEx.Message; + bRuntimeException = true; + } + + m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); + if (bIllegalException || bRuntimeException) + { + m_pDoc->GetIDocumentUndoRedo().Undo(); + if (bIllegalException) + { + throw lang::IllegalArgumentException(sMessage, nullptr, 0); + } + else + { + throw uno::RuntimeException(sMessage); + } + } + SwTextNode *const pTextNode( aPam.Start()->GetNode().GetTextNode() ); + OSL_ENSURE(pTextNode, "no SwTextNode?"); + if (pTextNode) + { + xRet = SwXParagraph::CreateXParagraph(*m_pDoc, pTextNode, &m_rThis); + } + + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::insertTextPortion( + const OUString& rText, + const uno::Sequence< beans::PropertyValue > & + rCharacterAndParagraphProperties, + const uno::Reference<text::XTextRange>& xInsertPosition) +{ + SolarMutexGuard aGuard; + + if(!IsValid()) + { + throw uno::RuntimeException(); + } + uno::Reference< text::XTextRange > xRet; + const rtl::Reference<SwXTextCursor> xTextCursor = createXTextCursorByRange(xInsertPosition); + + bool bIllegalException = false; + bool bRuntimeException = false; + OUString sMessage; + m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); + + auto& rCursor(xTextCursor->GetCursor()); + m_pImpl->m_pDoc->DontExpandFormat( *rCursor.Start() ); + + if (!rText.isEmpty()) + { + SwNodeIndex const nodeIndex(rCursor.GetPoint()->GetNode(), -1); + const sal_Int32 nContentPos = rCursor.GetPoint()->GetContentIndex(); + SwUnoCursorHelper::DocInsertStringSplitCR( + *m_pImpl->m_pDoc, rCursor, rText, false); + SwUnoCursorHelper::SelectPam(rCursor, true); + rCursor.GetPoint()->Assign(nodeIndex.GetNode(), SwNodeOffset(+1), nContentPos); + } + + try + { + SfxItemPropertySet const*const pCursorPropSet = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR); + SwUnoCursorHelper::SetPropertyValues(rCursor, *pCursorPropSet, + rCharacterAndParagraphProperties, + SetAttrMode::NOFORMATATTR); + } + catch (const lang::IllegalArgumentException& rIllegal) + { + sMessage = rIllegal.Message; + bIllegalException = true; + } + catch (const uno::RuntimeException& rRuntime) + { + sMessage = rRuntime.Message; + bRuntimeException = true; + } + m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr); + if (bIllegalException || bRuntimeException) + { + m_pImpl->m_pDoc->GetIDocumentUndoRedo().Undo(); + if (bIllegalException) + { + throw lang::IllegalArgumentException(sMessage, nullptr, 0); + } + else + { + throw uno::RuntimeException(sMessage); + } + } + xRet = new SwXTextRange(rCursor, this); + return xRet; +} + +// Append text portions at the end of the last paragraph of the text interface. +// Support of import filters. +uno::Reference< text::XTextRange > SAL_CALL +SwXText::appendTextPortion( + const OUString& rText, + const uno::Sequence< beans::PropertyValue > & + rCharacterAndParagraphProperties) +{ + // Right now this doesn't need a guard, as it's just calling the insert + // version, that has it already. + uno::Reference<text::XTextRange> xInsertPosition = getEnd(); + return insertTextPortion(rText, rCharacterAndParagraphProperties, xInsertPosition); +} + +// enable inserting/appending text contents like graphic objects, shapes and so on to +// support import filters +uno::Reference< text::XTextRange > SAL_CALL +SwXText::insertTextContentWithProperties( + const uno::Reference< text::XTextContent >& xTextContent, + const uno::Sequence< beans::PropertyValue >& + rCharacterAndParagraphProperties, + const uno::Reference< text::XTextRange >& xInsertPosition) +{ + SolarMutexGuard aGuard; + + if (!IsValid()) + { + throw uno::RuntimeException(); + } + + SwUnoInternalPaM aPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(aPam, xInsertPosition)) + { + throw lang::IllegalArgumentException("invalid position", nullptr, 2); + } + + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, SwResId(STR_UNDO_INSERT_TEXTBOX)); + + m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, &aRewriter); + + // Any direct formatting ending at the insert position (xRange) should not + // be expanded to cover the inserted content (xContent) + // (insertTextContent() shouldn't do this, only ...WithProperties()!) + GetDoc()->DontExpandFormat( *aPam.Start() ); + + // now attach the text content here + insertTextContent( xInsertPosition, xTextContent, false ); + // now apply the properties to the anchor + if (rCharacterAndParagraphProperties.hasElements()) + { + try + { + const uno::Reference< beans::XPropertySet > xAnchor( + xTextContent->getAnchor(), uno::UNO_QUERY); + if (xAnchor.is()) + { + for (const auto& rProperty : rCharacterAndParagraphProperties) + { + xAnchor->setPropertyValue(rProperty.Name, rProperty.Value); + } + } + } + catch (const uno::Exception& e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, &aRewriter); + throw lang::WrappedTargetRuntimeException( e.Message, + uno::Reference< uno::XInterface >(), anyEx ); + } + } + m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, &aRewriter); + return xInsertPosition; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXText::appendTextContent( + const uno::Reference< text::XTextContent >& xTextContent, + const uno::Sequence< beans::PropertyValue >& rCharacterAndParagraphProperties + ) +{ + // Right now this doesn't need a guard, as it's just calling the insert + // version, that has it already. + uno::Reference<text::XTextRange> xInsertPosition = getEnd(); + return insertTextContentWithProperties(xTextContent, rCharacterAndParagraphProperties, xInsertPosition); +} + +// determine whether SwFrameFormat is a graphic node +static bool isGraphicNode(const SwFrameFormat* pFrameFormat) +{ + // safety + if( !pFrameFormat->GetContent().GetContentIdx() ) + { + return false; + } + auto index = *pFrameFormat->GetContent().GetContentIdx(); + // consider the next node -> there is the graphic stored + ++index; + return index.GetNode().IsGrfNode(); +} + +/// Determines if the at-para rAnchor is anchored at the start or end of rAnchorCheckPam. +static bool IsAtParaMatch(const SwPaM& rAnchorCheckPam, const SwFormatAnchor& rAnchor) +{ + if (rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PARA) + { + return false; + } + + if (rAnchorCheckPam.Start()->GetNode() == *rAnchor.GetAnchorNode()) + { + return true; + } + + if (rAnchorCheckPam.End()->GetNode() == *rAnchor.GetAnchorNode()) + { + SwTextNode* pEndTextNode = rAnchorCheckPam.End()->GetNode().GetTextNode(); + if (pEndTextNode && rAnchorCheckPam.End()->GetContentIndex() == pEndTextNode->Len()) + { + // rAnchorCheckPam covers the entire last text node, rAnchor is at-para, consider this + // as "inside pam" rather than "at the end of pam". + return false; + } + return true; + } + + return false; +} + +// move previously appended paragraphs into a text frames +// to support import filters +uno::Reference< text::XTextContent > SAL_CALL +SwXText::convertToTextFrame( + const uno::Reference< text::XTextRange >& xStart, + const uno::Reference< text::XTextRange >& xEnd, + const uno::Sequence< beans::PropertyValue >& rFrameProperties) +{ + SolarMutexGuard aGuard; + + if(!IsValid()) + { + throw uno::RuntimeException(); + } + // tdf#143384 recognize dummy property, that was set to make createTextCursor + // to not ignore tables. + // It is enough to use this hack only for the range start, + // because as far as I know, the range cannot end with table when this property is set. + ::sw::TextRangeMode eMode = ::sw::TextRangeMode::RequireTextNode; + for (const auto& rCellProperty : rFrameProperties) + { + if (rCellProperty.Name == "CursorNotIgnoreTables") + { + bool bAllowNonTextNode = false; + rCellProperty.Value >>= bAllowNonTextNode; + if (bAllowNonTextNode) + eMode = ::sw::TextRangeMode::AllowTableNode; + break; + } + } + uno::Reference< text::XTextContent > xRet; + std::optional<SwUnoInternalPaM> pTempStartPam(*GetDoc()); + std::optional<SwUnoInternalPaM> pEndPam(*GetDoc()); + if (!::sw::XTextRangeToSwPaM(*pTempStartPam, xStart, eMode) + || !::sw::XTextRangeToSwPaM(*pEndPam, xEnd)) + { + throw lang::IllegalArgumentException(); + } + + auto pStartPam(GetDoc()->CreateUnoCursor(*pTempStartPam->GetPoint())); + if (pTempStartPam->HasMark()) + { + pStartPam->SetMark(); + *pStartPam->GetMark() = *pTempStartPam->GetMark(); + } + pTempStartPam.reset(); + + SwXTextRange *const pStartRange = dynamic_cast<SwXTextRange*>(xStart.get()); + SwXTextRange *const pEndRange = dynamic_cast<SwXTextRange*>(xEnd.get()); + // bookmarks have to be removed before the referenced text node + // is deleted in DelFullPara + if (pStartRange) + { + pStartRange->Invalidate(); + } + if (pEndRange) + { + pEndRange->Invalidate(); + } + + m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + bool bIllegalException = false; + bool bRuntimeException = false; + OUString sMessage; + SwStartNode* pStartStartNode = pStartPam->GetPointNode().StartOfSectionNode(); + while (pStartStartNode && pStartStartNode->IsSectionNode()) + { + pStartStartNode = pStartStartNode->StartOfSectionNode(); + } + SwStartNode* pEndStartNode = pEndPam->GetPointNode().StartOfSectionNode(); + while (pEndStartNode && pEndStartNode->IsSectionNode()) + { + pEndStartNode = pEndStartNode->StartOfSectionNode(); + } + bool bParaAfterInserted = false; + bool bParaBeforeInserted = false; + ::std::optional<SwPaM> oAnchorCheckPam; + oAnchorCheckPam.emplace(*pStartPam->Start(), *pEndPam->End()); + if ( + pStartStartNode && pEndStartNode && + (pStartStartNode != pEndStartNode || pStartStartNode != GetStartNode()) + ) + { + // todo: if the start/end is in a table then insert a paragraph + // before/after, move the start/end nodes, then convert and + // remove the additional paragraphs in the end + SwTableNode * pStartTableNode(nullptr); + if (pStartStartNode->GetStartNodeType() == SwTableBoxStartNode) + { + pStartTableNode = pStartStartNode->FindTableNode(); + // Is it the same table start node than the end? + SwTableNode *const pEndStartTableNode(pEndStartNode->FindTableNode()); + while (pEndStartTableNode && pStartTableNode && + pEndStartTableNode->GetIndex() < pStartTableNode->GetIndex()) + { + SwStartNode* pStartStartTableNode = pStartTableNode->StartOfSectionNode(); + pStartTableNode = pStartStartTableNode->FindTableNode(); + } + } + if (pStartTableNode) + { + const SwNodeIndex aTableIdx( *pStartTableNode, -1 ); + SwPosition aBefore(aTableIdx); + bParaBeforeInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ); + pStartPam->DeleteMark(); + *pStartPam->GetPoint() = aBefore; + pStartStartNode = pStartPam->GetPointNode().StartOfSectionNode(); + } + if (pEndStartNode->GetStartNodeType() == SwTableBoxStartNode) + { + SwTableNode *const pEndTableNode = pEndStartNode->FindTableNode(); + SwEndNode *const pTableEnd = pEndTableNode->EndOfSectionNode(); + SwPosition aTableEnd(*pTableEnd); + bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aTableEnd ); + pEndPam->DeleteMark(); + *pEndPam->GetPoint() = aTableEnd; + pEndStartNode = pEndPam->GetPointNode().StartOfSectionNode(); + } + // now we should have the positions in the same hierarchy + if ((pStartStartNode != pEndStartNode) || + (pStartStartNode != GetStartNode())) + { + // if not - remove the additional paragraphs and throw + oAnchorCheckPam.reset(); // clear SwIndex before deleting nodes + if (bParaBeforeInserted) + { + SwCursor aDelete(*pStartPam->GetPoint(), nullptr); + *pStartPam->GetPoint() = // park it because node is deleted + SwPosition(GetDoc()->GetNodes().GetEndOfContent()); + aDelete.MovePara(GoCurrPara, fnParaStart); + aDelete.SetMark(); + aDelete.MovePara(GoCurrPara, fnParaEnd); + GetDoc()->getIDocumentContentOperations().DelFullPara(aDelete); + } + if (bParaAfterInserted) + { + SwCursor aDelete(*pEndPam->GetPoint(), nullptr); + *pEndPam->GetPoint() = // park it because node is deleted + SwPosition(GetDoc()->GetNodes().GetEndOfContent()); + aDelete.MovePara(GoCurrPara, fnParaStart); + aDelete.SetMark(); + aDelete.MovePara(GoCurrPara, fnParaEnd); + GetDoc()->getIDocumentContentOperations().DelFullPara(aDelete); + } + throw lang::IllegalArgumentException(); + } + } + + // make a selection from pStartPam to pEndPam + // If there is no content in the frame the shape is in + // it gets deleted in the DelFullPara call below, + // In this case insert a tmp text node ( we delete it later ) + if (pStartPam->Start()->GetNode() == pEndPam->Start()->GetNode() + && pStartPam->End()->GetNode() == pEndPam->End()->GetNode()) + { + SwPosition aEnd(*pStartPam->End()); + bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd ); + pEndPam->DeleteMark(); + *pEndPam->GetPoint() = aEnd; + *oAnchorCheckPam->End() = aEnd; + } + pStartPam->SetMark(); + *pStartPam->End() = *pEndPam->End(); + pEndPam.reset(); + + // see if there are frames already anchored to this node + // we have to work with the SdrObjects, as unique name is not guaranteed in their frame format + // tdf#115094: do nothing if we have a graphic node + o3tl::sorted_vector<const SdrObject*> aAnchoredObjectsByPtr; + std::set<OUString> aAnchoredObjectsByName; + for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrameFormats()->size(); ++i) + { + const SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i]; + const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor(); + // note: Word can do at-char anchors in text frames - sometimes! + // see testFlyInFly for why this checks only the edges of the selection, + // and testFloatingTablesAnchor for why it excludes pre/post table + // added nodes + if (!isGraphicNode(pFrameFormat) + && (IsAtParaMatch(*oAnchorCheckPam, rAnchor) + || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() + && ( *oAnchorCheckPam->Start() == *rAnchor.GetContentAnchor() + || *oAnchorCheckPam->End() == *rAnchor.GetContentAnchor())))) + { + if (pFrameFormat->GetName().isEmpty()) + { + aAnchoredObjectsByPtr.insert(pFrameFormat->FindSdrObject()); + } + else + { + aAnchoredObjectsByName.insert(pFrameFormat->GetName()); + } + } + } + oAnchorCheckPam.reset(); // clear SwIndex before deleting nodes + + const rtl::Reference<SwXTextFrame> xNewFrame = + SwXTextFrame::CreateXTextFrame(*m_pImpl->m_pDoc, nullptr); + try + { + for (const beans::PropertyValue& rValue : rFrameProperties) + { + xNewFrame->SwXFrame::setPropertyValue(rValue.Name, rValue.Value); + } + + { // has to be in a block to remove the SwIndexes before + // DelFullPara is called + const uno::Reference< text::XTextRange> xInsertTextRange = + new SwXTextRange(*pStartPam, this); + assert(xNewFrame->IsDescriptor()); + xNewFrame->attachToRange(xInsertTextRange, pStartPam.get()); + assert(!xNewFrame->getName().isEmpty()); + } + + SwTextNode *const pTextNode(pStartPam->GetPointNode().GetTextNode()); + assert(pTextNode); + if (!pTextNode || !pTextNode->Len()) // don't remove if it contains text! + { + { // has to be in a block to remove the SwIndexes before + // DelFullPara is called + SwPaM aMovePam( pStartPam->GetPointNode() ); + if (aMovePam.Move( fnMoveForward, GoInContent )) + { + // move the anchor to the next paragraph + SwFormatAnchor aNewAnchor(xNewFrame->GetFrameFormat()->GetAnchor()); + aNewAnchor.SetAnchor( aMovePam.Start() ); + m_pImpl->m_pDoc->SetAttr( + aNewAnchor, *xNewFrame->GetFrameFormat() ); + + // also move frames anchored to us + for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrameFormats()->size(); ++i) + { + SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i]; + if ((!pFrameFormat->GetName().isEmpty() && aAnchoredObjectsByName.find(pFrameFormat->GetName()) != aAnchoredObjectsByName.end() ) || + ( pFrameFormat->GetName().isEmpty() && aAnchoredObjectsByPtr.find(pFrameFormat->FindSdrObject()) != aAnchoredObjectsByPtr.end()) ) + { + // copy the anchor to the next paragraph + SwFormatAnchor aAnchor(pFrameFormat->GetAnchor()); + aAnchor.SetAnchor(aMovePam.Start()); + m_pImpl->m_pDoc->SetAttr(aAnchor, *pFrameFormat); + } + else + { + // if this frame is a textbox of a shape anchored to us, move this textbox too. + const auto& pTextBoxes = pFrameFormat->GetOtherTextBoxFormats(); + if (pFrameFormat->Which() == RES_FLYFRMFMT && pTextBoxes + && pTextBoxes->GetOwnerShape()) + { + const auto& rShapeAnchor = pTextBoxes->GetOwnerShape()->GetAnchor(); + if (rShapeAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR + && rShapeAnchor.GetContentAnchor() && pFrameFormat->GetAnchor().GetContentAnchor() + && pStartPam->ContainsPosition(*pFrameFormat->GetAnchor().GetContentAnchor())) + { + const SwNode& rAnchorNode + = *pFrameFormat->GetAnchor().GetAnchorNode(); + if (!(rAnchorNode.FindFooterStartNode() || rAnchorNode.FindHeaderStartNode())) + { + SwFormatAnchor aAnchor(pFrameFormat->GetAnchor()); + aAnchor.SetAnchor(aMovePam.Start()); + m_pImpl->m_pDoc->SetAttr(aAnchor, *pFrameFormat); + } + } + } + } + } + } + } + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*pStartPam); + } + } + catch (const lang::IllegalArgumentException& rIllegal) + { + sMessage = rIllegal.Message; + bIllegalException = true; + } + catch (const uno::RuntimeException& rRuntime) + { + sMessage = rRuntime.Message; + bRuntimeException = true; + } + xRet = static_cast<SwXFrame*>(xNewFrame.get()); + if (bParaBeforeInserted || bParaAfterInserted) + { + const rtl::Reference<SwXTextCursor> xFrameTextCursor = + xNewFrame->createXTextCursor(); + if (bParaBeforeInserted) + { + // todo: remove paragraph before frame + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*xFrameTextCursor->GetPaM()); + } + if (bParaAfterInserted) + { + xFrameTextCursor->gotoEnd(false); + if (!bParaBeforeInserted) + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*xFrameTextCursor->GetPaM()); + else + { + // In case the frame has a table only, the cursor points to the end of the first cell of the table. + SwPaM aPaM(*xFrameTextCursor->GetPaM()->GetPointNode().FindSttNodeByType(SwFlyStartNode)->EndOfSectionNode()); + // Now we have the end of the frame -- the node before that will be the paragraph we want to remove. + aPaM.GetPoint()->Adjust(SwNodeOffset(-1)); + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(aPaM); + } + } + } + + m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); + if (bIllegalException || bRuntimeException) + { + m_pImpl->m_pDoc->GetIDocumentUndoRedo().Undo(); + if (bIllegalException) + { + throw lang::IllegalArgumentException(sMessage, nullptr, 0); + } + else + { + throw uno::RuntimeException(sMessage); + } + } + return xRet; +} + +namespace { + +// Move previously imported paragraphs into a new text table. +struct VerticallyMergedCell +{ + std::vector<uno::Reference< beans::XPropertySet > > aCells; + sal_Int32 nLeftPosition; + bool bOpen; + + VerticallyMergedCell(uno::Reference< beans::XPropertySet > const& rxCell, + const sal_Int32 nLeft) + : nLeftPosition( nLeft ) + , bOpen( true ) + { + aCells.push_back( rxCell ); + } +}; + +} + +#define COL_POS_FUZZY 2 + +static bool lcl_SimilarPosition( const sal_Int32 nPos1, const sal_Int32 nPos2 ) +{ + return abs( nPos1 - nPos2 ) < COL_POS_FUZZY; +} + +void SwXText::Impl::ConvertCell( + const uno::Sequence< uno::Reference< text::XTextRange > > & rCell, + std::vector<SwNodeRange> & rRowNodes, + SwNodeRange *const pLastCell) +{ + if (rCell.getLength() != 2) + { + throw lang::IllegalArgumentException( + "rCell needs to contain 2 elements", + uno::Reference< text::XTextCopy >( &m_rThis ), sal_Int16( 2 ) ); + } + const uno::Reference<text::XTextRange> xStartRange = rCell[0]; + const uno::Reference<text::XTextRange> xEndRange = rCell[1]; + SwUnoInternalPaM aStartCellPam(*m_pDoc); + SwUnoInternalPaM aEndCellPam(*m_pDoc); + + // !!! TODO - PaMs in tables and sections do not work here - + // the same applies to PaMs in frames !!! + + if (!::sw::XTextRangeToSwPaM(aStartCellPam, xStartRange) || + !::sw::XTextRangeToSwPaM(aEndCellPam, xEndRange)) + { + throw lang::IllegalArgumentException( + "Start or End range cannot be resolved to a SwPaM", + uno::Reference< text::XTextCopy >( &m_rThis ), sal_Int16( 2 ) ); + } + + SwNodeRange aTmpRange(aStartCellPam.Start()->GetNode(), + aEndCellPam.End()->GetNode()); + std::optional<SwNodeRange> oCorrectedRange; + m_pDoc->GetNodes().ExpandRangeForTableBox(aTmpRange, oCorrectedRange); + + if (oCorrectedRange) + { + SwPaM aNewStartPaM(oCorrectedRange->aStart, 0); + aStartCellPam = aNewStartPaM; + + sal_Int32 nEndLen = 0; + SwTextNode * pTextNode = oCorrectedRange->aEnd.GetNode().GetTextNode(); + if (pTextNode != nullptr) + nEndLen = pTextNode->Len(); + + SwPaM aNewEndPaM(oCorrectedRange->aEnd, nEndLen); + aEndCellPam = aNewEndPaM; + + oCorrectedRange.reset(); + } + + /** check the nodes between start and end + it is allowed to have pairs of StartNode/EndNodes + */ + if (aStartCellPam.Start()->GetNode() < aEndCellPam.End()->GetNode()) + { + // increment on each StartNode and decrement on each EndNode + // we must reach zero at the end and must not go below zero + tools::Long nOpenNodeBlock = 0; + SwNodeIndex aCellIndex(aStartCellPam.Start()->GetNode()); + while (aCellIndex < aEndCellPam.End()->GetNodeIndex()) + { + if (aCellIndex.GetNode().IsStartNode()) + { + ++nOpenNodeBlock; + } + else if (aCellIndex.GetNode().IsEndNode()) + { + --nOpenNodeBlock; + } + if (nOpenNodeBlock < 0) + { + throw lang::IllegalArgumentException(); + } + ++aCellIndex; + } + if (nOpenNodeBlock != 0) + { + throw lang::IllegalArgumentException(); + } + } + + /** The vector<vector> NodeRanges has to contain consecutive nodes. + In rTableRanges the ranges don't need to be full paragraphs but + they have to follow each other. To process the ranges they + have to be aligned on paragraph borders by inserting paragraph + breaks. Non-consecutive ranges must initiate an exception. + */ + if (!pLastCell) // first cell? + { + // align the beginning - if necessary + if (aStartCellPam.Start()->GetContentIndex()) + { + m_pDoc->getIDocumentContentOperations().SplitNode(*aStartCellPam.Start(), false); + } + } + else + { + // check the predecessor + const SwNodeOffset nStartCellNodeIndex = + aStartCellPam.Start()->GetNodeIndex(); + const SwNodeOffset nLastNodeEndIndex = pLastCell->aEnd.GetIndex(); + if (nLastNodeEndIndex == nStartCellNodeIndex) + { + // same node as predecessor then equal nContent? + if (0 != aStartCellPam.Start()->GetContentIndex()) + { + throw lang::IllegalArgumentException(); + } + + m_pDoc->getIDocumentContentOperations().SplitNode(*aStartCellPam.Start(), false); + SwNodeOffset const nNewIndex(aStartCellPam.Start()->GetNodeIndex()); + if (nNewIndex != nStartCellNodeIndex) + { + // aStartCellPam now points to the 2nd node + // the last cell may *also* point to 2nd node now - fix it! + assert(nNewIndex == nStartCellNodeIndex + 1); + if (pLastCell->aEnd.GetIndex() == nNewIndex) + { + --pLastCell->aEnd; + if (pLastCell->aStart.GetIndex() == nNewIndex) + { + --pLastCell->aStart; + } + } + } + } + else if (nStartCellNodeIndex == (nLastNodeEndIndex + 1)) + { + // next paragraph - now the content index of the new should be 0 + // and of the old one should be equal to the text length + // but if it isn't we don't care - the cell is being inserted on + // the node border anyway + } + else + { + throw lang::IllegalArgumentException(); + } + } + // now check if there's a need to insert another paragraph break + if (aEndCellPam.End()->GetContentIndex() < + aEndCellPam.End()->GetNode().GetTextNode()->Len()) + { + m_pDoc->getIDocumentContentOperations().SplitNode(*aEndCellPam.End(), false); + // take care that the new start/endcell is moved to the right position + // aStartCellPam has to point to the start of the new (previous) node + // aEndCellPam has to point to the end of the new (previous) node + aStartCellPam.DeleteMark(); + aStartCellPam.Move(fnMoveBackward, GoInNode); + aStartCellPam.GetPoint()->SetContent(0); + aEndCellPam.DeleteMark(); + aEndCellPam.Move(fnMoveBackward, GoInNode); + aEndCellPam.GetPoint()->SetContent( + aEndCellPam.GetPointNode().GetTextNode()->Len() ); + } + + assert(aStartCellPam.Start()->GetContentIndex() == 0); + assert(aEndCellPam.End()->GetContentIndex() == aEndCellPam.End()->GetNode().GetTextNode()->Len()); + SwNodeRange aCellRange(aStartCellPam.Start()->GetNode(), + aEndCellPam.End()->GetNode()); + rRowNodes.push_back(aCellRange); // note: invalidates pLastCell! + + // tdf#149649 delete any fieldmarks overlapping the cell + IDocumentMarkAccess & rIDMA(*m_pDoc->getIDocumentMarkAccess()); + while (sw::mark::IFieldmark *const pMark = rIDMA.getInnerFieldmarkFor(*aStartCellPam.Start())) + { + if (pMark->GetMarkEnd() <= *aEndCellPam.End()) + { + if (pMark->GetMarkStart() < *aStartCellPam.Start()) + { + SAL_INFO("sw.uno", "deleting fieldmark overlapping table cell"); + rIDMA.deleteMark(pMark); + } + else + { + break; + } + } + else + { + SwPosition const sepPos(::sw::mark::FindFieldSep(*pMark)); + if (*aStartCellPam.Start() <= sepPos && sepPos <= *aEndCellPam.End()) + { + SAL_INFO("sw.uno", "deleting fieldmark with separator in table cell"); + rIDMA.deleteMark(pMark); + } + else + { + break; + } + } + } + while (sw::mark::IFieldmark *const pMark = rIDMA.getInnerFieldmarkFor(*aEndCellPam.End())) + { + if (*aStartCellPam.Start() <= pMark->GetMarkStart()) + { + if (*aEndCellPam.End() < pMark->GetMarkEnd()) + { + SAL_INFO("sw.uno", "deleting fieldmark overlapping table cell"); + rIDMA.deleteMark(pMark); + } + else + { + break; + } + } + else + { + SwPosition const sepPos(::sw::mark::FindFieldSep(*pMark)); + if (*aStartCellPam.Start() <= sepPos && sepPos <= *aEndCellPam.End()) + { + SAL_INFO("sw.uno", "deleting fieldmark with separator in table cell"); + rIDMA.deleteMark(pMark); + } + else + { + break; + } + } + } +} + +typedef uno::Sequence< text::TableColumnSeparator > TableColumnSeparators; + +static void +lcl_ApplyRowProperties( + uno::Sequence<beans::PropertyValue> const& rRowProperties, + uno::Any const& rRow, + TableColumnSeparators & rRowSeparators) +{ + uno::Reference< beans::XPropertySet > xRow; + rRow >>= xRow; + for (const beans::PropertyValue& rProperty : rRowProperties) + { + if ( rProperty.Name == "TableColumnSeparators" ) + { + // add the separators to access the cell's positions + // for vertical merging later + TableColumnSeparators aSeparators; + rProperty.Value >>= aSeparators; + rRowSeparators = aSeparators; + } + xRow->setPropertyValue(rProperty.Name, rProperty.Value); + } +} + +static sal_Int32 lcl_GetLeftPos(sal_Int32 nCell, TableColumnSeparators const& rRowSeparators) +{ + if(!nCell) + return 0; + if (rRowSeparators.getLength() < nCell) + return -1; + return rRowSeparators[nCell - 1].Position; +} + +static void +lcl_ApplyCellProperties( + const sal_Int32 nLeftPos, + const uno::Sequence< beans::PropertyValue >& rCellProperties, + const uno::Reference< uno::XInterface >& xCell, + std::vector<VerticallyMergedCell> & rMergedCells) +{ + const uno::Reference< beans::XPropertySet > xCellPS(xCell, uno::UNO_QUERY); + for (const auto& rCellProperty : rCellProperties) + { + const OUString & rName = rCellProperty.Name; + const uno::Any & rValue = rCellProperty.Value; + if ( rName == "VerticalMerge" ) + { + // determine left border position + // add the cell to a queue of merged cells + bool bMerge = false; + rValue >>= bMerge; + if (bMerge) + { + // 'close' all the cell with the same left position + // if separate vertical merges in the same column exist + for(auto& aMergedCell : rMergedCells) + { + if(lcl_SimilarPosition(aMergedCell.nLeftPosition, nLeftPos)) + { + aMergedCell.bOpen = false; + } + } + // add the new group of merged cells + rMergedCells.emplace_back(xCellPS, nLeftPos); + } + else + { + bool bFound = false; + SAL_WARN_IF(rMergedCells.empty(), "sw.uno", "the first merged cell is missing"); + for(auto& aMergedCell : rMergedCells) + { + if (aMergedCell.bOpen && lcl_SimilarPosition(aMergedCell.nLeftPosition, nLeftPos)) + { + aMergedCell.aCells.push_back( xCellPS ); + bFound = true; + } + } + SAL_WARN_IF(!bFound, "sw.uno", "couldn't find first vertically merged cell" ); + } + } + else + { + try + { + static const std::initializer_list<std::u16string_view> vDenylist = { + u"LeftMargin", + }; + if (std::find(vDenylist.begin(), vDenylist.end(), rName) == vDenylist.end()) + { + xCellPS->setPropertyValue(rName, rValue); + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "sw.uno", "Exception when setting cell property " << rName ); + } + } + } +} + +static void +lcl_MergeCells(std::vector<VerticallyMergedCell> & rMergedCells) +{ + for(auto& aMergedCell : rMergedCells) + { + // the first of the cells gets the number of cells set as RowSpan + // the others get the inverted number of remaining merged cells + // (3,-2,-1) + sal_Int32 nCellCount = static_cast<sal_Int32>(aMergedCell.aCells.size()); + if(nCellCount<2) + { + SAL_WARN("sw.uno", "incomplete vertical cell merge"); + continue; + } + aMergedCell.aCells.front()->setPropertyValue(UNO_NAME_ROW_SPAN, uno::Any(nCellCount--)); + nCellCount*=-1; + for(auto pxPSet = aMergedCell.aCells.begin()+1; nCellCount<0; ++pxPSet, ++nCellCount) + { + (*pxPSet)->setPropertyValue(UNO_NAME_ROW_SPAN, uno::Any(nCellCount)); + (*pxPSet)->setPropertyValue("VerticalMerge", uno::Any(true)); + } + } +} + +uno::Reference< text::XTextTable > SAL_CALL +SwXText::convertToTable( + const uno::Sequence< uno::Sequence< uno::Sequence< + uno::Reference< text::XTextRange > > > >& rTableRanges, + const uno::Sequence< uno::Sequence< uno::Sequence< + beans::PropertyValue > > >& rCellProperties, + const uno::Sequence< uno::Sequence< beans::PropertyValue > >& + rRowProperties, + const uno::Sequence< beans::PropertyValue >& rTableProperties) +{ + SolarMutexGuard aGuard; + + if(!IsValid()) + { + throw uno::RuntimeException(); + } + + IDocumentRedlineAccess & rIDRA(m_pImpl->m_pDoc->getIDocumentRedlineAccess()); + if (!IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())) + { + throw uno::RuntimeException( + "cannot convertToTable if tracked changes are hidden!"); + } + + //at first collect the text ranges as SwPaMs + const uno::Sequence< uno::Sequence< uno::Reference< text::XTextRange > > >* + pTableRanges = rTableRanges.getConstArray(); + std::vector< std::vector<SwNodeRange> > aTableNodes; + for (sal_Int32 nRow = 0; nRow < rTableRanges.getLength(); ++nRow) + { + std::vector<SwNodeRange> aRowNodes; + const uno::Sequence< uno::Reference< text::XTextRange > >* pRow = + pTableRanges[nRow].getConstArray(); + const sal_Int32 nCells(pTableRanges[nRow].getLength()); + + if (0 == nCells) // this would lead to no pLastCell below + { // and make it impossible to detect node gaps + throw lang::IllegalArgumentException(); + } + + for (sal_Int32 nCell = 0; nCell < nCells; ++nCell) + { + SwNodeRange *const pLastCell( + (nCell == 0) + ? ((nRow == 0) + ? nullptr + : &*aTableNodes.rbegin()->rbegin()) + : &*aRowNodes.rbegin()); + m_pImpl->ConvertCell(pRow[nCell], aRowNodes, pLastCell); + } + assert(!aRowNodes.empty()); + aTableNodes.push_back(aRowNodes); + } + + std::vector< TableColumnSeparators > + aRowSeparators(rRowProperties.getLength()); + std::vector<VerticallyMergedCell> aMergedCells; + + SwTable const*const pTable = m_pImpl->m_pDoc->TextToTable( aTableNodes ); + + if (!pTable) + return uno::Reference< text::XTextTable >(); + + uno::Reference<text::XTextTable> const xRet = + SwXTextTable::CreateXTextTable(pTable->GetFrameFormat()); + uno::Reference<beans::XPropertySet> const xPrSet(xRet, uno::UNO_QUERY); + // set properties to the table + // catch lang::WrappedTargetException and lang::IndexOutOfBoundsException + try + { + //apply table properties + for(const auto& rTableProperty : rTableProperties) + { + try + { + static const std::initializer_list<std::u16string_view> vDenylist = { + u"BottomBorder", + u"CharAutoKerning", + u"CharFontName", + u"CharFontNameAsian", + u"CharFontNameComplex", + u"CharHeight", + u"CharHeightAsian", + u"CharHeightComplex", + u"CharInteropGrabBag", + u"CharLocale", + u"CharLocaleAsian", + u"CharLocaleComplex", + u"HorizontalBorder", + u"LeftBorder", + u"ParaAdjust", + u"ParaBottomMargin", + u"ParaIsHyphenation", + u"ParaLineSpacing", + u"ParaOrphans", + u"ParaTopMargin", + u"ParaWidows", + u"RightBorder", + u"TopBorder", + u"VerticalBorder", + }; + if (std::find(vDenylist.begin(), vDenylist.end(), rTableProperty.Name) == vDenylist.end()) + { + xPrSet->setPropertyValue(rTableProperty.Name, rTableProperty.Value); + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "sw.uno", "Exception when setting property: " << rTableProperty.Name ); + } + } + + //apply row properties + const auto xRows = xRet->getRows(); + const sal_Int32 nLast = std::min(xRows->getCount(), rRowProperties.getLength()); + SAL_WARN_IF(nLast != rRowProperties.getLength(), "sw.uno", "not enough rows for properties"); + for(sal_Int32 nCnt = 0; nCnt < nLast; ++nCnt) + lcl_ApplyRowProperties(rRowProperties[nCnt], xRows->getByIndex(nCnt), aRowSeparators[nCnt]); + + uno::Reference<table::XCellRange> const xCR(xRet, uno::UNO_QUERY_THROW); + //apply cell properties + sal_Int32 nRow = 0; + for(const auto& rCellPropertiesForRow : rCellProperties) + { + sal_Int32 nCell = 0; + for(const auto& rCellProps : rCellPropertiesForRow) + { + lcl_ApplyCellProperties(lcl_GetLeftPos(nCell, aRowSeparators[nRow]), + rCellProps, + xCR->getCellByPosition(nCell, nRow), + aMergedCells); + ++nCell; + } + ++nRow; + } + + // now that the cell properties are set the vertical merge values + // have to be applied + lcl_MergeCells(aMergedCells); + } + catch (const lang::WrappedTargetException&) + { + } + catch (const lang::IndexOutOfBoundsException&) + { + } + + assert(SwTable::FindTable(pTable->GetFrameFormat()) == pTable); + assert(pTable->GetFrameFormat() == + dynamic_cast<SwXTextTable&>(*xRet).GetFrameFormat()); + return xRet; +} + +void SAL_CALL +SwXText::copyText( + const uno::Reference< text::XTextCopy >& xSource ) +{ + SolarMutexGuard aGuard; + + SwXText* const pSource(dynamic_cast<SwXText*>(xSource.get())); + if (!pSource) + throw uno::RuntimeException(); + + rtl::Reference< SwXTextCursor > const xCursor = pSource->createXTextCursor(); + xCursor->gotoEnd( true ); + + SwNodeIndex rNdIndex( *GetStartNode( ), 1 ); + SwPosition rPos( rNdIndex ); + // tdf#112202 need SwXText because cursor cannot select table at the start + SwTextNode * pFirstNode; + { + SwPaM temp(*pSource->GetStartNode(), *pSource->GetStartNode()->EndOfSectionNode(), SwNodeOffset(+1), SwNodeOffset(-1)); + pFirstNode = temp.GetMark()->GetNode().GetTextNode(); + if (pFirstNode) + { + temp.GetMark()->AssignStartIndex(*pFirstNode); + } + if (SwTextNode *const pNode = temp.GetPoint()->GetNode().GetTextNode()) + { + temp.GetPoint()->AssignEndIndex(*pNode); + } + // Explicitly request copy text mode, so + // sw::DocumentContentOperationsManager::CopyFlyInFlyImpl() will copy shapes anchored to + // us, even if we have only a single paragraph. + m_pImpl->m_pDoc->getIDocumentContentOperations().CopyRange(temp, rPos, SwCopyFlags::CheckPosInFly); + } + if (!pFirstNode) + { // the node at rPos was split; get rid of the first empty one so + // that the pasted table is first + auto pDelCursor(m_pImpl->m_pDoc->CreateUnoCursor(SwPosition(*GetStartNode(), SwNodeOffset(1)))); + m_pImpl->m_pDoc->getIDocumentContentOperations().DelFullPara(*pDelCursor); + } +} + +SwXBodyText::SwXBodyText(SwDoc *const pDoc) + : SwXText(pDoc, CursorType::Body) +{ +} + +SwXBodyText::~SwXBodyText() +{ +} + +OUString SAL_CALL +SwXBodyText::getImplementationName() +{ + return "SwXBodyText"; +} + +sal_Bool SAL_CALL SwXBodyText::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXBodyText::getSupportedServiceNames() +{ + return { "com.sun.star.text.Text" }; +} + +uno::Sequence< uno::Type > SAL_CALL +SwXBodyText::getTypes() +{ + const uno::Sequence< uno::Type > aTypes = SwXBodyText_Base::getTypes(); + const uno::Sequence< uno::Type > aTextTypes = SwXText::getTypes(); + return ::comphelper::concatSequences(aTypes, aTextTypes); +} + +uno::Sequence< sal_Int8 > SAL_CALL +SwXBodyText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Any SAL_CALL +SwXBodyText::queryInterface(const uno::Type& rType) +{ + const uno::Any ret = SwXText::queryInterface(rType); + return (ret.getValueType() == cppu::UnoType<void>::get()) + ? SwXBodyText_Base::queryInterface(rType) + : ret; +} + +rtl::Reference<SwXTextCursor> SwXBodyText::CreateTextCursor(const bool bIgnoreTables) +{ + if(!IsValid()) + { + return nullptr; + } + + // the cursor has to skip tables contained in this text + SwPaM aPam(GetDoc()->GetNodes().GetEndOfContent()); + aPam.Move( fnMoveBackward, GoInDoc ); + if (!bIgnoreTables) + { + SwTableNode * pTableNode = aPam.GetPointNode().FindTableNode(); + while (pTableNode) + { + aPam.GetPoint()->Assign( *pTableNode->EndOfSectionNode() ); + SwContentNode* pCont = GetDoc()->GetNodes().GoNext(aPam.GetPoint()); + pTableNode = pCont->FindTableNode(); + } + } + return new SwXTextCursor(*GetDoc(), this, CursorType::Body, *aPam.GetPoint()); +} + +rtl::Reference< SwXTextCursor > +SwXBodyText::createXTextCursor() +{ + return CreateTextCursor(); +} + +rtl::Reference< SwXTextCursor > +SwXBodyText::createXTextCursorByRange( + const uno::Reference< text::XTextRange > & xTextPosition) +{ + if(!IsValid()) + throw uno::RuntimeException(cInvalidObject); + + rtl::Reference< SwXTextCursor > aRef; + SwUnoInternalPaM aPam(*GetDoc()); + if (::sw::XTextRangeToSwPaM(aPam, xTextPosition)) + { + if ( !aPam.GetPointNode().GetTextNode() ) + throw uno::RuntimeException("Invalid text range" ); + + SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); + + SwStartNode* p1 = aPam.GetPointNode().StartOfSectionNode(); + //document starts with a section? + while(p1->IsSectionNode()) + { + p1 = p1->StartOfSectionNode(); + } + SwStartNode *const p2 = rNode.StartOfSectionNode(); + + if(p1 == p2) + { + aRef = new SwXTextCursor(*GetDoc(), this, CursorType::Body, + *aPam.GetPoint(), aPam.GetMark()); + } + } + if(!aRef.is()) + { + throw uno::RuntimeException( "End of content node doesn't have the proper start node", + uno::Reference< uno::XInterface >( *this ) ); + } + return aRef; +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXBodyText::createEnumeration() +{ + return createParagraphEnumeration(); +} + +rtl::Reference< SwXParagraphEnumeration > +SwXBodyText::createParagraphEnumeration() +{ + SolarMutexGuard aGuard; + + if (!IsValid()) + throw uno::RuntimeException(cInvalidObject); + + SwNode& rNode = GetDoc()->GetNodes().GetEndOfContent(); + SwPosition aPos(rNode); + auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); + pUnoCursor->Move(fnMoveBackward, GoInDoc); + return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::Body); +} + +uno::Type SAL_CALL +SwXBodyText::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL +SwXBodyText::hasElements() +{ + SolarMutexGuard aGuard; + + if (!IsValid()) + throw uno::RuntimeException(cInvalidObject); + + return true; +} + +class SwXHeadFootText::Impl + : public SvtListener +{ + public: + SwFrameFormat* m_pHeadFootFormat; + bool m_bIsHeader; + + Impl(SwFrameFormat& rHeadFootFormat, const bool bIsHeader) + : m_pHeadFootFormat(&rHeadFootFormat) + , m_bIsHeader(bIsHeader) + { + StartListening(m_pHeadFootFormat->GetNotifier()); + } + + SwFrameFormat* GetHeadFootFormat() const { + return m_pHeadFootFormat; + } + + SwFrameFormat& GetHeadFootFormatOrThrow() { + if (!m_pHeadFootFormat) { + throw uno::RuntimeException("SwXHeadFootText: disposed or invalid", nullptr); + } + return *m_pHeadFootFormat; + } + protected: + virtual void Notify(const SfxHint& rHint) override + { + if(rHint.GetId() == SfxHintId::Dying) + m_pHeadFootFormat = nullptr; + } +}; + +rtl::Reference<SwXHeadFootText> SwXHeadFootText::CreateXHeadFootText( + SwFrameFormat& rHeadFootFormat, + const bool bIsHeader) +{ + // re-use existing SwXHeadFootText + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXHeadFootText> xText = dynamic_cast<SwXHeadFootText*>(rHeadFootFormat.GetXObject().get().get()); + if(!xText.is()) + { + xText = new SwXHeadFootText(rHeadFootFormat, bIsHeader); + rHeadFootFormat.SetXObject(static_cast<cppu::OWeakObject*>(xText.get())); + } + return xText; +} + +SwXHeadFootText::SwXHeadFootText(SwFrameFormat& rHeadFootFormat, const bool bIsHeader) + : SwXText( + rHeadFootFormat.GetDoc(), + bIsHeader ? CursorType::Header : CursorType::Footer) + , m_pImpl(new SwXHeadFootText::Impl(rHeadFootFormat, bIsHeader)) +{ +} + +SwXHeadFootText::~SwXHeadFootText() +{ } + +OUString SAL_CALL +SwXHeadFootText::getImplementationName() +{ + return {"SwXHeadFootText"}; +} + +sal_Bool SAL_CALL SwXHeadFootText::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL +SwXHeadFootText::getSupportedServiceNames() +{ + return {"com.sun.star.text.Text"}; +} + +const SwStartNode* SwXHeadFootText::GetStartNode() const +{ + const SwStartNode* pSttNd = nullptr; + SwFrameFormat* const pHeadFootFormat = m_pImpl->GetHeadFootFormat(); + if(pHeadFootFormat) + { + const SwFormatContent& rFlyContent = pHeadFootFormat->GetContent(); + if(rFlyContent.GetContentIdx()) + { + pSttNd = rFlyContent.GetContentIdx()->GetNode().GetStartNode(); + } + } + return pSttNd; +} + +uno::Sequence<uno::Type> SAL_CALL SwXHeadFootText::getTypes() +{ + return ::comphelper::concatSequences( + SwXHeadFootText_Base::getTypes(), + SwXText::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL SwXHeadFootText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Any SAL_CALL SwXHeadFootText::queryInterface(const uno::Type& rType) +{ + const uno::Any ret = SwXHeadFootText_Base::queryInterface(rType); + return (ret.getValueType() == cppu::UnoType<void>::get()) + ? SwXText::queryInterface(rType) + : ret; +} + +rtl::Reference<SwXTextCursor> SwXHeadFootText::CreateTextCursor(const bool bIgnoreTables) +{ + SwFrameFormat & rHeadFootFormat( m_pImpl->GetHeadFootFormatOrThrow() ); + + const SwFormatContent& rFlyContent = rHeadFootFormat.GetContent(); + const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); + SwPosition aPos(rNode); + rtl::Reference<SwXTextCursor> pXCursor = new SwXTextCursor(*GetDoc(), this, + (m_pImpl->m_bIsHeader) ? CursorType::Header : CursorType::Footer, aPos); + auto& rUnoCursor(pXCursor->GetCursor()); + rUnoCursor.Move(fnMoveForward, GoInNode); + + // save current start node to be able to check if there is content + // after the table - otherwise the cursor would be in the body text! + SwStartNode const*const pOwnStartNode = rNode.FindSttNodeByType( + (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); + + if (!bIgnoreTables) + { + // is there a table here? + SwTableNode* pTableNode = rUnoCursor.GetPointNode().FindTableNode(); + while (pTableNode) + { + rUnoCursor.GetPoint()->Assign(*pTableNode->EndOfSectionNode()); + SwContentNode* pCont = GetDoc()->GetNodes().GoNext(rUnoCursor.GetPoint()); + pTableNode = pCont->FindTableNode(); + } + } + SwStartNode const*const pNewStartNode = rUnoCursor.GetPointNode().FindSttNodeByType( + (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); + if (!pNewStartNode || (pNewStartNode != pOwnStartNode)) + { + throw uno::RuntimeException("no text available"); + } + return pXCursor; +} + +rtl::Reference< SwXTextCursor > +SwXHeadFootText::createXTextCursor() +{ + return CreateTextCursor(false); +} + +rtl::Reference<SwXTextCursor> SwXHeadFootText::createXTextCursorByRange( + const uno::Reference<text::XTextRange>& xTextPosition) +{ + SwFrameFormat& rHeadFootFormat( m_pImpl->GetHeadFootFormatOrThrow() ); + + SwUnoInternalPaM aPam(*GetDoc()); + if (!sw::XTextRangeToSwPaM(aPam, xTextPosition)) + { + throw uno::RuntimeException(cInvalidObject); + } + + SwNode& rNode = rHeadFootFormat.GetContent().GetContentIdx()->GetNode(); + SwPosition aPos(rNode); + SwPaM aHFPam(aPos); + aHFPam.Move(fnMoveForward, GoInNode); + SwStartNode* const pOwnStartNode = aHFPam.GetPointNode().FindSttNodeByType( + (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); + SwStartNode* const p1 = aPam.GetPointNode().FindSttNodeByType( + (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode); + if (p1 == pOwnStartNode) + { + return new SwXTextCursor( + *GetDoc(), + this, + (m_pImpl->m_bIsHeader) ? CursorType::Header : CursorType::Footer, + *aPam.GetPoint(), aPam.GetMark()); + } + return nullptr; +} + +uno::Reference<container::XEnumeration> SAL_CALL SwXHeadFootText::createEnumeration() +{ + SolarMutexGuard aGuard; + SwFrameFormat& rHeadFootFormat(m_pImpl->GetHeadFootFormatOrThrow()); + + const SwFormatContent& rFlyContent = rHeadFootFormat.GetContent(); + const SwNode& rNode = rFlyContent.GetContentIdx()->GetNode(); + SwPosition aPos(rNode); + auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); + pUnoCursor->Move(fnMoveForward, GoInNode); + return SwXParagraphEnumeration::Create( + this, + pUnoCursor, + (m_pImpl->m_bIsHeader) + ? CursorType::Header + : CursorType::Footer); +} + +uno::Type SAL_CALL SwXHeadFootText::getElementType() + { return cppu::UnoType<text::XTextRange>::get(); } + +sal_Bool SAL_CALL SwXHeadFootText::hasElements() + { return true; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unotextmarkup.cxx b/sw/source/core/unocore/unotextmarkup.cxx new file mode 100644 index 0000000000..4bbc860160 --- /dev/null +++ b/sw/source/core/unocore/unotextmarkup.cxx @@ -0,0 +1,514 @@ +/* -*- 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 <unotextmarkup.hxx> + +#include <comphelper/servicehelper.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <svl/listener.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <SwSmartTagMgr.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/text/TextMarkupType.hpp> +#include <com/sun/star/text/TextMarkupDescriptor.hpp> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/container/XStringKeyMap.hpp> +#include <ndtxt.hxx> +#include <SwGrammarMarkUp.hxx> +#include <TextCursorHelper.hxx> +#include <GrammarContact.hxx> + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +#include <pam.hxx> + +#include <unotextrange.hxx> +#include <modeltoviewhelper.hxx> + +using namespace ::com::sun::star; + +struct SwXTextMarkup::Impl + : public SvtListener +{ + SwTextNode* m_pTextNode; + ModelToViewHelper const m_ConversionMap; + + Impl(SwTextNode* const pTextNode, ModelToViewHelper aMap) + : m_pTextNode(pTextNode) + , m_ConversionMap(std::move(aMap)) + { + if(m_pTextNode) + StartListening(pTextNode->GetNotifier()); + } + + virtual void Notify(const SfxHint& rHint) override; +}; + +SwXTextMarkup::SwXTextMarkup( + SwTextNode *const pTextNode, const ModelToViewHelper& rMap) + : m_pImpl(new Impl(pTextNode, rMap)) +{ +} + +SwXTextMarkup::~SwXTextMarkup() +{ +} + +SwTextNode* SwXTextMarkup::GetTextNode() +{ + return m_pImpl->m_pTextNode; +} + +void SwXTextMarkup::ClearTextNode() +{ + m_pImpl->m_pTextNode = nullptr; + m_pImpl->EndListeningAll(); +} + +const ModelToViewHelper& SwXTextMarkup::GetConversionMap() const +{ + return m_pImpl->m_ConversionMap; +} + +uno::Reference< container::XStringKeyMap > SAL_CALL SwXTextMarkup::getMarkupInfoContainer() +{ + return new SwXStringKeyMap; +} + +void SAL_CALL SwXTextMarkup::commitTextRangeMarkup(::sal_Int32 nType, const OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange, + const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + + if (auto pRange = dynamic_cast<SwXTextRange*>(xRange.get())) + { + SwDoc& rDoc = pRange->GetDoc(); + + SwUnoInternalPaM aPam(rDoc); + + ::sw::XTextRangeToSwPaM(aPam, xRange); + + auto [startPos, endPos] = aPam.StartEnd(); // SwPosition* + + commitStringMarkup (nType, aIdentifier, startPos->GetContentIndex(), endPos->GetContentIndex() - startPos->GetContentIndex(), xMarkupInfoContainer); + } + else if (auto pCursor = dynamic_cast<OTextCursorHelper*>(xRange.get())) + { + SwPaM & rPam(*pCursor->GetPaM()); + + auto [startPos, endPos] = rPam.StartEnd(); // SwPosition* + + commitStringMarkup (nType, aIdentifier, startPos->GetContentIndex(), endPos->GetContentIndex() - startPos->GetContentIndex(), xMarkupInfoContainer); + } +} + +void SAL_CALL SwXTextMarkup::commitStringMarkup( + ::sal_Int32 nType, + const OUString & rIdentifier, + ::sal_Int32 nStart, + ::sal_Int32 nLength, + const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + + // paragraph already dead or modified? + if (!m_pImpl->m_pTextNode || nLength <= 0) + return; + + if ( nType == text::TextMarkupType::SMARTTAG && + !SwSmartTagMgr::Get().IsSmartTagTypeEnabled( rIdentifier ) ) + return; + + // get appropriate list to use... + SwWrongList* pWList = nullptr; + bool bRepaint = false; + if ( nType == text::TextMarkupType::SPELLCHECK ) + { + pWList = m_pImpl->m_pTextNode->GetWrong(); + if ( !pWList ) + { + pWList = new SwWrongList( WRONGLIST_SPELL ); + m_pImpl->m_pTextNode->SetWrong( std::unique_ptr<SwWrongList>(pWList) ); + } + } + else if ( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) + { + sw::GrammarContact* pGrammarContact = sw::getGrammarContactFor(*m_pImpl->m_pTextNode); + if( pGrammarContact ) + { + pWList = pGrammarContact->getGrammarCheck(*m_pImpl->m_pTextNode, true); + OSL_ENSURE( pWList, "GrammarContact _has_ to deliver a wrong list" ); + } + else + { + pWList = m_pImpl->m_pTextNode->GetGrammarCheck(); + if ( !pWList ) + { + m_pImpl->m_pTextNode->SetGrammarCheck( std::make_unique<SwGrammarMarkUp>() ); + pWList = m_pImpl->m_pTextNode->GetGrammarCheck(); + } + } + bRepaint = pWList == m_pImpl->m_pTextNode->GetGrammarCheck(); + if( pWList->GetBeginInv() < COMPLETE_STRING ) + static_cast<SwGrammarMarkUp*>(pWList)->ClearGrammarList(); + } + else if ( nType == text::TextMarkupType::SMARTTAG ) + { + pWList = m_pImpl->m_pTextNode->GetSmartTags(); + if ( !pWList ) + { + pWList = new SwWrongList( WRONGLIST_SMARTTAG ); + m_pImpl->m_pTextNode->SetSmartTags( std::unique_ptr<SwWrongList>(pWList) ); + } + } + else + { + OSL_FAIL( "Unknown mark-up type" ); + return; + } + + const ModelToViewHelper::ModelPosition aStartPos = + m_pImpl->m_ConversionMap.ConvertToModelPosition( nStart ); + const ModelToViewHelper::ModelPosition aEndPos = + m_pImpl->m_ConversionMap.ConvertToModelPosition( nStart + nLength - 1); + + const bool bStartInField = aStartPos.mbIsField; + const bool bEndInField = aEndPos.mbIsField; + bool bCommit = false; + + if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos ) + { + nStart = aStartPos.mnSubPos; + const sal_Int32 nFieldPosModel = aStartPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + + SwWrongList* pSubList = pWList->SubList( nInsertPos ); + if ( !pSubList ) + { + if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) + pSubList = new SwGrammarMarkUp(); + else + pSubList = new SwWrongList( pWList->GetWrongListType() ); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + + pWList = pSubList; + bCommit = true; + } + else if ( !bStartInField && !bEndInField ) + { + nStart = aStartPos.mnPos; + bCommit = true; + nLength = aEndPos.mnPos + 1 - aStartPos.mnPos; + } + else if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) + { + bCommit = true; + nStart = aStartPos.mnPos; + sal_Int32 nEnd = aEndPos.mnPos; + if( bStartInField && nType != text::TextMarkupType::SENTENCE ) + { + const sal_Int32 nFieldPosModel = aStartPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + SwWrongList* pSubList = pWList->SubList( nInsertPos ); + if ( !pSubList ) + { + pSubList = new SwGrammarMarkUp(); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + const sal_Int32 nTmpStart = + m_pImpl->m_ConversionMap.ConvertToViewPosition(aStartPos.mnPos); + const sal_Int32 nTmpLen = + m_pImpl->m_ConversionMap.ConvertToViewPosition(aStartPos.mnPos + 1) + - nTmpStart - aStartPos.mnSubPos; + if( nTmpLen > 0 ) + { + pSubList->Insert( rIdentifier, xMarkupInfoContainer, aStartPos.mnSubPos, nTmpLen ); + } + ++nStart; + } + if( bEndInField && nType != text::TextMarkupType::SENTENCE ) + { + const sal_Int32 nFieldPosModel = aEndPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + SwWrongList* pSubList = pWList->SubList( nInsertPos ); + if ( !pSubList ) + { + pSubList = new SwGrammarMarkUp(); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + const sal_Int32 nTmpLen = aEndPos.mnSubPos + 1; + pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, nTmpLen ); + } + else + ++nEnd; + if( nEnd > nStart ) + nLength = nEnd - nStart; + else + bCommit = false; + } + + if ( bCommit ) + { + if( nType == text::TextMarkupType::SENTENCE ) + static_cast<SwGrammarMarkUp*>(pWList)->setSentence( nStart ); + else + pWList->Insert( rIdentifier, xMarkupInfoContainer, nStart, nLength ); + } + + if( bRepaint ) + sw::finishGrammarCheckFor(*m_pImpl->m_pTextNode); +} + +static void lcl_commitGrammarMarkUp( + const ModelToViewHelper& rConversionMap, + SwGrammarMarkUp* pWList, + ::sal_Int32 nType, + const OUString & rIdentifier, + ::sal_Int32 nStart, + ::sal_Int32 nLength, + const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) +{ + OSL_ENSURE( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE, "Wrong mark-up type" ); + const ModelToViewHelper::ModelPosition aStartPos = + rConversionMap.ConvertToModelPosition( nStart ); + const ModelToViewHelper::ModelPosition aEndPos = + rConversionMap.ConvertToModelPosition( nStart + nLength - 1); + + const bool bStartInField = aStartPos.mbIsField; + const bool bEndInField = aEndPos.mbIsField; + bool bCommit = false; + + if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos ) + { + nStart = aStartPos.mnSubPos; + const sal_Int32 nFieldPosModel = aStartPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + + SwGrammarMarkUp* pSubList = static_cast<SwGrammarMarkUp*>(pWList->SubList( nInsertPos )); + if ( !pSubList ) + { + pSubList = new SwGrammarMarkUp(); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + + pWList = pSubList; + bCommit = true; + } + else if ( !bStartInField && !bEndInField ) + { + nStart = aStartPos.mnPos; + bCommit = true; + nLength = aEndPos.mnPos + 1 - aStartPos.mnPos; + } + else + { + bCommit = true; + nStart = aStartPos.mnPos; + sal_Int32 nEnd = aEndPos.mnPos; + if( bStartInField && nType != text::TextMarkupType::SENTENCE ) + { + const sal_Int32 nFieldPosModel = aStartPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + SwGrammarMarkUp* pSubList = static_cast<SwGrammarMarkUp*>(pWList->SubList( nInsertPos )); + if ( !pSubList ) + { + pSubList = new SwGrammarMarkUp(); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + const sal_Int32 nTmpStart = rConversionMap.ConvertToViewPosition( aStartPos.mnPos ); + const sal_Int32 nTmpLen = rConversionMap.ConvertToViewPosition( aStartPos.mnPos + 1 ) + - nTmpStart - aStartPos.mnSubPos; + if( nTmpLen > 0 ) + pSubList->Insert( rIdentifier, xMarkupInfoContainer, aStartPos.mnSubPos, nTmpLen ); + ++nStart; + } + if( bEndInField && nType != text::TextMarkupType::SENTENCE ) + { + const sal_Int32 nFieldPosModel = aEndPos.mnPos; + const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); + SwGrammarMarkUp* pSubList = static_cast<SwGrammarMarkUp*>(pWList->SubList( nInsertPos )); + if ( !pSubList ) + { + pSubList = new SwGrammarMarkUp(); + pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); + } + const sal_Int32 nTmpLen = aEndPos.mnSubPos + 1; + pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, nTmpLen ); + } + else + ++nEnd; + if( nEnd > nStart ) + nLength = nEnd - nStart; + else + bCommit = false; + } + + if ( bCommit ) + { + if( nType == text::TextMarkupType::SENTENCE ) + pWList->setSentence( nStart+nLength ); + else + pWList->Insert( rIdentifier, xMarkupInfoContainer, nStart, nLength ); + } +} + +void SAL_CALL SwXTextMarkup::commitMultiTextMarkup( + const uno::Sequence< text::TextMarkupDescriptor > &rMarkups ) +{ + SolarMutexGuard aGuard; + + // paragraph already dead or modified? + if (!m_pImpl->m_pTextNode) + return; + + // for grammar checking there should be exactly one sentence markup + // and 0..n grammar markups. + // Different markups are not expected but may be applied anyway since + // that should be no problem... + // but it has to be implemented, at the moment only this function is for + // grammar markups and sentence markup only! + const text::TextMarkupDescriptor *pSentenceMarkUp = nullptr; + for( const text::TextMarkupDescriptor &rDesc : rMarkups ) + { + if (rDesc.nType == text::TextMarkupType::SENTENCE) + { + if (pSentenceMarkUp != nullptr) + throw lang::IllegalArgumentException(); // there is already one sentence markup + pSentenceMarkUp = &rDesc; + } + else if( rDesc.nType != text::TextMarkupType::PROOFREADING ) + return; + } + + if( pSentenceMarkUp == nullptr ) + return; + + // get appropriate list to use... + SwGrammarMarkUp* pWList = nullptr; + bool bRepaint = false; + sw::GrammarContact* pGrammarContact = sw::getGrammarContactFor(*m_pImpl->m_pTextNode); + if( pGrammarContact ) + { + pWList = pGrammarContact->getGrammarCheck(*m_pImpl->m_pTextNode, true); + OSL_ENSURE( pWList, "GrammarContact _has_ to deliver a wrong list" ); + } + else + { + pWList = m_pImpl->m_pTextNode->GetGrammarCheck(); + if ( !pWList ) + { + m_pImpl->m_pTextNode->SetGrammarCheck( std::make_unique<SwGrammarMarkUp>() ); + pWList = m_pImpl->m_pTextNode->GetGrammarCheck(); + pWList->SetInvalid( 0, COMPLETE_STRING ); + } + } + bRepaint = pWList == m_pImpl->m_pTextNode->GetGrammarCheck(); + + bool bAcceptGrammarError = false; + if( pWList->GetBeginInv() < COMPLETE_STRING ) + { + const ModelToViewHelper::ModelPosition aSentenceEnd = + m_pImpl->m_ConversionMap.ConvertToModelPosition( + pSentenceMarkUp->nOffset + pSentenceMarkUp->nLength ); + bAcceptGrammarError = aSentenceEnd.mnPos > pWList->GetBeginInv(); + pWList->ClearGrammarList( aSentenceEnd.mnPos ); + } + + if( bAcceptGrammarError ) + { + for( const text::TextMarkupDescriptor &rDesc : rMarkups ) + { + lcl_commitGrammarMarkUp(m_pImpl->m_ConversionMap, pWList, rDesc.nType, + rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer ); + } + } + else + { + bRepaint = false; + const text::TextMarkupDescriptor &rDesc = *pSentenceMarkUp; + lcl_commitGrammarMarkUp(m_pImpl->m_ConversionMap, pWList, rDesc.nType, + rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer ); + } + + if( bRepaint ) + sw::finishGrammarCheckFor(*m_pImpl->m_pTextNode); +} + +void SwXTextMarkup::Impl::Notify(const SfxHint& rHint) +{ + DBG_TESTSOLARMUTEX(); + if(rHint.GetId() == SfxHintId::Dying) + { + m_pTextNode = nullptr; + } +} + +SwXStringKeyMap::SwXStringKeyMap() +{ +} + +uno::Any SAL_CALL SwXStringKeyMap::getValue(const OUString & aKey) +{ + std::map< OUString, uno::Any >::const_iterator aIter = maMap.find( aKey ); + if ( aIter == maMap.end() ) + throw container::NoSuchElementException(); + + return (*aIter).second; +} + +sal_Bool SAL_CALL SwXStringKeyMap::hasValue(const OUString & aKey) +{ + return maMap.find( aKey ) != maMap.end(); +} + +void SAL_CALL SwXStringKeyMap::insertValue(const OUString & aKey, const uno::Any & aValue) +{ + std::map< OUString, uno::Any >::const_iterator aIter = maMap.find( aKey ); + if ( aIter != maMap.end() ) + throw container::ElementExistException(); + + maMap[ aKey ] = aValue; +} + +::sal_Int32 SAL_CALL SwXStringKeyMap::getCount() +{ + return maMap.size(); +} + +OUString SAL_CALL SwXStringKeyMap::getKeyByIndex(::sal_Int32 nIndex) +{ + if ( o3tl::make_unsigned(nIndex) >= maMap.size() ) + throw lang::IndexOutOfBoundsException(); + + return OUString(); +} + +uno::Any SAL_CALL SwXStringKeyMap::getValueByIndex(::sal_Int32 nIndex) +{ + if ( o3tl::make_unsigned(nIndex) >= maMap.size() ) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |