diff options
Diffstat (limited to 'svx/source/xoutdev')
-rw-r--r-- | svx/source/xoutdev/XPropertyEntry.cxx | 30 | ||||
-rw-r--r-- | svx/source/xoutdev/_xoutbmp.cxx | 428 | ||||
-rw-r--r-- | svx/source/xoutdev/_xpoly.cxx | 943 | ||||
-rw-r--r-- | svx/source/xoutdev/xattr.cxx | 3130 | ||||
-rw-r--r-- | svx/source/xoutdev/xattr2.cxx | 731 | ||||
-rw-r--r-- | svx/source/xoutdev/xattrbmp.cxx | 342 | ||||
-rw-r--r-- | svx/source/xoutdev/xpool.cxx | 242 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabbtmp.cxx | 114 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabcolr.cxx | 172 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabdash.cxx | 225 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabgrdt.cxx | 175 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabhtch.cxx | 194 | ||||
-rw-r--r-- | svx/source/xoutdev/xtable.cxx | 393 | ||||
-rw-r--r-- | svx/source/xoutdev/xtablend.cxx | 163 | ||||
-rw-r--r-- | svx/source/xoutdev/xtabptrn.cxx | 149 |
15 files changed, 7431 insertions, 0 deletions
diff --git a/svx/source/xoutdev/XPropertyEntry.cxx b/svx/source/xoutdev/XPropertyEntry.cxx new file mode 100644 index 0000000000..2791946838 --- /dev/null +++ b/svx/source/xoutdev/XPropertyEntry.cxx @@ -0,0 +1,30 @@ +/* -*- 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 <svx/XPropertyEntry.hxx> +#include <utility> + +XPropertyEntry::XPropertyEntry(OUString aPropEntryName) + : maPropEntryName(std::move(aPropEntryName)) +{ +} + +XPropertyEntry::~XPropertyEntry() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/_xoutbmp.cxx b/svx/source/xoutdev/_xoutbmp.cxx new file mode 100644 index 0000000000..18f574f51b --- /dev/null +++ b/svx/source/xoutdev/_xoutbmp.cxx @@ -0,0 +1,428 @@ +/* -*- 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 <comphelper/base64.hxx> +#include <comphelper/graphicmimetype.hxx> +#include <tools/debug.hxx> +#include <vcl/virdev.hxx> +#include <sfx2/docfile.hxx> +#include <svx/xoutbmp.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/cvtgrf.hxx> +#include <memory> + +#include <com/sun/star/beans/XPropertySet.hpp> + +constexpr OUStringLiteral FORMAT_SVG = u"svg"; +constexpr OUStringLiteral FORMAT_WMF = u"wmf"; +constexpr OUString FORMAT_EMF = u"emf"_ustr; +constexpr OUStringLiteral FORMAT_PDF = u"pdf"; + +constexpr OUString FORMAT_BMP = u"bmp"_ustr; +constexpr OUString FORMAT_GIF = u"gif"_ustr; +constexpr OUStringLiteral FORMAT_JPG = u"jpg"; +constexpr OUString FORMAT_PNG = u"png"_ustr; +constexpr OUStringLiteral FORMAT_TIF = u"tif"; +constexpr OUStringLiteral FORMAT_WEBP = u"webp"; + +using namespace com::sun::star; + +Animation XOutBitmap::MirrorAnimation( const Animation& rAnimation, bool bHMirr, bool bVMirr ) +{ + Animation aNewAnim( rAnimation ); + + if( bHMirr || bVMirr ) + { + const Size& rGlobalSize = aNewAnim.GetDisplaySizePixel(); + BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE; + + if( bHMirr ) + nMirrorFlags |= BmpMirrorFlags::Horizontal; + + if( bVMirr ) + nMirrorFlags |= BmpMirrorFlags::Vertical; + + for( sal_uInt16 i = 0, nCount = aNewAnim.Count(); i < nCount; i++ ) + { + AnimationFrame aAnimationFrame( aNewAnim.Get( i ) ); + + // mirror the BitmapEx + aAnimationFrame.maBitmapEx.Mirror( nMirrorFlags ); + + // Adjust the positions inside the whole bitmap + if( bHMirr ) + aAnimationFrame.maPositionPixel.setX(rGlobalSize.Width() - aAnimationFrame.maPositionPixel.X() - + aAnimationFrame.maSizePixel.Width()); + + if( bVMirr ) + aAnimationFrame.maPositionPixel.setY(rGlobalSize.Height() - aAnimationFrame.maPositionPixel.Y() - + aAnimationFrame.maSizePixel.Height()); + + aNewAnim.Replace(aAnimationFrame, i); + } + } + + return aNewAnim; +} + +Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const BmpMirrorFlags nMirrorFlags ) +{ + Graphic aRetGraphic; + + if( nMirrorFlags != BmpMirrorFlags::NONE ) + { + if( rGraphic.IsAnimated() ) + { + aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(), + bool( nMirrorFlags & BmpMirrorFlags::Horizontal ), + bool( nMirrorFlags & BmpMirrorFlags::Vertical ) ); + } + else + { + BitmapEx aBmp( rGraphic.GetBitmapEx() ); + aBmp.Mirror( nMirrorFlags ); + aRetGraphic = aBmp; + } + } + else + aRetGraphic = rGraphic; + + return aRetGraphic; +} + +static OUString match(std::u16string_view filter, const OUString& expected, bool matchEmpty = true) +{ + return (matchEmpty && filter.empty()) || expected.equalsIgnoreAsciiCase(filter) ? expected + : OUString(); +} + +static OUString isKnownVectorFormat(const Graphic& rGraphic, std::u16string_view rFilter) +{ + const auto& pData(rGraphic.getVectorGraphicData()); + if (!pData || pData->getBinaryDataContainer().getSize() == 0) + return {}; + + // Does the filter name match the original format? + switch (pData->getType()) + { + case VectorGraphicDataType::Svg: + return match(rFilter, FORMAT_SVG, false); + case VectorGraphicDataType::Wmf: + return match(rFilter, FORMAT_WMF, false); + case VectorGraphicDataType::Emf: + return match(rFilter, FORMAT_EMF, false); + case VectorGraphicDataType::Pdf: + return match(rFilter, FORMAT_PDF, false); + } + + if (rGraphic.GetGfxLink().IsEMF()) + return match(rFilter, FORMAT_EMF, false); + + return {}; +} + +static OUString isKnownRasterFormat(const GfxLink& rLink, std::u16string_view rFilter) +{ + // tdf#60684: use native format if possible but it must correspond to filter name + // or no specific format has been required + // without this, you may save for example file with png extension but jpg content + switch (rLink.GetType()) + { + case GfxLinkType::NativeGif: + return match(rFilter, FORMAT_GIF); + + // #i15508# added BMP type for better exports (no call/trigger found, prob used in HTML export) + case GfxLinkType::NativeBmp: + return match(rFilter, FORMAT_BMP); + + case GfxLinkType::NativeJpg: + return match(rFilter, FORMAT_JPG); + case GfxLinkType::NativePng: + return match(rFilter, FORMAT_PNG); + case GfxLinkType::NativeTif: + return match(rFilter, FORMAT_TIF); + case GfxLinkType::NativeWebp: + return match(rFilter, FORMAT_WEBP); + default: + return {}; + } +} + +ErrCode XOutBitmap::WriteGraphic( const Graphic& rGraphic, OUString& rFileName, + const OUString& rFilterName, const XOutFlags nFlags, + const Size* pMtfSize_100TH_MM, + const css::uno::Sequence< css::beans::PropertyValue >* pFilterData, + OUString* pMediaType ) +{ + if( rGraphic.GetType() == GraphicType::NONE ) + return ERRCODE_NONE; + + INetURLObject aURL( rFileName ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + + DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::WriteGraphic(...): invalid URL" ); + + // calculate correct file name + if( !( nFlags & XOutFlags::DontExpandFilename ) ) + { + OUString aStr( OUString::number( rGraphic.GetChecksum(), 16 ) ); + if ( aStr[0] == '-' ) + aStr = OUString::Concat("m") + aStr.subView(1); + OUString aName = aURL.getBase() + "_" + aURL.getExtension() + "_" + aStr; + aURL.setBase( aName ); + } + + // #i121128# use shortcut to write Vector Graphic Data data in original form (if possible) + if (OUString aExt = isKnownVectorFormat(rGraphic, rFilterName); !aExt.isEmpty()) + { + if (!(nFlags & XOutFlags::DontAddExtension)) + aURL.setExtension(aExt); + + rFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + if (pMediaType) + if (auto xGraphic = rGraphic.GetXGraphic().query<css::beans::XPropertySet>()) + xGraphic->getPropertyValue("MimeType") >>= *pMediaType; + + SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC); + SvStream* pOStm = aMedium.GetOutStream(); + + if (pOStm) + { + rGraphic.getVectorGraphicData()->getBinaryDataContainer().writeToStream(*pOStm); + aMedium.Commit(); + + if (!aMedium.GetErrorIgnoreWarning()) + return ERRCODE_NONE; + } + } + + if( ( nFlags & XOutFlags::UseNativeIfPossible ) && + !( nFlags & XOutFlags::MirrorHorz ) && + !( nFlags & XOutFlags::MirrorVert ) && + ( rGraphic.GetType() != GraphicType::GdiMetafile ) && rGraphic.IsGfxLink() ) + { + // try to write native link + const GfxLink aGfxLink( rGraphic.GetGfxLink() ); + if (OUString aExt = isKnownRasterFormat(aGfxLink, rFilterName); !aExt.isEmpty()) + { + if( !(nFlags & XOutFlags::DontAddExtension) ) + aURL.setExtension( aExt ); + rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + if (pMediaType) + if (auto xGraphic = rGraphic.GetXGraphic().query<css::beans::XPropertySet>()) + xGraphic->getPropertyValue("MimeType") >>= *pMediaType; + + SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC); + SvStream* pOStm = aMedium.GetOutStream(); + + if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() ) + { + pOStm->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize()); + aMedium.Commit(); + + if( !aMedium.GetErrorIgnoreWarning() ) + return ERRCODE_NONE; + } + } + } + + OUString aFilter( rFilterName ); + bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated(); + bool bWriteTransGrf = ( aFilter.equalsIgnoreAsciiCase( "transgrf" ) ) || + ( aFilter.equalsIgnoreAsciiCase( "gif" ) ) || + ( nFlags & XOutFlags::UseGifIfPossible ) || + ( ( nFlags & XOutFlags::UseGifIfSensible ) && ( bAnimated || bTransparent ) ); + + // get filter and extension + if( bWriteTransGrf ) + aFilter = FORMAT_GIF; + + sal_uInt16 nFilter = rFilter.GetExportFormatNumberForShortName( aFilter ); + + if( GRFILTER_FORMAT_NOTFOUND == nFilter ) + { + nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_PNG ); + + if( GRFILTER_FORMAT_NOTFOUND == nFilter ) + nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_BMP ); + } + + if( GRFILTER_FORMAT_NOTFOUND != nFilter ) + { + Graphic aGraphic; + OUString aExt = rFilter.GetExportFormatShortName( nFilter ).toAsciiLowerCase(); + + if( bWriteTransGrf ) + { + if( bAnimated ) + aGraphic = rGraphic; + else + { + if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GraphicType::Bitmap ) ) + { + ScopedVclPtrInstance< VirtualDevice > pVDev; + const Size aSize(pVDev->LogicToPixel(*pMtfSize_100TH_MM, MapMode(MapUnit::Map100thMM))); + + if( pVDev->SetOutputSizePixel( aSize ) ) + { + const Wallpaper aWallpaper( pVDev->GetBackground() ); + const Point aPt; + + pVDev->SetBackground( Wallpaper( COL_BLACK ) ); + pVDev->Erase(); + rGraphic.Draw(*pVDev, aPt, aSize); + + const Bitmap aBitmap( pVDev->GetBitmap( aPt, aSize ) ); + + pVDev->SetBackground( aWallpaper ); + pVDev->Erase(); + rGraphic.Draw(*pVDev, aPt, aSize); + + pVDev->SetRasterOp( RasterOp::Xor ); + pVDev->DrawBitmap( aPt, aSize, aBitmap ); + aGraphic = BitmapEx( aBitmap, pVDev->GetBitmap( aPt, aSize ) ); + } + else + aGraphic = rGraphic.GetBitmapEx(); + } + else + aGraphic = rGraphic.GetBitmapEx(); + } + } + else + { + if (bAnimated) + aGraphic = rGraphic; + else if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GraphicType::Bitmap ) ) + { + ScopedVclPtrInstance< VirtualDevice > pVDev; + const Size aSize(pVDev->LogicToPixel(*pMtfSize_100TH_MM, MapMode(MapUnit::Map100thMM))); + + if( pVDev->SetOutputSizePixel( aSize ) ) + { + rGraphic.Draw(*pVDev, Point(), aSize); + aGraphic = BitmapEx(pVDev->GetBitmap(Point(), aSize)); + } + else + aGraphic = rGraphic.GetBitmapEx(); + } + else + aGraphic = rGraphic.GetBitmapEx(); + } + + // mirror? + if( ( nFlags & XOutFlags::MirrorHorz ) || ( nFlags & XOutFlags::MirrorVert ) ) + { + BmpMirrorFlags nBmpMirrorFlags = BmpMirrorFlags::NONE; + if( nFlags & XOutFlags::MirrorHorz ) + nBmpMirrorFlags |= BmpMirrorFlags::Horizontal; + if( nFlags & XOutFlags::MirrorVert ) + nBmpMirrorFlags |= BmpMirrorFlags::Vertical; + aGraphic = MirrorGraphic( aGraphic, nBmpMirrorFlags ); + } + + if (aGraphic.GetType() != GraphicType::NONE) + { + if( !(nFlags & XOutFlags::DontAddExtension) ) + aURL.setExtension( aExt ); + rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + if (pMediaType) + *pMediaType = rFilter.GetExportFormatMediaType(nFilter); + return ExportGraphic( aGraphic, aURL, rFilter, nFilter, pFilterData ); + } + } + + return ERRCODE_GRFILTER_FILTERERROR; +} + +bool XOutBitmap::GraphicToBase64(const Graphic& rGraphic, OUString& rOUString, bool bAddPrefix, + ConvertDataFormat aTargetFormat) +{ + SvMemoryStream aOStm; + GfxLink aLink = rGraphic.GetGfxLink(); + + if (aTargetFormat == ConvertDataFormat::Unknown) + { + switch (aLink.GetType()) + { + case GfxLinkType::NativeJpg: + aTargetFormat = ConvertDataFormat::JPG; + break; + case GfxLinkType::NativePng: + aTargetFormat = ConvertDataFormat::PNG; + break; + case GfxLinkType::NativeSvg: + aTargetFormat = ConvertDataFormat::SVG; + break; + default: + // save everything else (including gif) into png + aTargetFormat = ConvertDataFormat::PNG; + break; + } + } + + ErrCode nErr = GraphicConverter::Export(aOStm,rGraphic,aTargetFormat); + if ( nErr ) + { + SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr ); + return false; + } + css::uno::Sequence<sal_Int8> aOStmSeq( static_cast<sal_Int8 const *>(aOStm.GetData()),aOStm.TellEnd() ); + OUStringBuffer aStrBuffer; + ::comphelper::Base64::encode(aStrBuffer,aOStmSeq); + rOUString = aStrBuffer.makeStringAndClear(); + + if (bAddPrefix) + { + OUString aMimeType + = comphelper::GraphicMimeTypeHelper::GetMimeTypeForConvertDataFormat(aTargetFormat); + rOUString = aMimeType + ";base64," + rOUString; + } + + return true; +} + +ErrCode XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL, + GraphicFilter& rFilter, const sal_uInt16 nFormat, + const css::uno::Sequence< css::beans::PropertyValue >* pFilterData ) +{ + DBG_ASSERT( rURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::ExportGraphic(...): invalid URL" ); + + SfxMedium aMedium( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC ); + SvStream* pOStm = aMedium.GetOutStream(); + ErrCode nRet = ERRCODE_GRFILTER_IOERROR; + + if( pOStm ) + { + nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pOStm, nFormat, pFilterData ); + + aMedium.Commit(); + + if( aMedium.GetErrorIgnoreWarning() && ( ERRCODE_NONE == nRet ) ) + nRet = ERRCODE_GRFILTER_IOERROR; + } + + return nRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/_xpoly.cxx b/svx/source/xoutdev/_xpoly.cxx new file mode 100644 index 0000000000..e9f0f1ebad --- /dev/null +++ b/svx/source/xoutdev/_xpoly.cxx @@ -0,0 +1,943 @@ +/* -*- 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 <tools/debug.hxx> +#include <tools/poly.hxx> +#include <tools/helpers.hxx> +#include <tools/gen.hxx> + +#include <svx/xpoly.hxx> +#include <xpolyimp.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/range/b2drange.hxx> + + +ImpXPolygon::ImpXPolygon(sal_uInt16 nInitSize, sal_uInt16 _nResize) + : pOldPointAry(nullptr) + , bDeleteOldPoints(false) + , nSize(0) + , nResize(_nResize) + , nPoints(0) +{ + Resize(nInitSize); +} + +ImpXPolygon::ImpXPolygon( const ImpXPolygon& rImpXPoly ) + : pOldPointAry(nullptr) + , bDeleteOldPoints(false) + , nSize(0) + , nResize(rImpXPoly.nResize) + , nPoints(0) +{ + rImpXPoly.CheckPointDelete(); + + Resize( rImpXPoly.nSize ); + + // copy + nPoints = rImpXPoly.nPoints; + memcpy( pPointAry.get(), rImpXPoly.pPointAry.get(), nSize*sizeof( Point ) ); + memcpy( pFlagAry.get(), rImpXPoly.pFlagAry.get(), nSize ); +} + +ImpXPolygon::~ImpXPolygon() +{ + pPointAry.reset(); + if ( bDeleteOldPoints ) + { + delete[] pOldPointAry; + pOldPointAry = nullptr; + } +} + +bool ImpXPolygon::operator==(const ImpXPolygon& rImpXPoly) const +{ + return nPoints==rImpXPoly.nPoints && + (nPoints==0 || + (memcmp(pPointAry.get(), rImpXPoly.pPointAry.get(), nPoints*sizeof(Point))==0 && + memcmp(pFlagAry.get(), rImpXPoly.pFlagAry.get(), nPoints)==0)); +} + +/** Change polygon size + * + * @param nNewSize the new size of the polygon + * @param bDeletePoints if FALSE, do not delete the point array directly but + * wait for the next call before doing so. This prevents + * errors with XPoly[n] = XPoly[0] where a resize might + * destroy the right side point array too early. + */ +void ImpXPolygon::Resize( sal_uInt16 nNewSize, bool bDeletePoints ) +{ + if( nNewSize == nSize ) + return; + + PolyFlags* pOldFlagAry = pFlagAry.release(); + sal_uInt16 nOldSize = nSize; + + CheckPointDelete(); + pOldPointAry = pPointAry.release(); + + // Round the new size to a multiple of nResize, if + // the object was not newly created (nSize != 0) + if ( nSize != 0 && nNewSize > nSize ) + { + DBG_ASSERT(nResize, "Trying to resize but nResize = 0 !"); + nNewSize = nSize + ((nNewSize-nSize-1) / nResize + 1) * nResize; + } + // create point array + nSize = nNewSize; + pPointAry.reset( new Point[ nSize ] ); + + // create flag array + pFlagAry.reset( new PolyFlags[ nSize ] ); + memset( pFlagAry.get(), 0, nSize ); + + // copy if needed + if (nOldSize) + { + if( nOldSize < nSize ) + { + memcpy( pPointAry.get(), pOldPointAry, nOldSize*sizeof( Point ) ); + memcpy( pFlagAry.get(), pOldFlagAry, nOldSize ); + } + else + { + memcpy( pPointAry.get(), pOldPointAry, nSize*sizeof( Point ) ); + memcpy( pFlagAry.get(), pOldFlagAry, nSize ); + + // adjust number of valid points + if( nPoints > nSize ) + nPoints = nSize; + } + } + if ( bDeletePoints ) + { + delete[] pOldPointAry; + pOldPointAry = nullptr; + } + else + bDeleteOldPoints = true; + delete[] pOldFlagAry; +} + +void ImpXPolygon::InsertSpace( sal_uInt16 nPos, sal_uInt16 nCount ) +{ + CheckPointDelete(); + + if ( nPos > nPoints ) + nPos = nPoints; + + // if the polygon is too small then enlarge it + if( (nPoints + nCount) > nSize ) + Resize( nPoints + nCount ); + + // If the insert is not at the last position, move everything after backwards + if( nPos < nPoints ) + { + sal_uInt16 nMove = nPoints - nPos; + memmove( &pPointAry[nPos+nCount], &pPointAry[nPos], + nMove * sizeof(Point) ); + memmove( &pFlagAry[nPos+nCount], &pFlagAry[nPos], nMove ); + } + std::fill(pPointAry.get() + nPos, pPointAry.get() + nPos + nCount, Point()); + memset( &pFlagAry [nPos], 0, nCount ); + + nPoints = nPoints + nCount; +} + +void ImpXPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount ) +{ + CheckPointDelete(); + + if( (nPos + nCount) > nPoints ) + return; + + sal_uInt16 nMove = nPoints - nPos - nCount; + + if( nMove ) + { + memmove( &pPointAry[nPos], &pPointAry[nPos+nCount], + nMove * sizeof(Point) ); + memmove( &pFlagAry[nPos], &pFlagAry[nPos+nCount], nMove ); + } + std::fill(pPointAry.get() + (nPoints - nCount), pPointAry.get() + nPoints, Point()); + memset( &pFlagAry [nPoints - nCount], 0, nCount ); + nPoints = nPoints - nCount; +} + +void ImpXPolygon::CheckPointDelete() const +{ + if ( bDeleteOldPoints ) + { + delete[] pOldPointAry; + const_cast< ImpXPolygon* >(this)->pOldPointAry = nullptr; + const_cast< ImpXPolygon* >(this)->bDeleteOldPoints = false; + } +} + +XPolygon::XPolygon( sal_uInt16 nSize ) + : pImpXPolygon( ImpXPolygon( nSize, 16 ) ) +{ +} + +XPolygon::XPolygon( const XPolygon& ) = default; + +XPolygon::XPolygon( XPolygon&& ) = default; + +/// create a XPolygon out of a standard polygon +XPolygon::XPolygon( const tools::Polygon& rPoly ) + : pImpXPolygon( rPoly.GetSize() ) +{ + sal_uInt16 nSize = rPoly.GetSize(); + pImpXPolygon->nPoints = nSize; + + for( sal_uInt16 i = 0; i < nSize; i++ ) + { + pImpXPolygon->pPointAry[i] = rPoly[i]; + pImpXPolygon->pFlagAry[i] = rPoly.GetFlags( i ); + } +} + +/// create a rectangle (also with rounded corners) as a Bézier polygon +XPolygon::XPolygon(const tools::Rectangle& rRect, tools::Long nRx, tools::Long nRy) + : pImpXPolygon( 17 ) +{ + tools::Long nWh = (rRect.GetWidth() - 1) / 2; + tools::Long nHh = (rRect.GetHeight() - 1) / 2; + + if ( nRx > nWh ) nRx = nWh; + if ( nRy > nHh ) nRy = nHh; + + // negate Rx => circle clockwise + nRx = -nRx; + + // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5) + tools::Long nXHdl = static_cast<tools::Long>(0.552284749 * nRx); + tools::Long nYHdl = static_cast<tools::Long>(0.552284749 * nRy); + sal_uInt16 nPos = 0; + + if ( nRx && nRy ) + { + Point aCenter; + + for (sal_uInt16 nQuad = 0; nQuad < 4; nQuad++) + { + switch ( nQuad ) + { + case 0: aCenter = rRect.TopLeft(); + aCenter.AdjustX( -nRx ); + aCenter.AdjustY(nRy ); + break; + case 1: aCenter = rRect.TopRight(); + aCenter.AdjustX(nRx ); + aCenter.AdjustY(nRy ); + break; + case 2: aCenter = rRect.BottomRight(); + aCenter.AdjustX(nRx ); + aCenter.AdjustY( -nRy ); + break; + case 3: aCenter = rRect.BottomLeft(); + aCenter.AdjustX( -nRx ); + aCenter.AdjustY( -nRy ); + break; + } + GenBezArc(aCenter, nRx, nRy, nXHdl, nYHdl, 0_deg100, 9000_deg100, nQuad, nPos); + pImpXPolygon->pFlagAry[nPos ] = PolyFlags::Smooth; + pImpXPolygon->pFlagAry[nPos+3] = PolyFlags::Smooth; + nPos += 4; + } + } + else + { + pImpXPolygon->pPointAry[nPos++] = rRect.TopLeft(); + pImpXPolygon->pPointAry[nPos++] = rRect.TopRight(); + pImpXPolygon->pPointAry[nPos++] = rRect.BottomRight(); + pImpXPolygon->pPointAry[nPos++] = rRect.BottomLeft(); + } + pImpXPolygon->pPointAry[nPos] = pImpXPolygon->pPointAry[0]; + pImpXPolygon->nPoints = nPos + 1; +} + +/// create an ellipse (curve) as Bézier polygon +XPolygon::XPolygon(const Point& rCenter, tools::Long nRx, tools::Long nRy, + Degree100 nStartAngle, Degree100 nEndAngle, bool bClose) + : pImpXPolygon( 17 ) +{ + nStartAngle %= 36000_deg100; + if ( nEndAngle > 36000_deg100 ) nEndAngle %= 36000_deg100; + bool bFull = (nStartAngle == 0_deg100 && nEndAngle == 36000_deg100); + + // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5) + tools::Long nXHdl = static_cast<tools::Long>(0.552284749 * nRx); + tools::Long nYHdl = static_cast<tools::Long>(0.552284749 * nRy); + sal_uInt16 nPos = 0; + bool bLoopEnd = false; + + do + { + Degree100 nA1, nA2; + sal_uInt16 nQuad = nStartAngle.get() / 9000; + if ( nQuad == 4 ) nQuad = 0; + bLoopEnd = CheckAngles(nStartAngle, nEndAngle, nA1, nA2); + GenBezArc(rCenter, nRx, nRy, nXHdl, nYHdl, nA1, nA2, nQuad, nPos); + nPos += 3; + if ( !bLoopEnd ) + pImpXPolygon->pFlagAry[nPos] = PolyFlags::Smooth; + + } while ( !bLoopEnd ); + + // if not a full circle then connect edges with center point if necessary + if ( !bFull && bClose ) + pImpXPolygon->pPointAry[++nPos] = rCenter; + + if ( bFull ) + { + pImpXPolygon->pFlagAry[0 ] = PolyFlags::Smooth; + pImpXPolygon->pFlagAry[nPos] = PolyFlags::Smooth; + } + pImpXPolygon->nPoints = nPos + 1; +} + +XPolygon::~XPolygon() = default; + +void XPolygon::SetPointCount( sal_uInt16 nPoints ) +{ + std::as_const(pImpXPolygon)->CheckPointDelete(); + + if( pImpXPolygon->nSize < nPoints ) + pImpXPolygon->Resize( nPoints ); + + if ( nPoints < pImpXPolygon->nPoints ) + { + sal_uInt16 nSize = pImpXPolygon->nPoints - nPoints; + std::fill( + pImpXPolygon->pPointAry.get() + nPoints, pImpXPolygon->pPointAry.get() + nPoints + nSize, Point()); + memset( &pImpXPolygon->pFlagAry [nPoints], 0, nSize ); + } + pImpXPolygon->nPoints = nPoints; +} + +sal_uInt16 XPolygon::GetSize() const +{ + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->nSize; +} + +sal_uInt16 XPolygon::GetPointCount() const +{ + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->nPoints; +} + +void XPolygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags ) +{ + if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints; + pImpXPolygon->InsertSpace( nPos, 1 ); + pImpXPolygon->pPointAry[nPos] = rPt; + pImpXPolygon->pFlagAry[nPos] = eFlags; +} + +void XPolygon::Insert( sal_uInt16 nPos, const XPolygon& rXPoly ) +{ + if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints; + + sal_uInt16 nPoints = rXPoly.GetPointCount(); + + pImpXPolygon->InsertSpace( nPos, nPoints ); + + memcpy( &(pImpXPolygon->pPointAry[nPos]), + rXPoly.pImpXPolygon->pPointAry.get(), + nPoints*sizeof( Point ) ); + memcpy( &(pImpXPolygon->pFlagAry[nPos]), + rXPoly.pImpXPolygon->pFlagAry.get(), + nPoints ); +} + +void XPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount ) +{ + pImpXPolygon->Remove( nPos, nCount ); +} + +void XPolygon::Move( tools::Long nHorzMove, tools::Long nVertMove ) +{ + if ( !nHorzMove && !nVertMove ) + return; + + // move points + sal_uInt16 nCount = pImpXPolygon->nPoints; + for ( sal_uInt16 i = 0; i < nCount; i++ ) + { + Point* pPt = &(pImpXPolygon->pPointAry[i]); + pPt->AdjustX( nHorzMove ); + pPt->AdjustY( nVertMove ); + } +} + +tools::Rectangle XPolygon::GetBoundRect() const +{ + pImpXPolygon->CheckPointDelete(); + tools::Rectangle aRetval; + + if(pImpXPolygon->nPoints) + { + // #i37709# + // For historical reasons the control points are not part of the + // BoundRect. This makes it necessary to subdivide the polygon to + // get a relatively correct BoundRect. Numerically, this is not + // correct and never was. + + const basegfx::B2DRange aPolygonRange(basegfx::utils::getRange(getB2DPolygon())); + aRetval = tools::Rectangle( + FRound(aPolygonRange.getMinX()), FRound(aPolygonRange.getMinY()), + FRound(aPolygonRange.getMaxX()), FRound(aPolygonRange.getMaxY())); + } + + return aRetval; +} + +const Point& XPolygon::operator[]( sal_uInt16 nPos ) const +{ + DBG_ASSERT(nPos < pImpXPolygon->nPoints, "Invalid index at const array access to XPolygon"); + + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->pPointAry[nPos]; +} + +Point& XPolygon::operator[]( sal_uInt16 nPos ) +{ + std::as_const(pImpXPolygon)->CheckPointDelete(); + + if( nPos >= pImpXPolygon->nSize ) + { + DBG_ASSERT(pImpXPolygon->nResize, "Invalid index at array access to XPolygon"); + pImpXPolygon->Resize(nPos + 1, false); + } + if( nPos >= pImpXPolygon->nPoints ) + pImpXPolygon->nPoints = nPos + 1; + + return pImpXPolygon->pPointAry[nPos]; +} + +XPolygon& XPolygon::operator=( const XPolygon& ) = default; + +XPolygon& XPolygon::operator=( XPolygon&& ) = default; + +bool XPolygon::operator==( const XPolygon& rXPoly ) const +{ + pImpXPolygon->CheckPointDelete(); + return rXPoly.pImpXPolygon == pImpXPolygon; +} + +/// get the flags for the point at the given position +PolyFlags XPolygon::GetFlags( sal_uInt16 nPos ) const +{ + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->pFlagAry[nPos]; +} + +/// set the flags for the point at the given position +void XPolygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags ) +{ + std::as_const(pImpXPolygon)->CheckPointDelete(); + pImpXPolygon->pFlagAry[nPos] = eFlags; +} + +/// short path to read the CONTROL flag directly (TODO: better explain what the sense behind this flag is!) +bool XPolygon::IsControl(sal_uInt16 nPos) const +{ + return pImpXPolygon->pFlagAry[nPos] == PolyFlags::Control; +} + +/// short path to read the SMOOTH and SYMMTR flag directly (TODO: better explain what the sense behind these flags is!) +bool XPolygon::IsSmooth(sal_uInt16 nPos) const +{ + PolyFlags eFlag = pImpXPolygon->pFlagAry[nPos]; + return ( eFlag == PolyFlags::Smooth || eFlag == PolyFlags::Symmetric ); +} + +/** calculate the euclidean distance between two points + * + * @param nP1 The first point + * @param nP2 The second point + */ +double XPolygon::CalcDistance(sal_uInt16 nP1, sal_uInt16 nP2) +{ + const Point& rP1 = pImpXPolygon->pPointAry[nP1]; + const Point& rP2 = pImpXPolygon->pPointAry[nP2]; + double fDx = rP2.X() - rP1.X(); + double fDy = rP2.Y() - rP1.Y(); + return std::hypot(fDx, fDy); +} + +void XPolygon::SubdivideBezier(sal_uInt16 nPos, bool bCalcFirst, double fT) +{ + Point* pPoints = pImpXPolygon->pPointAry.get(); + double fT2 = fT * fT; + double fT3 = fT * fT2; + double fU = 1.0 - fT; + double fU2 = fU * fU; + double fU3 = fU * fU2; + sal_uInt16 nIdx = nPos; + short nPosInc, nIdxInc; + + if ( bCalcFirst ) + { + nPos += 3; + nPosInc = -1; + nIdxInc = 0; + } + else + { + nPosInc = 1; + nIdxInc = 1; + } + pPoints[nPos].setX( static_cast<tools::Long>(fU3 * pPoints[nIdx ].X() + + fT * fU2 * pPoints[nIdx+1].X() * 3 + + fT2 * fU * pPoints[nIdx+2].X() * 3 + + fT3 * pPoints[nIdx+3].X()) ); + pPoints[nPos].setY( static_cast<tools::Long>(fU3 * pPoints[nIdx ].Y() + + fT * fU2 * pPoints[nIdx+1].Y() * 3 + + fT2 * fU * pPoints[nIdx+2].Y() * 3 + + fT3 * pPoints[nIdx+3].Y()) ); + nPos = nPos + nPosInc; + nIdx = nIdx + nIdxInc; + pPoints[nPos].setX( static_cast<tools::Long>(fU2 * pPoints[nIdx ].X() + + fT * fU * pPoints[nIdx+1].X() * 2 + + fT2 * pPoints[nIdx+2].X()) ); + pPoints[nPos].setY( static_cast<tools::Long>(fU2 * pPoints[nIdx ].Y() + + fT * fU * pPoints[nIdx+1].Y() * 2 + + fT2 * pPoints[nIdx+2].Y()) ); + nPos = nPos + nPosInc; + nIdx = nIdx + nIdxInc; + pPoints[nPos].setX( static_cast<tools::Long>(fU * pPoints[nIdx ].X() + + fT * pPoints[nIdx+1].X()) ); + pPoints[nPos].setY( static_cast<tools::Long>(fU * pPoints[nIdx ].Y() + + fT * pPoints[nIdx+1].Y()) ); +} + +/// Generate a Bézier arc +void XPolygon::GenBezArc(const Point& rCenter, tools::Long nRx, tools::Long nRy, + tools::Long nXHdl, tools::Long nYHdl, Degree100 nStart, Degree100 nEnd, + sal_uInt16 nQuad, sal_uInt16 nFirst) +{ + Point* pPoints = pImpXPolygon->pPointAry.get(); + pPoints[nFirst ] = rCenter; + pPoints[nFirst+3] = rCenter; + + if ( nQuad == 1 || nQuad == 2 ) + { + nRx = -nRx; nXHdl = -nXHdl; + } + if ( nQuad == 0 || nQuad == 1 ) + { + nRy = -nRy; nYHdl = -nYHdl; + } + + if ( nQuad == 0 || nQuad == 2 ) + { + pPoints[nFirst].AdjustX( nRx ); + pPoints[nFirst+3].AdjustY( nRy ); + } + else + { + pPoints[nFirst].AdjustY( nRy ); + pPoints[nFirst+3].AdjustX( nRx ); + } + pPoints[nFirst+1] = pPoints[nFirst]; + pPoints[nFirst+2] = pPoints[nFirst+3]; + + if ( nQuad == 0 || nQuad == 2 ) + { + pPoints[nFirst+1].AdjustY( nYHdl ); + pPoints[nFirst+2].AdjustX( nXHdl ); + } + else + { + pPoints[nFirst+1].AdjustX( nXHdl ); + pPoints[nFirst+2].AdjustY( nYHdl ); + } + if ( nStart > 0_deg100 ) + SubdivideBezier(nFirst, false, static_cast<double>(nStart.get()) / 9000); + if ( nEnd < 9000_deg100 ) + SubdivideBezier(nFirst, true, static_cast<double>((nEnd-nStart).get()) / (9000_deg100-nStart).get()); + SetFlags(nFirst+1, PolyFlags::Control); + SetFlags(nFirst+2, PolyFlags::Control); +} + +bool XPolygon::CheckAngles(Degree100& nStart, Degree100 nEnd, Degree100& nA1, Degree100& nA2) +{ + if ( nStart == 36000_deg100 ) nStart = 0_deg100; + if ( nEnd == 0_deg100 ) nEnd = 36000_deg100; + Degree100 nStPrev = nStart; + Degree100 nMax((nStart.get() / 9000 + 1) * 9000); + Degree100 nMin = nMax - 9000_deg100; + + if ( nEnd >= nMax || nEnd <= nStart ) nA2 = 9000_deg100; + else nA2 = nEnd - nMin; + nA1 = nStart - nMin; + nStart = nMax; + + // returns true when the last segment was calculated + return (nStPrev < nEnd && nStart >= nEnd); +} + +/** Calculate a smooth transition to connect two Bézier curves + * + * This is done by projecting the corresponding point onto a line between + * two other points. + * + * @param nCenter The point at the end or beginning of the curve. + * If nCenter is at the end of the polygon the point is moved + * to the opposite side. + * @param nDrag The moved point that specifies the relocation. + * @param nPnt The point to modify. + */ +void XPolygon::CalcSmoothJoin(sal_uInt16 nCenter, sal_uInt16 nDrag, sal_uInt16 nPnt) +{ + // If nPoint is no control point, i.e. cannot be moved, then + // move nDrag instead on the line between nCenter and nPnt + if ( !IsControl(nPnt) ) + std::swap( nDrag, nPnt ); + Point* pPoints = pImpXPolygon->pPointAry.get(); + Point aDiff = pPoints[nDrag] - pPoints[nCenter]; + double fDiv = CalcDistance(nCenter, nDrag); + + if ( fDiv ) + { + double fRatio = CalcDistance(nCenter, nPnt) / fDiv; + // keep the length if SMOOTH + if ( GetFlags(nCenter) == PolyFlags::Smooth || !IsControl(nDrag) ) + { + aDiff.setX( static_cast<tools::Long>(fRatio * aDiff.X()) ); + aDiff.setY( static_cast<tools::Long>(fRatio * aDiff.Y()) ); + } + pPoints[nPnt] = pPoints[nCenter] - aDiff; + } +} + +/** Calculate tangent between two Bézier curves + * + * @param nCenter start or end point of the curves + * @param nPrev previous reference point + * @param nNext next reference point + */ +void XPolygon::CalcTangent(sal_uInt16 nCenter, sal_uInt16 nPrev, sal_uInt16 nNext) +{ + double fAbsLen = CalcDistance(nNext, nPrev); + + if ( !fAbsLen ) + return; + + const Point& rCenter = pImpXPolygon->pPointAry[nCenter]; + Point& rNext = pImpXPolygon->pPointAry[nNext]; + Point& rPrev = pImpXPolygon->pPointAry[nPrev]; + Point aDiff = rNext - rPrev; + double fNextLen = CalcDistance(nCenter, nNext) / fAbsLen; + double fPrevLen = CalcDistance(nCenter, nPrev) / fAbsLen; + + // same length for both sides if SYMMTR + if ( GetFlags(nCenter) == PolyFlags::Symmetric ) + { + fPrevLen = (fNextLen + fPrevLen) / 2; + fNextLen = fPrevLen; + } + rNext.setX( rCenter.X() + static_cast<tools::Long>(fNextLen * aDiff.X()) ); + rNext.setY( rCenter.Y() + static_cast<tools::Long>(fNextLen * aDiff.Y()) ); + rPrev.setX( rCenter.X() - static_cast<tools::Long>(fPrevLen * aDiff.X()) ); + rPrev.setY( rCenter.Y() - static_cast<tools::Long>(fPrevLen * aDiff.Y()) ); +} + +/// convert four polygon points into a Bézier curve +void XPolygon::PointsToBezier(sal_uInt16 nFirst) +{ + double nFullLength, nPart1Length, nPart2Length; + double fX0, fY0, fX1, fY1, fX2, fY2, fX3, fY3; + double fTx1, fTx2, fTy1, fTy2; + double fT1, fU1, fT2, fU2, fV; + Point* pPoints = pImpXPolygon->pPointAry.get(); + + if ( nFirst > pImpXPolygon->nPoints - 4 || IsControl(nFirst) || + IsControl(nFirst+1) || IsControl(nFirst+2) || IsControl(nFirst+3) ) + return; + + fTx1 = pPoints[nFirst+1].X(); + fTy1 = pPoints[nFirst+1].Y(); + fTx2 = pPoints[nFirst+2].X(); + fTy2 = pPoints[nFirst+2].Y(); + fX0 = pPoints[nFirst ].X(); + fY0 = pPoints[nFirst ].Y(); + fX3 = pPoints[nFirst+3].X(); + fY3 = pPoints[nFirst+3].Y(); + + nPart1Length = CalcDistance(nFirst, nFirst+1); + nPart2Length = nPart1Length + CalcDistance(nFirst+1, nFirst+2); + nFullLength = nPart2Length + CalcDistance(nFirst+2, nFirst+3); + if ( nFullLength < 20 ) + return; + + if ( nPart2Length == nFullLength ) + nPart2Length -= 1; + if ( nPart1Length == nFullLength ) + nPart1Length = nPart2Length - 1; + if ( nPart1Length <= 0 ) + nPart1Length = 1; + if ( nPart2Length <= 0 || nPart2Length == nPart1Length ) + nPart2Length = nPart1Length + 1; + + fT1 = nPart1Length / nFullLength; + fU1 = 1.0 - fT1; + fT2 = nPart2Length / nFullLength; + fU2 = 1.0 - fT2; + fV = 3 * (1.0 - (fT1 * fU2) / (fT2 * fU1)); + + fX1 = fTx1 / (fT1 * fU1 * fU1) - fTx2 * fT1 / (fT2 * fT2 * fU1 * fU2); + fX1 /= fV; + fX1 -= fX0 * ( fU1 / fT1 + fU2 / fT2) / 3; + fX1 += fX3 * ( fT1 * fT2 / (fU1 * fU2)) / 3; + + fY1 = fTy1 / (fT1 * fU1 * fU1) - fTy2 * fT1 / (fT2 * fT2 * fU1 * fU2); + fY1 /= fV; + fY1 -= fY0 * ( fU1 / fT1 + fU2 / fT2) / 3; + fY1 += fY3 * ( fT1 * fT2 / (fU1 * fU2)) / 3; + + fX2 = fTx2 / (fT2 * fT2 * fU2 * 3) - fX0 * fU2 * fU2 / ( fT2 * fT2 * 3); + fX2 -= fX1 * fU2 / fT2; + fX2 -= fX3 * fT2 / (fU2 * 3); + + fY2 = fTy2 / (fT2 * fT2 * fU2 * 3) - fY0 * fU2 * fU2 / ( fT2 * fT2 * 3); + fY2 -= fY1 * fU2 / fT2; + fY2 -= fY3 * fT2 / (fU2 * 3); + + pPoints[nFirst+1] = Point(static_cast<tools::Long>(fX1), static_cast<tools::Long>(fY1)); + pPoints[nFirst+2] = Point(static_cast<tools::Long>(fX2), static_cast<tools::Long>(fY2)); + SetFlags(nFirst+1, PolyFlags::Control); + SetFlags(nFirst+2, PolyFlags::Control); +} + +/// scale in X- and/or Y-direction +void XPolygon::Scale(double fSx, double fSy) +{ + std::as_const(pImpXPolygon)->CheckPointDelete(); + + sal_uInt16 nPntCnt = pImpXPolygon->nPoints; + + for (sal_uInt16 i = 0; i < nPntCnt; i++) + { + Point& rPnt = pImpXPolygon->pPointAry[i]; + rPnt.setX( static_cast<tools::Long>(fSx * rPnt.X()) ); + rPnt.setY( static_cast<tools::Long>(fSy * rPnt.Y()) ); + } +} + +/** + * Distort a polygon by scaling its coordinates relative to a reference + * rectangle into an arbitrary rectangle. + * + * Mapping between polygon corners and reference rectangle: + * 0: top left 0----1 + * 1: top right | | + * 2: bottom right 3----2 + * 3: bottom left + */ +void XPolygon::Distort(const tools::Rectangle& rRefRect, + const XPolygon& rDistortedRect) +{ + std::as_const(pImpXPolygon)->CheckPointDelete(); + + tools::Long Xr, Wr; + tools::Long Yr, Hr; + + Xr = rRefRect.Left(); + Yr = rRefRect.Top(); + Wr = rRefRect.GetWidth(); + Hr = rRefRect.GetHeight(); + + if ( !Wr || !Hr ) + return; + + tools::Long X1, X2, X3, X4; + tools::Long Y1, Y2, Y3, Y4; + DBG_ASSERT(rDistortedRect.pImpXPolygon->nPoints >= 4, + "Distort: rectangle too small"); + + X1 = rDistortedRect[0].X(); + Y1 = rDistortedRect[0].Y(); + X2 = rDistortedRect[1].X(); + Y2 = rDistortedRect[1].Y(); + X3 = rDistortedRect[3].X(); + Y3 = rDistortedRect[3].Y(); + X4 = rDistortedRect[2].X(); + Y4 = rDistortedRect[2].Y(); + + sal_uInt16 nPntCnt = pImpXPolygon->nPoints; + + for (sal_uInt16 i = 0; i < nPntCnt; i++) + { + double fTx, fTy, fUx, fUy; + Point& rPnt = pImpXPolygon->pPointAry[i]; + + fTx = static_cast<double>(rPnt.X() - Xr) / Wr; + fTy = static_cast<double>(rPnt.Y() - Yr) / Hr; + fUx = 1.0 - fTx; + fUy = 1.0 - fTy; + + rPnt.setX( static_cast<tools::Long>( fUy * (fUx * X1 + fTx * X2) + + fTy * (fUx * X3 + fTx * X4) ) ); + rPnt.setY( static_cast<tools::Long>( fUx * (fUy * Y1 + fTy * Y3) + + fTx * (fUy * Y2 + fTy * Y4) ) ); + } +} + +basegfx::B2DPolygon XPolygon::getB2DPolygon() const +{ + // #i74631# use tools Polygon class for conversion to not have the code doubled + // here. This needs one more conversion but avoids different converters in + // the long run + const tools::Polygon aSource(GetPointCount(), pImpXPolygon->pPointAry.get(), pImpXPolygon->pFlagAry.get()); + + return aSource.getB2DPolygon(); +} + +XPolygon::XPolygon(const basegfx::B2DPolygon& rPolygon) + : pImpXPolygon( tools::Polygon( rPolygon ).GetSize() ) +{ + // #i74631# use tools Polygon class for conversion to not have the code doubled + // here. This needs one more conversion but avoids different converters in + // the long run + + const tools::Polygon aSource(rPolygon); + sal_uInt16 nSize = aSource.GetSize(); + pImpXPolygon->nPoints = nSize; + + for( sal_uInt16 i = 0; i < nSize; i++ ) + { + pImpXPolygon->pPointAry[i] = aSource[i]; + pImpXPolygon->pFlagAry[i] = aSource.GetFlags( i ); + } +} + +// XPolyPolygon +XPolyPolygon::XPolyPolygon() = default; + +XPolyPolygon::XPolyPolygon( const XPolyPolygon& ) = default; + +XPolyPolygon::XPolyPolygon( XPolyPolygon&& ) = default; + +XPolyPolygon::XPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon) +{ + for(auto const& rCandidate : rPolyPolygon) + { + Insert(XPolygon(rCandidate)); + } +} + +XPolyPolygon::~XPolyPolygon() = default; + +void XPolyPolygon::Insert( XPolygon&& rXPoly ) +{ + pImpXPolyPolygon->aXPolyList.emplace_back( std::move(rXPoly) ); +} + +/// insert all XPolygons of a XPolyPolygon +void XPolyPolygon::Insert( const XPolyPolygon& rXPolyPoly ) +{ + for ( size_t i = 0; i < rXPolyPoly.Count(); i++) + { + pImpXPolyPolygon->aXPolyList.emplace_back( rXPolyPoly[i] ); + } +} + +void XPolyPolygon::Remove( sal_uInt16 nPos ) +{ + pImpXPolyPolygon->aXPolyList.erase( pImpXPolyPolygon->aXPolyList.begin() + nPos ); +} + +const XPolygon& XPolyPolygon::GetObject( sal_uInt16 nPos ) const +{ + return pImpXPolyPolygon->aXPolyList[ nPos ]; +} + +void XPolyPolygon::Clear() +{ + pImpXPolyPolygon->aXPolyList.clear(); +} + +sal_uInt16 XPolyPolygon::Count() const +{ + return static_cast<sal_uInt16>(pImpXPolyPolygon->aXPolyList.size()); +} + +tools::Rectangle XPolyPolygon::GetBoundRect() const +{ + size_t nXPoly = pImpXPolyPolygon->aXPolyList.size(); + tools::Rectangle aRect; + + for ( size_t n = 0; n < nXPoly; n++ ) + { + XPolygon const & rXPoly = pImpXPolyPolygon->aXPolyList[ n ]; + aRect.Union( rXPoly.GetBoundRect() ); + } + + return aRect; +} + +XPolygon& XPolyPolygon::operator[]( sal_uInt16 nPos ) +{ + return pImpXPolyPolygon->aXPolyList[ nPos ]; +} + +XPolyPolygon& XPolyPolygon::operator=( const XPolyPolygon& ) = default; + +XPolyPolygon& XPolyPolygon::operator=( XPolyPolygon&& ) = default; + +/** + * Distort a polygon by scaling its coordinates relative to a reference + * rectangle into an arbitrary rectangle. + * + * Mapping between polygon corners and reference rectangle: + * 0: top left 0----1 + * 1: top right | | + * 2: bottom right 3----2 + * 3: bottom left + */ +void XPolyPolygon::Distort(const tools::Rectangle& rRefRect, + const XPolygon& rDistortedRect) +{ + for (size_t i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList[ i ].Distort(rRefRect, rDistortedRect); +} + +basegfx::B2DPolyPolygon XPolyPolygon::getB2DPolyPolygon() const +{ + basegfx::B2DPolyPolygon aRetval; + + for(sal_uInt16 a(0); a < Count(); a++) + { + const XPolygon& rPoly = (*this)[a]; + aRetval.append(rPoly.getB2DPolygon()); + } + + return aRetval; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xattr.cxx b/svx/source/xoutdev/xattr.cxx new file mode 100644 index 0000000000..5f5c51655f --- /dev/null +++ b/svx/source/xoutdev/xattr.cxx @@ -0,0 +1,3130 @@ +/* -*- 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 <utility> + +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/drawing/Hatch.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/LineDash.hpp> +#include <com/sun/star/drawing/DashStyle.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <o3tl/string_view.hxx> +#include <o3tl/any.hxx> +#include <svl/itempool.hxx> +#include <editeng/memberids.h> +#include <docmodel/uno/UnoGradientTools.hxx> +#include <docmodel/uno/UnoComplexColor.hxx> +#include <docmodel/color/ComplexColorJSON.hxx> +#include <tools/mapunit.hxx> +#include <tools/UnitConversion.hxx> +#include <osl/diagnose.h> + +#include <svx/unoapi.hxx> +#include <svl/style.hxx> + +#include <tools/bigint.hxx> +#include <svl/itemset.hxx> +#include <svx/strings.hrc> +#include <svx/xfillit0.hxx> +#include <svx/xflasit.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlnasit.hxx> +#include <svx/xtextit0.hxx> +#include <svx/xtable.hxx> +#include <svx/dialmgr.hxx> +#include <svx/xflclit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xsflclit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnwtit.hxx> +#include <svx/xlnclit.hxx> +#include <svx/xlnstit.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xlnstwit.hxx> +#include <svx/xlnedwit.hxx> +#include <svx/xlnstcit.hxx> +#include <svx/xlnedcit.hxx> +#include <editeng/itemtype.hxx> +#include <editeng/eerdll.hxx> +#include <svx/xdef.hxx> +#include <svx/unomid.hxx> +#include <svx/svdmodel.hxx> +#include <svx/xftdiit.hxx> +#include <svx/xftstit.hxx> +#include <svx/xftmrit.hxx> +#include <svx/xftouit.hxx> +#include <svx/xftshit.hxx> +#include <svx/xftshcit.hxx> +#include <svx/xftshxy.hxx> +#include <svx/xftadit.hxx> +#include <svx/svddef.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <unotools/intlwrapper.hxx> +#include <unotools/syslocale.hxx> +#include <string> + +#include <boost/property_tree/json_parser.hpp> +#include <libxml/xmlwriter.h> + +using namespace ::com::sun::star; + +typedef std::map<OUString, OUString> StringMap; + +NameOrIndex::NameOrIndex(TypedWhichId<NameOrIndex> _nWhich, sal_Int32 nIndex) : + SfxStringItem(_nWhich, OUString()), + m_nPalIndex(nIndex) +{ +} + +NameOrIndex::NameOrIndex(TypedWhichId<NameOrIndex> _nWhich, const OUString& rName) : + SfxStringItem(_nWhich, rName), + m_nPalIndex(-1) +{ +} + +NameOrIndex::NameOrIndex(const NameOrIndex& rNameOrIndex) : + SfxStringItem(rNameOrIndex), + m_nPalIndex(rNameOrIndex.m_nPalIndex) +{ +} + +bool NameOrIndex::operator==(const SfxPoolItem& rItem) const +{ + return ( SfxStringItem::operator==(rItem) && + static_cast<const NameOrIndex&>(rItem).m_nPalIndex == m_nPalIndex ); +} + +NameOrIndex* NameOrIndex::Clone(SfxItemPool* /*pPool*/) const +{ + return new NameOrIndex(*this); +} + +/** this static checks if the given NameOrIndex item has a unique name for its value. + The returned String is a unique name for an item with this value in both given pools. + Argument pPool2 can be null. + If returned string equals NameOrIndex->GetName(), the name was already unique. +*/ +OUString NameOrIndex::CheckNamedItem( const NameOrIndex* pCheckItem, const sal_uInt16 nWhich, const SfxItemPool* pPool1, SvxCompareValueFunc pCompareValueFunc, TranslateId pPrefixResId, const XPropertyListRef &pDefaults ) +{ + bool bForceNew = false; + + OUString aUniqueName = SvxUnogetInternalNameForItem(nWhich, pCheckItem->GetName()); + + // 2. if we have a name check if there is already an item with the + // same name in the documents pool with a different line end or start + + if (!aUniqueName.isEmpty() && pPool1) + { + for (const SfxPoolItem* pItem : pPool1->GetItemSurrogates(nWhich)) + { + const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem); + + if( pNameOrIndex->GetName() == pCheckItem->GetName() ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( !pCompareValueFunc( pNameOrIndex, pCheckItem ) ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + } + + // if we have no name yet, find existing item with same content or + // create a unique name + if (aUniqueName.isEmpty()) + { + sal_Int32 nUserIndex = 1; + const OUString aUser(SvxResId(pPrefixResId) + " "); + + if( pDefaults ) + { + const int nCount = pDefaults->Count(); + int nIndex; + for( nIndex = 0; nIndex < nCount; nIndex++ ) + { + const XPropertyEntry* pEntry = pDefaults->Get(nIndex); + if( pEntry ) + { + bool bFound = false; + + switch( nWhich ) + { + case XATTR_FILLBITMAP: + { + const GraphicObject& rGraphicObjectA(static_cast<const XFillBitmapItem*>(pCheckItem)->GetGraphicObject()); + const GraphicObject& rGraphicObjectB(static_cast<const XBitmapEntry*>(pEntry)->GetGraphicObject()); + + bFound = (rGraphicObjectA == rGraphicObjectB); + break; + } + case XATTR_LINEDASH: + bFound = static_cast<const XLineDashItem*>(pCheckItem)->GetDashValue() == static_cast<const XDashEntry*>(pEntry)->GetDash(); + break; + case XATTR_LINESTART: + bFound = static_cast<const XLineStartItem*>(pCheckItem)->GetLineStartValue() == static_cast<const XLineEndEntry*>(pEntry)->GetLineEnd(); + break; + case XATTR_LINEEND: + bFound = static_cast<const XLineEndItem*>(pCheckItem)->GetLineEndValue() == static_cast<const XLineEndEntry*>(pEntry)->GetLineEnd(); + break; + case XATTR_FILLGRADIENT: + bFound = static_cast<const XFillGradientItem*>(pCheckItem)->GetGradientValue() == static_cast<const XGradientEntry*>(pEntry)->GetGradient(); + break; + case XATTR_FILLHATCH: + bFound = static_cast<const XFillHatchItem*>(pCheckItem)->GetHatchValue() == static_cast<const XHatchEntry*>(pEntry)->GetHatch(); + break; + } + + if( bFound ) + { + aUniqueName = pEntry->GetName(); + break; + } + else + { + const OUString& aEntryName = pEntry->GetName(); + if(aEntryName.getLength() >= aUser.getLength()) + { + sal_Int32 nThisIndex = o3tl::toInt32(aEntryName.subView( aUser.getLength() )); + if( nThisIndex >= nUserIndex ) + nUserIndex = nThisIndex + 1; + } + } + } + } + } + + if (aUniqueName.isEmpty() && pPool1) + { + for (const SfxPoolItem* pItem : pPool1->GetItemSurrogates(nWhich)) + { + const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem); + + if( !pNameOrIndex->GetName().isEmpty() ) + { + if( !bForceNew && pCompareValueFunc( pNameOrIndex, pCheckItem ) ) + return pNameOrIndex->GetName(); + + if( pNameOrIndex->GetName().startsWith( aUser ) ) + { + sal_Int32 nThisIndex = o3tl::toInt32(pNameOrIndex->GetName().subView( aUser.getLength() )); + if( nThisIndex >= nUserIndex ) + nUserIndex = nThisIndex + 1; + } + } + } + aUniqueName = aUser + OUString::number( nUserIndex ); + } + } + + return aUniqueName; +} + +void NameOrIndex::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("NameOrIndex")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("isIndex"), BAD_CAST(OString::boolean(IsIndex()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(m_nPalIndex).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + +SfxPoolItem* XColorItem::CreateDefault() { return new XColorItem; } + +XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, sal_Int32 nIndex, const Color& rTheColor) : + NameOrIndex(_nWhich, nIndex), + aColor(rTheColor) +{ +} + +XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, const OUString& rName, const Color& rTheColor) : + NameOrIndex(_nWhich, rName), + aColor(rTheColor) +{ +} + +XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, const Color& rTheColor) + : NameOrIndex(_nWhich, OUString()) + , aColor(rTheColor) +{ +} + +XColorItem::XColorItem(const XColorItem& rItem) : + NameOrIndex(rItem), + aColor(rItem.aColor), + maComplexColor(rItem.maComplexColor) +{ +} + +XColorItem* XColorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XColorItem(*this); +} + +bool XColorItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && + static_cast<const XColorItem&>(rItem).aColor == aColor ) && + static_cast<const XColorItem&>(rItem).maComplexColor == maComplexColor; +} + +const Color& XColorItem::GetColorValue() const +{ + assert(!IsIndex()); + return aColor; + +} + +bool XColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId) const +{ + nMemberId &= ~CONVERT_TWIPS; + switch (nMemberId) + { + case MID_COMPLEX_COLOR: + { + auto xComplexColor = model::color::createXComplexColor(getComplexColor()); + rVal <<= xComplexColor; + break; + } + case MID_COMPLEX_COLOR_JSON: + { + rVal <<= OStringToOUString(model::color::convertToJSON(getComplexColor()), RTL_TEXTENCODING_UTF8); + break; + } + default: + { + rVal <<= GetColorValue().GetRGBColor(); + break; + } + } + return true; +} + +bool XColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId) +{ + nMemberId &= ~CONVERT_TWIPS; + switch (nMemberId) + { + case MID_COMPLEX_COLOR: + { + css::uno::Reference<css::util::XComplexColor> xComplexColor; + if (!(rVal >>= xComplexColor)) + return false; + setComplexColor(model::color::getFromXComplexColor(xComplexColor)); + } + break; + case MID_COMPLEX_COLOR_JSON: + { + OUString sComplexColorJson; + if (!(rVal >>= sComplexColorJson)) + return false; + + if (sComplexColorJson.isEmpty()) + return false; + + OString aJSON = OUStringToOString(sComplexColorJson, RTL_TEXTENCODING_ASCII_US); + model::ComplexColor aComplexColor; + model::color::convertFromJSON(aJSON, aComplexColor); + setComplexColor(aComplexColor); + } + break; + default: + { + Color nValue; + if(!(rVal >>= nValue )) + return false; + + SetColorValue( nValue ); + + } + break; + } + return true; +} + +void XColorItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XColorItem")); + if (Which() == SDRATTR_SHADOWCOLOR) + { + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWCOLOR")); + } + else if (Which() == XATTR_FILLCOLOR) + { + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("XATTR_FILLCOLOR")); + } + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aColor"), + BAD_CAST(aColor.AsRGBHexString().toUtf8().getStr())); + + NameOrIndex::dumpAsXml(pWriter); + + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("complex-color")); + + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("scheme-index"), + BAD_CAST(OString::number(sal_Int16(maComplexColor.getThemeColorType())).getStr())); + + for (auto const& rTransform : maComplexColor.getTransformations()) + { + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("transformation")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("type"), + BAD_CAST(OString::number(sal_Int16(rTransform.meType)).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), + BAD_CAST(OString::number(rTransform.mnValue).getStr())); + (void)xmlTextWriterEndElement(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); + + (void)xmlTextWriterEndElement(pWriter); +} + +// --- line attributes --- + + +SfxPoolItem* XLineStyleItem::CreateDefault() { return new XLineStyleItem; } + +XLineStyleItem::XLineStyleItem(css::drawing::LineStyle eTheLineStyle) : + SfxEnumItem(XATTR_LINESTYLE, eTheLineStyle) +{ +} + +XLineStyleItem* XLineStyleItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineStyleItem( *this ); +} + +bool XLineStyleItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + + TranslateId pId; + + switch( GetValue() ) + { + case css::drawing::LineStyle_NONE: + pId = RID_SVXSTR_INVISIBLE; + break; + case css::drawing::LineStyle_SOLID: + pId = RID_SVXSTR_SOLID; + break; + default: break; + } + + if (pId) + rText = SvxResId(pId); + return true; +} + +bool XLineStyleItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + css::drawing::LineStyle eLS = GetValue(); + rVal <<= eLS; + return true; +} + +bool XLineStyleItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + css::drawing::LineStyle eLS; + if(!(rVal >>= eLS )) + { + // also try an int (for Basic) + sal_Int32 nLS = 0; + if(!(rVal >>= nLS)) + return false; + eLS = static_cast<css::drawing::LineStyle>(nLS); + } + + SetValue( eLS ); + return true; +} + +sal_uInt16 XLineStyleItem::GetValueCount() const +{ + return 3; +} + +XDash::XDash(css::drawing::DashStyle eTheDash, sal_uInt16 nTheDots, double nTheDotLen, + sal_uInt16 nTheDashes, double nTheDashLen, double nTheDistance) : + eDash(eTheDash), + nDots(nTheDots), + nDashes(nTheDashes), + nDotLen(nTheDotLen), + nDashLen(nTheDashLen), + nDistance(nTheDistance) +{ +} + +bool XDash::operator==(const XDash& rDash) const +{ + return ( eDash == rDash.eDash && + nDots == rDash.nDots && + nDotLen == rDash.nDotLen && + nDashes == rDash.nDashes && + nDashLen == rDash.nDashLen && + nDistance == rDash.nDistance ); +} + +// XDash is translated into an array of doubles which describe the lengths of the +// dashes, dots and empty passages. It returns the complete length of the full DashDot +// sequence and fills the given vector of doubles accordingly (also resizing, so deleting it). +const double SMALLEST_DASH_WIDTH(26.95); + +double XDash::CreateDotDashArray(::std::vector< double >& rDotDashArray, double fLineWidth) const +{ + double fFullDotDashLen(0.0); + const sal_uInt16 nNumDotDashArray = (GetDots() + GetDashes()) * 2; + rDotDashArray.resize( nNumDotDashArray, 0.0 ); + sal_uInt16 a; + sal_uInt16 nIns(0); + double fDashDotDistance = GetDistance(); + double fSingleDashLen = GetDashLen(); + double fSingleDotLen = GetDotLen(); + + if (fLineWidth == 0.0) + fLineWidth = SMALLEST_DASH_WIDTH; + + if(GetDashStyle() == css::drawing::DashStyle_RECTRELATIVE || GetDashStyle() == css::drawing::DashStyle_ROUNDRELATIVE) + { + double fFactor = fLineWidth / 100.0; + + if(GetDashes()) + { + if(GetDashLen()) + { + // is a dash + fSingleDashLen *= fFactor; + } + else + { + // is a dot + fSingleDashLen = fLineWidth; + } + } + + if(GetDots()) + { + if(GetDotLen()) + { + // is a dash + fSingleDotLen *= fFactor; + } + else + { + // is a dot + fSingleDotLen = fLineWidth; + } + } + + if(GetDashes() || GetDots()) + { + if(GetDistance()) + { + // dash as distance + fDashDotDistance *= fFactor; + } + else + { + // dot as distance + fDashDotDistance = fLineWidth; + } + } + } + else + { + // absolute values + if(GetDashes()) + { + if(GetDashLen()) + { + // is a dash + if(fSingleDashLen < SMALLEST_DASH_WIDTH) + { + fSingleDashLen = SMALLEST_DASH_WIDTH; + } + } + else + { + // is a dot + if(fSingleDashLen < fLineWidth) + { + fSingleDashLen = fLineWidth; + } + } + } + + if(GetDots()) + { + if(GetDotLen()) + { + // is a dash + if(fSingleDotLen < SMALLEST_DASH_WIDTH) + { + fSingleDotLen = SMALLEST_DASH_WIDTH; + } + } + else + { + // is a dot + if(fSingleDotLen < fLineWidth) + { + fSingleDotLen = fLineWidth; + } + } + } + + if(GetDashes() || GetDots()) + { + if(GetDistance()) + { + // dash as distance + if(fDashDotDistance < SMALLEST_DASH_WIDTH) + { + fDashDotDistance = SMALLEST_DASH_WIDTH; + } + } + else + { + // dot as distance + if(fDashDotDistance < fLineWidth) + { + fDashDotDistance = fLineWidth; + } + } + } + } + + for(a=0;a<GetDots();a++) + { + rDotDashArray[nIns++] = fSingleDotLen; + fFullDotDashLen += fSingleDotLen; + rDotDashArray[nIns++] = fDashDotDistance; + fFullDotDashLen += fDashDotDistance; + } + + for(a=0;a<GetDashes();a++) + { + rDotDashArray[nIns++] = fSingleDashLen; + fFullDotDashLen += fSingleDashLen; + rDotDashArray[nIns++] = fDashDotDistance; + fFullDotDashLen += fDashDotDistance; + } + + return fFullDotDashLen; +} + +SfxPoolItem* XLineDashItem::CreateDefault() {return new XLineDashItem;} + +XLineDashItem::XLineDashItem(const OUString& rName, const XDash& rTheDash) : + NameOrIndex(XATTR_LINEDASH, rName), + aDash(rTheDash) +{ +} + +XLineDashItem::XLineDashItem(const XLineDashItem& rItem) : + NameOrIndex(rItem), + aDash(rItem.aDash) +{ +} + +XLineDashItem::XLineDashItem(const XDash& rTheDash) +: NameOrIndex( XATTR_LINEDASH, -1 ), + aDash(rTheDash) +{ +} + +XLineDashItem* XLineDashItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineDashItem(*this); +} + +bool XLineDashItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && + aDash == static_cast<const XLineDashItem&>(rItem).aDash ); +} + +bool XLineDashItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XLineDashItem::HasMetrics() const +{ + return true; +} + +void XLineDashItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv) +{ + aDash.SetDotLen( BigInt::Scale( aDash.GetDotLen(), nMul, nDiv ) ); + aDash.SetDashLen( BigInt::Scale( aDash.GetDashLen(), nMul, nDiv ) ); + aDash.SetDistance( BigInt::Scale( aDash.GetDistance(), nMul, nDiv ) ); +} + +bool XLineDashItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case 0: + { + css::drawing::LineDash aLineDash; + + const XDash& rXD = GetDashValue(); + aLineDash.Style = static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(rXD.GetDashStyle())); + aLineDash.Dots = rXD.GetDots(); + aLineDash.DotLen = rXD.GetDotLen(); + aLineDash.Dashes = rXD.GetDashes(); + aLineDash.DashLen = rXD.GetDashLen(); + aLineDash.Distance = rXD.GetDistance(); + + uno::Sequence< beans::PropertyValue > aPropSeq{ + comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())), + comphelper::makePropertyValue("LineDash", aLineDash) + }; + rVal <<= aPropSeq; + break; + } + + case MID_NAME: + { + rVal <<= SvxUnogetApiNameForItem(Which(), GetName()); + break; + } + + case MID_LINEDASH: + { + const XDash& rXD = GetDashValue(); + + css::drawing::LineDash aLineDash; + + aLineDash.Style = static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(rXD.GetDashStyle())); + aLineDash.Dots = rXD.GetDots(); + aLineDash.DotLen = rXD.GetDotLen(); + aLineDash.Dashes = rXD.GetDashes(); + aLineDash.DashLen = rXD.GetDashLen(); + aLineDash.Distance = rXD.GetDistance(); + + rVal <<= aLineDash; + break; + } + + case MID_LINEDASH_STYLE: + { + const XDash& rXD = GetDashValue(); + rVal <<= static_cast<css::drawing::DashStyle>(static_cast<sal_Int16>(rXD.GetDashStyle())); + break; + } + + case MID_LINEDASH_DOTS: + { + const XDash& rXD = GetDashValue(); + rVal <<= rXD.GetDots(); + break; + } + + case MID_LINEDASH_DOTLEN: + { + const XDash& rXD = GetDashValue(); + rVal <<= rXD.GetDotLen(); + break; + } + + case MID_LINEDASH_DASHES: + { + const XDash& rXD = GetDashValue(); + rVal <<= rXD.GetDashes(); + break; + } + + case MID_LINEDASH_DASHLEN: + { + const XDash& rXD = GetDashValue(); + rVal <<= rXD.GetDashLen(); + break; + } + + case MID_LINEDASH_DISTANCE: + { + const XDash& rXD = GetDashValue(); + rVal <<= rXD.GetDistance(); + break; + } + + default: OSL_FAIL("Wrong MemberId!"); return false; + } + + return true; +} + +bool XLineDashItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case 0: + { + uno::Sequence< beans::PropertyValue > aPropSeq; + + if ( rVal >>= aPropSeq ) + { + css::drawing::LineDash aLineDash; + OUString aName; + bool bLineDash( false ); + for ( const auto& rProp : std::as_const(aPropSeq) ) + { + if ( rProp.Name == "Name" ) + rProp.Value >>= aName; + else if ( rProp.Name == "LineDash" ) + { + if ( rProp.Value >>= aLineDash ) + bLineDash = true; + } + } + + SetName( aName ); + if ( bLineDash ) + { + XDash aXDash; + + aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(aLineDash.Style))); + aXDash.SetDots(aLineDash.Dots); + aXDash.SetDotLen(aLineDash.DotLen); + aXDash.SetDashes(aLineDash.Dashes); + aXDash.SetDashLen(aLineDash.DashLen); + aXDash.SetDistance(aLineDash.Distance); + + if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes())) + aXDash.SetDots(1); + + SetDashValue( aXDash ); + } + + return true; + } + + return false; + } + + case MID_NAME: + { + OUString aName; + if (!(rVal >>= aName)) + return false; + SetName( aName ); + break; + } + + case MID_LINEDASH: + { + css::drawing::LineDash aLineDash; + if(!(rVal >>= aLineDash)) + return false; + + XDash aXDash; + + aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(aLineDash.Style))); + aXDash.SetDots(aLineDash.Dots); + aXDash.SetDotLen(aLineDash.DotLen); + aXDash.SetDashes(aLineDash.Dashes); + aXDash.SetDashLen(aLineDash.DashLen); + aXDash.SetDistance(aLineDash.Distance); + + if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes())) + aXDash.SetDots(1); + + SetDashValue( aXDash ); + break; + } + + case MID_LINEDASH_STYLE: + { + sal_Int16 nVal = sal_Int16(); + if(!(rVal >>= nVal)) + return false; + + XDash aXDash = GetDashValue(); + aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(nVal))); + + if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes())) + aXDash.SetDots(1); + + SetDashValue( aXDash ); + + break; + } + + case MID_LINEDASH_DOTS: + case MID_LINEDASH_DASHES: + { + sal_Int16 nVal = sal_Int16(); + if(!(rVal >>= nVal)) + return false; + + XDash aXDash = GetDashValue(); + if ( nMemberId == MID_LINEDASH_DOTS ) + aXDash.SetDots( nVal ); + else + aXDash.SetDashes( nVal ); + + if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes())) + aXDash.SetDots(1); + + SetDashValue( aXDash ); + break; + } + + case MID_LINEDASH_DOTLEN: + case MID_LINEDASH_DASHLEN: + case MID_LINEDASH_DISTANCE: + { + sal_uInt32 nVal = 0; + if(!(rVal >>= nVal)) + return false; + + XDash aXDash = GetDashValue(); + if ( nMemberId == MID_LINEDASH_DOTLEN ) + aXDash.SetDotLen( nVal ); + else if ( nMemberId == MID_LINEDASH_DASHLEN ) + aXDash.SetDashLen( nVal ); + else + aXDash.SetDistance( nVal ); + + if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes())) + aXDash.SetDots(1); + + SetDashValue( aXDash ); + break; + } + } + + return true; +} + +bool XLineDashItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 ) +{ + return static_cast<const XLineDashItem*>(p1)->GetDashValue() == static_cast<const XLineDashItem*>(p2)->GetDashValue(); +} + +std::unique_ptr<XLineDashItem> XLineDashItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + const OUString aUniqueName = NameOrIndex::CheckNamedItem( + this, XATTR_LINEDASH, &pModel->GetItemPool(), + XLineDashItem::CompareValueFunc, RID_SVXSTR_DASH20, + pModel->GetPropertyList( XPropertyListType::Dash ) ); + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() ) + return std::make_unique<XLineDashItem>( aUniqueName, aDash ); + } + + return nullptr; +} + +SfxPoolItem* XLineWidthItem::CreateDefault() {return new XLineWidthItem;} + +XLineWidthItem::XLineWidthItem(tools::Long nWidth) : + SfxMetricItem(XATTR_LINEWIDTH, nWidth) +{ +} + +XLineWidthItem* XLineWidthItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineWidthItem(*this); +} + +bool XLineWidthItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit eCoreUnit, + MapUnit ePresUnit, + OUString& rText, const IntlWrapper& rIntl +) const +{ + rText = GetMetricText( static_cast<tools::Long>(GetValue()), + eCoreUnit, ePresUnit, &rIntl) + + " " + EditResId( GetMetricId( ePresUnit) ); + return true; +} + +bool XLineWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + sal_Int32 nValue = GetValue(); + if( 0 != (nMemberId&CONVERT_TWIPS) ) + nValue = convertTwipToMm100(nValue); + + rVal <<= nValue; + return true; +} + +bool XLineWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + if( 0 != (nMemberId&CONVERT_TWIPS) ) + nValue = o3tl::toTwips(nValue, o3tl::Length::mm100); + + SetValue( nValue ); + return true; +} + +SfxPoolItem* XLineColorItem::CreateDefault() { return new XLineColorItem; } + +XLineColorItem::XLineColorItem(sal_Int32 nIndex, const Color& rTheColor) : + XColorItem(XATTR_LINECOLOR, nIndex, rTheColor) +{ +} + +XLineColorItem::XLineColorItem(const OUString& rName, const Color& rTheColor) : + XColorItem(XATTR_LINECOLOR, rName, rTheColor) +{ +} + +XLineColorItem* XLineColorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineColorItem(*this); +} + +bool XLineColorItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XLineColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId) const +{ + nMemberId &= ~CONVERT_TWIPS; + switch (nMemberId) + { + case MID_COMPLEX_COLOR: + { + auto xComplexColor = model::color::createXComplexColor(getComplexColor()); + rVal <<= xComplexColor; + break; + } + case MID_COMPLEX_COLOR_JSON: + { + rVal <<= OStringToOUString(model::color::convertToJSON(getComplexColor()), RTL_TEXTENCODING_UTF8); + break; + } + default: + { + rVal <<= GetColorValue().GetRGBColor(); + break; + } + } + return true; +} + +bool XLineColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId) +{ + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_COMPLEX_COLOR: + { + css::uno::Reference<css::util::XComplexColor> xComplexColor; + if (!(rVal >>= xComplexColor)) + return false; + setComplexColor(model::color::getFromXComplexColor(xComplexColor)); + } + break; + case MID_COMPLEX_COLOR_JSON: + { + OUString sComplexColorJson; + if (!(rVal >>= sComplexColorJson)) + return false; + + if (sComplexColorJson.isEmpty()) + return false; + model::ComplexColor aComplexColor; + OString aJSON = OUStringToOString(sComplexColorJson, RTL_TEXTENCODING_ASCII_US); + model::color::convertFromJSON(aJSON, aComplexColor); + setComplexColor(aComplexColor); + } + break; + default: + { + sal_Int32 nValue; + if(!(rVal >>= nValue )) + return false; + + SetColorValue( Color(ColorTransparency, nValue) ); + break; + } + } + return true; +} + + +SfxPoolItem* XLineStartItem::CreateDefault() {return new XLineStartItem;} + +XLineStartItem::XLineStartItem(sal_Int32 nIndex) +: NameOrIndex(XATTR_LINESTART, nIndex) +{ +} + +XLineStartItem::XLineStartItem(const OUString& rName, basegfx::B2DPolyPolygon aPolyPolygon) +: NameOrIndex(XATTR_LINESTART, rName), + maPolyPolygon(std::move(aPolyPolygon)) +{ +} + +XLineStartItem::XLineStartItem(const XLineStartItem& rItem) +: NameOrIndex(rItem), + maPolyPolygon(rItem.maPolyPolygon) +{ +} + +XLineStartItem::XLineStartItem(basegfx::B2DPolyPolygon aPolyPolygon) +: NameOrIndex( XATTR_LINESTART, -1 ), + maPolyPolygon(std::move(aPolyPolygon)) +{ +} + +XLineStartItem* XLineStartItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineStartItem(*this); +} + +bool XLineStartItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && static_cast<const XLineStartItem&>(rItem).maPolyPolygon == maPolyPolygon ); +} + +bool XLineStartItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XLineStartItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + if( nMemberId == MID_NAME ) + { + rVal <<= SvxUnogetApiNameForItem(Which(), GetName()); + } + else + { + css::drawing::PolyPolygonBezierCoords aBezier; + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( maPolyPolygon, aBezier ); + rVal <<= aBezier; + } + + return true; +} + +bool XLineStartItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + if( nMemberId == MID_NAME ) + { + return false; + } + else + { + maPolyPolygon.clear(); + + if( rVal.hasValue() ) + { + auto pCoords = o3tl::tryAccess<css::drawing::PolyPolygonBezierCoords>( + rVal); + if( !pCoords ) + return false; + + if( pCoords->Coordinates.getLength() > 0 ) + { + maPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( *pCoords ); + // #i72807# close line start/end polygons hard + // maPolyPolygon.setClosed(true); + } + } + } + + return true; +} + +/** this function searches in both the models pool and the styles pool for XLineStartItem + and XLineEndItem with the same value or name and returns an item with the value of + this item and a unique name for an item with this value. */ +std::unique_ptr<XLineStartItem> XLineStartItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + std::unique_ptr<XLineStartItem> pTempItem; + const XLineStartItem* pLineStartItem = this; + + OUString aUniqueName( GetName() ); + + if( !maPolyPolygon.count() ) + { + // if the polygon is empty, check if the name is empty + if( aUniqueName.isEmpty() ) + return nullptr; + + // force empty name for empty polygons + return std::make_unique<XLineStartItem>( "", maPolyPolygon ); + } + + if( maPolyPolygon.count() > 1 ) + { + // check if the polygon is closed + if(!maPolyPolygon.isClosed()) + { + // force a closed polygon + basegfx::B2DPolyPolygon aNew(maPolyPolygon); + aNew.setClosed(true); + pTempItem.reset(new XLineStartItem( aUniqueName, std::move(aNew) )); + pLineStartItem = pTempItem.get(); + } + } + + bool bForceNew = false; + + // 2. if we have a name check if there is already an item with the + // same name in the documents pool with a different line end or start + + const SfxItemPool& rPool1 = pModel->GetItemPool(); + if (!aUniqueName.isEmpty()) + { + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineStartValue() != pLineStartItem->GetLineStartValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + + if( !bForceNew ) + { + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineEndValue() != pLineStartItem->GetLineStartValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + } + } + + const SfxItemPool* pPool2 = pModel->GetStyleSheetPool() ? &pModel->GetStyleSheetPool()->GetPool() : nullptr; + if( !aUniqueName.isEmpty() && pPool2) + { + for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineStartValue() != pLineStartItem->GetLineStartValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + + if( !bForceNew ) + { + for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineEndValue() != pLineStartItem->GetLineStartValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + } + } + + // if we have no name yet, find existing item with same content or + // create a unique name + if( aUniqueName.isEmpty() ) + { + bool bFoundExisting = false; + + sal_Int32 nUserIndex = 1; + const OUString aUser(SvxResId(RID_SVXSTR_LINEEND)); + + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if (pItem && !pItem->GetName().isEmpty()) + { + if (!bForceNew && pItem->GetLineStartValue() == pLineStartItem->GetLineStartValue()) + { + aUniqueName = pItem->GetName(); + bFoundExisting = true; + break; + } + + if (pItem->GetName().startsWith(aUser)) + { + sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength())); + if (nThisIndex >= nUserIndex) + nUserIndex = nThisIndex + 1; + } + } + } + + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if (pItem && !pItem->GetName().isEmpty()) + { + if (!bForceNew && pItem->GetLineEndValue() == pLineStartItem->GetLineStartValue()) + { + aUniqueName = pItem->GetName(); + bFoundExisting = true; + break; + } + + if (pItem->GetName().startsWith(aUser)) + { + sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength())); + if (nThisIndex >= nUserIndex) + nUserIndex = nThisIndex + 1; + } + } + } + + if( !bFoundExisting ) + { + aUniqueName = aUser + " " + OUString::number( nUserIndex ); + } + } + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() || pTempItem ) + { + if( pTempItem ) + { + pTempItem->SetName( aUniqueName ); + return pTempItem; + } + else + { + return std::make_unique<XLineStartItem>( aUniqueName, maPolyPolygon ); + } + } + } + + return nullptr; +} + +SfxPoolItem* XLineEndItem::CreateDefault() {return new XLineEndItem;} + +XLineEndItem::XLineEndItem(sal_Int32 nIndex) +: NameOrIndex(XATTR_LINEEND, nIndex) +{ +} + +XLineEndItem::XLineEndItem(const OUString& rName, basegfx::B2DPolyPolygon aPolyPolygon) +: NameOrIndex(XATTR_LINEEND, rName), + maPolyPolygon(std::move(aPolyPolygon)) +{ +} + +XLineEndItem::XLineEndItem(const XLineEndItem& rItem) +: NameOrIndex(rItem), + maPolyPolygon(rItem.maPolyPolygon) +{ +} + +XLineEndItem::XLineEndItem(basegfx::B2DPolyPolygon aPolyPolygon) +: NameOrIndex( XATTR_LINEEND, -1 ), + maPolyPolygon(std::move(aPolyPolygon)) +{ +} + +XLineEndItem* XLineEndItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineEndItem(*this); +} + +bool XLineEndItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && static_cast<const XLineEndItem&>(rItem).maPolyPolygon == maPolyPolygon ); +} + + +/** this function searches in both the models pool and the styles pool for XLineStartItem + and XLineEndItem with the same value or name and returns an item with the value of + this item and a unique name for an item with this value. */ +std::unique_ptr<XLineEndItem> XLineEndItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + std::unique_ptr<XLineEndItem> pTempItem; + const XLineEndItem* pLineEndItem = this; + + OUString aUniqueName( GetName() ); + + if( !maPolyPolygon.count() ) + { + // if the polygon is empty, check if the name is empty + if( aUniqueName.isEmpty() ) + return nullptr; + + // force empty name for empty polygons + return std::make_unique<XLineEndItem>( "", maPolyPolygon ); + } + + if( maPolyPolygon.count() > 1 ) + { + // check if the polygon is closed + if(!maPolyPolygon.isClosed()) + { + // force a closed polygon + basegfx::B2DPolyPolygon aNew(maPolyPolygon); + aNew.setClosed(true); + pTempItem.reset(new XLineEndItem( aUniqueName, std::move(aNew) )); + pLineEndItem = pTempItem.get(); + } + } + + bool bForceNew = false; + + // 2. if we have a name check if there is already an item with the + // same name in the documents pool with a different line end or start + + const SfxItemPool& rPool1 = pModel->GetItemPool(); + if (!aUniqueName.isEmpty()) + { + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineStartValue() != pLineEndItem->GetLineEndValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + + if( !bForceNew ) + { + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineEndValue() != pLineEndItem->GetLineEndValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + } + } + + const SfxItemPool* pPool2 = pModel->GetStyleSheetPool() ? &pModel->GetStyleSheetPool()->GetPool() : nullptr; + if( !aUniqueName.isEmpty() && pPool2) + { + for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineStartValue() != pLineEndItem->GetLineEndValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + + if( !bForceNew ) + { + for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) ) + { + // if there is already an item with the same name and the same + // value it's ok to set it + if( pItem->GetLineEndValue() != pLineEndItem->GetLineEndValue() ) + { + // same name but different value, we need a new name for this item + aUniqueName.clear(); + bForceNew = true; + } + break; + } + } + } + } + + // if we have no name yet, find existing item with same content or + // create a unique name + if( aUniqueName.isEmpty() ) + { + bool bFoundExisting = false; + + sal_Int32 nUserIndex = 1; + const OUString aUser(SvxResId(RID_SVXSTR_LINEEND)); + + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART)) + { + auto pItem = dynamic_cast<const XLineStartItem*>(p); + + if (pItem && !pItem->GetName().isEmpty()) + { + if (!bForceNew && pItem->GetLineStartValue() == pLineEndItem->GetLineEndValue()) + { + aUniqueName = pItem->GetName(); + bFoundExisting = true; + break; + } + + if (pItem->GetName().startsWith(aUser)) + { + sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength())); + if (nThisIndex >= nUserIndex) + nUserIndex = nThisIndex + 1; + } + } + } + + for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND)) + { + auto pItem = dynamic_cast<const XLineEndItem*>(p); + + if (pItem && !pItem->GetName().isEmpty()) + { + if (!bForceNew && pItem->GetLineEndValue() == pLineEndItem->GetLineEndValue()) + { + aUniqueName = pItem->GetName(); + bFoundExisting = true; + break; + } + + if (pItem->GetName().startsWith(aUser)) + { + sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength())); + if (nThisIndex >= nUserIndex) + nUserIndex = nThisIndex + 1; + } + } + } + + if( !bFoundExisting ) + { + aUniqueName = aUser + " " + OUString::number( nUserIndex ); + } + } + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() || pTempItem ) + { + if( pTempItem ) + { + pTempItem->SetName( aUniqueName ); + return pTempItem; + } + else + { + return std::make_unique<XLineEndItem>( aUniqueName, maPolyPolygon ); + } + } + } + + return nullptr; +} + +bool XLineEndItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XLineEndItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + if( nMemberId == MID_NAME ) + { + rVal <<= SvxUnogetApiNameForItem(Which(), GetName()); + } + else + { + css::drawing::PolyPolygonBezierCoords aBezier; + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( maPolyPolygon, aBezier ); + rVal <<= aBezier; + } + return true; +} + +bool XLineEndItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + if( nMemberId == MID_NAME ) + { + return false; + } + else + { + maPolyPolygon.clear(); + + if( rVal.hasValue() ) + { + auto pCoords = o3tl::tryAccess<css::drawing::PolyPolygonBezierCoords>( + rVal); + if( !pCoords ) + return false; + + if( pCoords->Coordinates.getLength() > 0 ) + { + maPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( *pCoords ); + // #i72807# close line start/end polygons hard + // maPolyPolygon.setClosed(true); + } + } + } + + return true; +} + +XLineStartWidthItem::XLineStartWidthItem(tools::Long nWidth) : + SfxMetricItem(XATTR_LINESTARTWIDTH, nWidth) +{ +} + +XLineStartWidthItem* XLineStartWidthItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineStartWidthItem(*this); +} + +bool XLineStartWidthItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit eCoreUnit, + MapUnit ePresUnit, + OUString& rText, const IntlWrapper& rIntl +) const +{ + rText = GetMetricText( static_cast<tools::Long>(GetValue()), + eCoreUnit, ePresUnit, &rIntl) + + " " + EditResId( GetMetricId( ePresUnit) ); + return true; +} + +bool XLineStartWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + rVal <<= GetValue(); + return true; +} + +bool XLineStartWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + SetValue( nValue ); + return true; +} + +XLineEndWidthItem::XLineEndWidthItem(tools::Long nWidth) : + SfxMetricItem(XATTR_LINEENDWIDTH, nWidth) +{ +} + +XLineEndWidthItem* XLineEndWidthItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineEndWidthItem(*this); +} + +bool XLineEndWidthItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit eCoreUnit, + MapUnit ePresUnit, + OUString& rText, const IntlWrapper& rIntl +) const +{ + rText = GetMetricText( static_cast<tools::Long>(GetValue()), + eCoreUnit, ePresUnit, &rIntl) + + " " + EditResId( GetMetricId( ePresUnit) ); + return true; +} + +bool XLineEndWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + rVal <<= GetValue(); + return true; +} + +bool XLineEndWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + SetValue( nValue ); + return true; +} + +XLineStartCenterItem::XLineStartCenterItem(bool bStartCenter) : + SfxBoolItem(XATTR_LINESTARTCENTER, bStartCenter) +{ +} + +XLineStartCenterItem* XLineStartCenterItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineStartCenterItem(*this); +} + +bool XLineStartCenterItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = SvxResId(GetValue() ? RID_SVXSTR_CENTERED : RID_SVXSTR_NOTCENTERED); + return true; +} + +bool XLineStartCenterItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + bool bValue = GetValue(); + rVal <<= bValue; + return true; +} + +bool XLineStartCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + auto b = o3tl::tryAccess<bool>(rVal); + if( !b.has_value() ) + return false; + + SetValue( *b ); + return true; +} + +XLineEndCenterItem::XLineEndCenterItem(bool bEndCenter) : + SfxBoolItem(XATTR_LINEENDCENTER, bEndCenter) +{ +} + +XLineEndCenterItem* XLineEndCenterItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineEndCenterItem(*this); +} + +bool XLineEndCenterItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = SvxResId(GetValue() ? RID_SVXSTR_CENTERED : RID_SVXSTR_NOTCENTERED); + return true; +} + +bool XLineEndCenterItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + bool bValue = GetValue(); + rVal <<= bValue; + return true; +} + +bool XLineEndCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + auto b = o3tl::tryAccess<bool>(rVal); + if( !b.has_value() ) + return false; + + SetValue( *b ); + return true; +} + +// --- fill attributes --- + + +SfxPoolItem* XFillStyleItem::CreateDefault() { return new XFillStyleItem; } + +XFillStyleItem::XFillStyleItem(drawing::FillStyle eFillStyle) : + SfxEnumItem(XATTR_FILLSTYLE, eFillStyle) +{ +} + +XFillStyleItem* XFillStyleItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillStyleItem( *this ); +} + +bool XFillStyleItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + + TranslateId pId; + + switch( GetValue() ) + { + case drawing::FillStyle_NONE: + pId = RID_SVXSTR_INVISIBLE; + break; + case drawing::FillStyle_SOLID: + pId = RID_SVXSTR_SOLID; + break; + case drawing::FillStyle_GRADIENT: + pId = RID_SVXSTR_GRADIENT; + break; + case drawing::FillStyle_HATCH: + pId = RID_SVXSTR_HATCH; + break; + case drawing::FillStyle_BITMAP: + pId = RID_SVXSTR_BITMAP; + break; + default: break; + } + + if (pId) + rText = SvxResId(pId); + return true; +} + +sal_uInt16 XFillStyleItem::GetValueCount() const +{ + return 5; +} + +bool XFillStyleItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + css::drawing::FillStyle eFS = GetValue(); + + rVal <<= eFS; + + return true; +} + +bool XFillStyleItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + css::drawing::FillStyle eFS; + if(!(rVal >>= eFS)) + { + // also try an int (for Basic) + sal_Int32 nFS = 0; + if(!(rVal >>= nFS)) + return false; + eFS = static_cast<css::drawing::FillStyle>(nFS); + } + + SetValue( eFS ); + + return true; +} + +void XFillStyleItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillStyleItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(static_cast<sal_Int16>(GetValue())).getStr())); + + OUString aPresentation; + IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag()); + GetPresentation(SfxItemPresentation::Nameless, MapUnit::Map100thMM, MapUnit::Map100thMM, aPresentation, aIntlWrapper); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("presentation"), BAD_CAST(aPresentation.toUtf8().getStr())); + + (void)xmlTextWriterEndElement(pWriter); +} + +boost::property_tree::ptree XFillStyleItem::dumpAsJSON() const +{ + boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON(); + + if (Which() == XATTR_FILLSTYLE) + aTree.put("commandName", ".uno:FillStyle"); + + OUString sValue; + + switch( GetValue() ) + { + case drawing::FillStyle_NONE: + sValue = "NONE"; + break; + case drawing::FillStyle_SOLID: + sValue = "SOLID"; + break; + case drawing::FillStyle_GRADIENT: + sValue = "GRADIENT"; + break; + case drawing::FillStyle_HATCH: + sValue = "HATCH"; + break; + case drawing::FillStyle_BITMAP: + sValue = "BITMAP"; + break; + default: break; + } + + aTree.put("state", sValue); + + return aTree; +} + + +SfxPoolItem* XFillColorItem::CreateDefault() { return new XFillColorItem; } + +XFillColorItem::XFillColorItem(sal_Int32 nIndex, const Color& rTheColor) : + XColorItem(XATTR_FILLCOLOR, nIndex, rTheColor) +{ +} + +XFillColorItem::XFillColorItem(const OUString& rName, const Color& rTheColor) : + XColorItem(XATTR_FILLCOLOR, rName, rTheColor) +{ +} + +XFillColorItem* XFillColorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillColorItem(*this); +} + +bool XFillColorItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XFillColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + switch (nMemberId) + { + case MID_COLOR_THEME_INDEX: + { + rVal <<= sal_Int16(getComplexColor().getThemeColorType()); + break; + } + case MID_COLOR_LUM_MOD: + { + sal_Int16 nValue = 10000; + for (auto const& rTransform : getComplexColor().getTransformations()) + { + if (rTransform.meType == model::TransformationType::LumMod) + nValue = rTransform.mnValue; + } + rVal <<= nValue; + break; + } + case MID_COLOR_LUM_OFF: + { + sal_Int16 nValue = 0; + for (auto const& rTransform : getComplexColor().getTransformations()) + { + if (rTransform.meType == model::TransformationType::LumOff) + nValue = rTransform.mnValue; + } + rVal <<= nValue; + break; + } + case MID_COMPLEX_COLOR: + { + auto xComplexColor = model::color::createXComplexColor(getComplexColor()); + rVal <<= xComplexColor; + break; + } + case MID_COMPLEX_COLOR_JSON: + { + rVal <<= OStringToOUString(model::color::convertToJSON(getComplexColor()), RTL_TEXTENCODING_UTF8); + break; + } + default: + { + rVal <<= GetColorValue().GetRGBColor(); + break; + } + } + + return true; +} + +bool XFillColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_COLOR_THEME_INDEX: + { + sal_Int16 nIndex = -1; + if (!(rVal >>= nIndex)) + return false; + getComplexColor().setThemeColor(model::convertToThemeColorType(nIndex)); + } + break; + case MID_COLOR_LUM_MOD: + { + sal_Int16 nLumMod = 10000; + if (!(rVal >>= nLumMod)) + return false; + getComplexColor().removeTransformations(model::TransformationType::LumMod); + getComplexColor().addTransformation({model::TransformationType::LumMod, nLumMod}); + } + break; + case MID_COLOR_LUM_OFF: + { + sal_Int16 nLumOff = 0; + if (!(rVal >>= nLumOff)) + return false; + getComplexColor().removeTransformations(model::TransformationType::LumOff); + getComplexColor().addTransformation({model::TransformationType::LumOff, nLumOff}); + } + break; + case MID_COMPLEX_COLOR: + { + css::uno::Reference<css::util::XComplexColor> xComplexColor; + if (!(rVal >>= xComplexColor)) + return false; + setComplexColor(model::color::getFromXComplexColor(xComplexColor)); + } + break; + case MID_COMPLEX_COLOR_JSON: + { + OUString sComplexColorJson; + if (!(rVal >>= sComplexColorJson)) + return false; + + if (sComplexColorJson.isEmpty()) + return false; + + OString aJSON = OUStringToOString(sComplexColorJson, RTL_TEXTENCODING_ASCII_US); + model::ComplexColor aComplexColor; + model::color::convertFromJSON(aJSON, aComplexColor); + setComplexColor(aComplexColor); + } + break; + default: + { + Color nValue; + if(!(rVal >>= nValue )) + return false; + + SetColorValue( nValue ); + + } + break; + } + return true; +} + +void XFillColorItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillColorItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + + XColorItem::dumpAsXml(pWriter); + + (void)xmlTextWriterEndElement(pWriter); +} + +boost::property_tree::ptree XFillColorItem::dumpAsJSON() const +{ + boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON(); + + if (Which() == XATTR_FILLCOLOR) + aTree.put("commandName", ".uno:FillPageColor"); + + aTree.put("state", GetColorValue().AsRGBHexString()); + + return aTree; +} + +XSecondaryFillColorItem::XSecondaryFillColorItem(const OUString& rName, const Color& rTheColor) : + XColorItem(XATTR_SECONDARYFILLCOLOR, rName, rTheColor) +{ +} + +XSecondaryFillColorItem* XSecondaryFillColorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XSecondaryFillColorItem(*this); +} + +bool XSecondaryFillColorItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +SfxPoolItem* XFillGradientItem::CreateDefault() { return new XFillGradientItem; } + +XFillGradientItem::XFillGradientItem(sal_Int32 nIndex, + const basegfx::BGradient& rTheGradient) : + NameOrIndex(XATTR_FILLGRADIENT, nIndex), + aGradient(rTheGradient) +{ +} + +XFillGradientItem::XFillGradientItem(const OUString& rName, + const basegfx::BGradient& rTheGradient, TypedWhichId<XFillGradientItem> nWhich) + : NameOrIndex(nWhich, rName) + , aGradient(rTheGradient) +{ +} + +XFillGradientItem::XFillGradientItem(const XFillGradientItem& rItem) : + NameOrIndex(rItem), + aGradient(rItem.aGradient) +{ +} + +XFillGradientItem::XFillGradientItem( const basegfx::BGradient& rTheGradient ) +: NameOrIndex( XATTR_FILLGRADIENT, -1 ), + aGradient(rTheGradient) +{ +} + +XFillGradientItem* XFillGradientItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillGradientItem(*this); +} + +bool XFillGradientItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && + aGradient == static_cast<const XFillGradientItem&>(rItem).aGradient ); +} + +const basegfx::BGradient& XFillGradientItem::GetGradientValue() const // GetValue -> GetGradientValue +{ + if (!IsIndex()) + return aGradient; + // ToDo: This should fail. We never called this code with a table so this should always + // have failed. Thus, I'm thinking that XFillGradientItem can't be an Index. + return aGradient; +} + +bool XFillGradientItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XFillGradientItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case 0: + { + // fill values + const css::awt::Gradient2 aGradient2 = model::gradient::createUnoGradient2(GetGradientValue()); + + // create sequence + uno::Sequence< beans::PropertyValue > aPropSeq{ + comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())), + comphelper::makePropertyValue("FillGradient", aGradient2) + }; + rVal <<= aPropSeq; + break; + } + + case MID_FILLGRADIENT: + { + // fill values + const css::awt::Gradient2 aGradient2 = model::gradient::createUnoGradient2(GetGradientValue()); + + // create sequence + rVal <<= aGradient2; + break; + } + + case MID_NAME: + { + rVal <<= SvxUnogetApiNameForItem(Which(), GetName()); + break; + } + + case MID_GRADIENT_COLORSTOPSEQUENCE: + { + // fill values + const css::awt::ColorStopSequence aColorStopSequence = model::gradient::createColorStopSequence(GetGradientValue().GetColorStops()); + + // create sequence + rVal <<= aColorStopSequence; + break; + } + + case MID_GRADIENT_STYLE: rVal <<= static_cast<sal_Int16>(GetGradientValue().GetGradientStyle()); break; + case MID_GRADIENT_STARTCOLOR: rVal <<= Color(GetGradientValue().GetColorStops().front().getStopColor()); break; + case MID_GRADIENT_ENDCOLOR: rVal <<= Color(GetGradientValue().GetColorStops().back().getStopColor()); break; + case MID_GRADIENT_ANGLE: rVal <<= static_cast<sal_Int16>(GetGradientValue().GetAngle()); break; + case MID_GRADIENT_BORDER: rVal <<= GetGradientValue().GetBorder(); break; + case MID_GRADIENT_XOFFSET: rVal <<= GetGradientValue().GetXOffset(); break; + case MID_GRADIENT_YOFFSET: rVal <<= GetGradientValue().GetYOffset(); break; + case MID_GRADIENT_STARTINTENSITY: rVal <<= GetGradientValue().GetStartIntens(); break; + case MID_GRADIENT_ENDINTENSITY: rVal <<= GetGradientValue().GetEndIntens(); break; + case MID_GRADIENT_STEPCOUNT: rVal <<= GetGradientValue().GetSteps(); break; + + default: OSL_FAIL("Wrong MemberId!"); return false; + } + + return true; +} + +bool XFillGradientItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case 0: + { + uno::Sequence< beans::PropertyValue > aPropSeq; + css::uno::Any aGradientAny; + + if ( rVal >>= aPropSeq ) + { + OUString aName; + + for ( const auto& rProp : std::as_const(aPropSeq) ) + { + if ( rProp.Name == "Name" ) + rProp.Value >>= aName; + else if ( rProp.Name == "FillGradient" ) + aGradientAny = rProp.Value; + } + + SetName( aName ); + + if (aGradientAny.hasValue() && (aGradientAny.has<css::awt::Gradient>() || aGradientAny.has<css::awt::Gradient2>())) + { + SetGradientValue(model::gradient::getFromAny(aGradientAny)); + } + + return true; + } + + return false; + } + + case MID_NAME: + { + OUString aName; + if (!(rVal >>= aName )) + return false; + SetName( aName ); + break; + } + + case MID_FILLGRADIENT: + { + if (rVal.hasValue() && (rVal.has<css::awt::Gradient>() || rVal.has<css::awt::Gradient2>())) + { + SetGradientValue(model::gradient::getFromAny(rVal)); + } + + break; + } + + case MID_GRADIENT_COLORSTOPSEQUENCE: + { + // check if we have a awt::ColorStopSequence + if (rVal.hasValue() && rVal.has<css::awt::ColorStopSequence>()) + { + + const basegfx::BColorStops aColorStops = model::gradient::getColorStopsFromAny(rVal); + + if (!aColorStops.empty()) + { + basegfx::BGradient aBGradient(GetGradientValue()); + aBGradient.SetColorStops(aColorStops); + SetGradientValue(aBGradient); + } + } + break; + } + + case MID_GRADIENT_STARTCOLOR: + case MID_GRADIENT_ENDCOLOR: + { + Color nVal; + if(!(rVal >>= nVal )) + return false; + + basegfx::BGradient aBGradient(GetGradientValue()); + basegfx::BColorStops aNewColorStops(aBGradient.GetColorStops()); + + if ( nMemberId == MID_GRADIENT_STARTCOLOR ) + { + aNewColorStops.replaceStartColor(nVal.getBColor()); + } + else + { + aNewColorStops.replaceEndColor(nVal.getBColor()); + } + + aBGradient.SetColorStops(aNewColorStops); + SetGradientValue( aBGradient ); + break; + } + + case MID_GRADIENT_STYLE: + case MID_GRADIENT_ANGLE: + case MID_GRADIENT_BORDER: + case MID_GRADIENT_STARTINTENSITY: + case MID_GRADIENT_ENDINTENSITY: + case MID_GRADIENT_STEPCOUNT: + case MID_GRADIENT_XOFFSET: + case MID_GRADIENT_YOFFSET: + { + sal_Int16 nVal = sal_Int16(); + if(!(rVal >>= nVal )) + return false; + + basegfx::BGradient aBGradient = GetGradientValue(); + + switch ( nMemberId ) + { + case MID_GRADIENT_STYLE: + aBGradient.SetGradientStyle( static_cast<css::awt::GradientStyle>(nVal) ); break; + case MID_GRADIENT_ANGLE: + aBGradient.SetAngle( Degree10(nVal) ); break; + case MID_GRADIENT_BORDER: + aBGradient.SetBorder( nVal ); break; + case MID_GRADIENT_STARTINTENSITY: + aBGradient.SetStartIntens( nVal ); break; + case MID_GRADIENT_ENDINTENSITY: + aBGradient.SetEndIntens( nVal ); break; + case MID_GRADIENT_STEPCOUNT: + aBGradient.SetSteps( nVal ); break; + case MID_GRADIENT_XOFFSET: + aBGradient.SetXOffset( nVal ); break; + case MID_GRADIENT_YOFFSET: + aBGradient.SetYOffset( nVal ); break; + } + + SetGradientValue( aBGradient ); + break; + } + } + + return true; +} + +bool XFillGradientItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 ) +{ + return static_cast<const XFillGradientItem*>(p1)->GetGradientValue() == static_cast<const XFillGradientItem*>(p2)->GetGradientValue(); +} + +std::unique_ptr<XFillGradientItem> XFillGradientItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + const OUString aUniqueName = NameOrIndex::CheckNamedItem( + this, Which(), &pModel->GetItemPool(), + XFillGradientItem::CompareValueFunc, RID_SVXSTR_GRADIENT, + pModel->GetPropertyList( XPropertyListType::Gradient ) ); + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() ) + return std::make_unique<XFillGradientItem>( aUniqueName, aGradient, TypedWhichId<XFillGradientItem>(Which()) ); + } + + return nullptr; +} + +boost::property_tree::ptree XFillGradientItem::dumpAsJSON() const +{ + boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON(); + + if (Which() == XATTR_FILLGRADIENT) + aTree.put("commandName", ".uno:FillGradient"); + + aTree.push_back(std::make_pair("state", GetGradientValue().dumpAsJSON())); + + return aTree; +} + + +SfxPoolItem* XFillFloatTransparenceItem::CreateDefault() { return new XFillFloatTransparenceItem; } + +XFillFloatTransparenceItem::XFillFloatTransparenceItem() : + bEnabled( false ) +{ + SetWhich( XATTR_FILLFLOATTRANSPARENCE ); +} + +XFillFloatTransparenceItem::XFillFloatTransparenceItem(const OUString& rName, const basegfx::BGradient& rGradient, bool bEnable ) : + XFillGradientItem ( rName, rGradient ), + bEnabled ( bEnable ) +{ + SetWhich( XATTR_FILLFLOATTRANSPARENCE ); +} + +XFillFloatTransparenceItem::XFillFloatTransparenceItem( const XFillFloatTransparenceItem& rItem ) : + XFillGradientItem ( rItem ), + bEnabled ( rItem.bEnabled ) +{ + SetWhich( XATTR_FILLFLOATTRANSPARENCE ); +} + +XFillFloatTransparenceItem::XFillFloatTransparenceItem(const basegfx::BGradient& rTheGradient, bool bEnable ) +: XFillGradientItem ( -1, rTheGradient ), + bEnabled ( bEnable ) +{ + SetWhich( XATTR_FILLFLOATTRANSPARENCE ); +} + +bool XFillFloatTransparenceItem::operator==( const SfxPoolItem& rItem ) const +{ + return ( NameOrIndex::operator==(rItem) ) && + ( GetGradientValue() == static_cast<const XFillGradientItem&>(rItem).GetGradientValue() ) && + ( bEnabled == static_cast<const XFillFloatTransparenceItem&>(rItem).bEnabled ); +} + +XFillFloatTransparenceItem* XFillFloatTransparenceItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillFloatTransparenceItem( *this ); +} + +bool XFillFloatTransparenceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + if (MID_GRADIENT_STARTINTENSITY == nMemberId + || MID_GRADIENT_ENDINTENSITY == nMemberId + || MID_GRADIENT_STEPCOUNT == nMemberId) + { + // tdf#155913 handle attributes not supported by transparency gradient as error + return false; + } + + if (!IsEnabled() && nMemberId == MID_NAME) + { + // make sure that we return empty string in case of query for + // "FillTransparenceGradientName" if the item is disabled + rVal <<= OUString(); + return true; + } + + return XFillGradientItem::QueryValue( rVal, nMemberId ); +} + +bool XFillFloatTransparenceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + if (MID_GRADIENT_STARTINTENSITY == nMemberId + || MID_GRADIENT_ENDINTENSITY == nMemberId + || MID_GRADIENT_STEPCOUNT == nMemberId) + { + // tdf#155913 handle attributes not supported by transparency gradient as error + return false; + } + + return XFillGradientItem::PutValue( rVal, nMemberId ); +} + +bool XFillFloatTransparenceItem::GetPresentation( SfxItemPresentation ePres, + MapUnit eCoreUnit, MapUnit ePresUnit, + OUString& rText, + const IntlWrapper& rIntlWrapper ) const +{ + return XFillGradientItem::GetPresentation( ePres, eCoreUnit, ePresUnit, rText, rIntlWrapper ); +} + +bool XFillFloatTransparenceItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 ) +{ + return static_cast<const XFillFloatTransparenceItem*>(p1)->IsEnabled() == static_cast<const XFillFloatTransparenceItem*>(p2)->IsEnabled() && + static_cast<const XFillFloatTransparenceItem*>(p1)->GetGradientValue() == static_cast<const XFillFloatTransparenceItem*>(p2)->GetGradientValue(); +} + +std::unique_ptr<XFillFloatTransparenceItem> XFillFloatTransparenceItem::checkForUniqueItem( SdrModel* pModel ) const +{ + // #85953# unique name only necessary when enabled + if(IsEnabled()) + { + if( pModel ) + { + const OUString aUniqueName = NameOrIndex::CheckNamedItem( this, + XATTR_FILLFLOATTRANSPARENCE, + &pModel->GetItemPool(), + XFillFloatTransparenceItem::CompareValueFunc, + RID_SVXSTR_TRASNGR0, + XPropertyListRef() ); + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() ) + { + return std::make_unique<XFillFloatTransparenceItem>( aUniqueName, GetGradientValue(), true ); + } + } + } + else + { + // #85953# if disabled, force name to empty string + if( !GetName().isEmpty() ) + { + return std::make_unique<XFillFloatTransparenceItem>(OUString(), GetGradientValue(), false); + } + } + + return nullptr; +} + +boost::property_tree::ptree XFillFloatTransparenceItem::dumpAsJSON() const +{ + boost::property_tree::ptree aTree = XFillGradientItem::dumpAsJSON(); + aTree.put("commandName", ".uno:FillFloatTransparence"); + + if (!bEnabled) + { + boost::property_tree::ptree& rState = aTree.get_child("state"); + // When gradient fill is disabled, the intensity fields contain the + // constant encoded percent-transparency. However we use that here to just + // distinguish between 'None' and 'Solid' types and correct the 'style' + // property appropriately. + if (GetGradientValue().GetStartIntens() == 100) + rState.put("style", "NONE"); + else + rState.put("style", "SOLID"); + } + + return aTree; +} + +XHatch::XHatch(const Color& rCol, css::drawing::HatchStyle eTheStyle, tools::Long nTheDistance, + Degree10 nTheAngle) : + eStyle(eTheStyle), + aColor(rCol), + nDistance(nTheDistance), + nAngle(nTheAngle) +{ +} + +bool XHatch::operator==(const XHatch& rHatch) const +{ + return ( eStyle == rHatch.eStyle && + aColor == rHatch.aColor && + nDistance == rHatch.nDistance && + nAngle == rHatch.nAngle ); +} + + +SfxPoolItem* XFillHatchItem::CreateDefault() { return new XFillHatchItem; } + +XFillHatchItem::XFillHatchItem(const OUString& rName, + const XHatch& rTheHatch) : + NameOrIndex(XATTR_FILLHATCH, rName), + aHatch(rTheHatch) +{ +} + +XFillHatchItem::XFillHatchItem(const XFillHatchItem& rItem) : + NameOrIndex(rItem), + aHatch(rItem.aHatch) +{ +} + +XFillHatchItem::XFillHatchItem(const XHatch& rTheHatch) +: NameOrIndex( XATTR_FILLHATCH, -1 ), + aHatch(rTheHatch) +{ +} + +XFillHatchItem* XFillHatchItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillHatchItem(*this); +} + +bool XFillHatchItem::operator==(const SfxPoolItem& rItem) const +{ + return ( NameOrIndex::operator==(rItem) && + aHatch == static_cast<const XFillHatchItem&>(rItem).aHatch ); +} + +bool XFillHatchItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText = GetName(); + return true; +} + +bool XFillHatchItem::HasMetrics() const +{ + return true; +} + +void XFillHatchItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv) +{ + aHatch.SetDistance( BigInt::Scale( aHatch.GetDistance(), nMul, nDiv ) ); +} + +bool XFillHatchItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case 0: + { + css::drawing::Hatch aUnoHatch; + + aUnoHatch.Style = aHatch.GetHatchStyle(); + aUnoHatch.Color = sal_Int32(aHatch.GetColor()); + aUnoHatch.Distance = aHatch.GetDistance(); + aUnoHatch.Angle = aHatch.GetAngle().get(); + + uno::Sequence< beans::PropertyValue > aPropSeq{ + comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())), + comphelper::makePropertyValue("FillHatch", aUnoHatch) + }; + rVal <<= aPropSeq; + break; + } + + case MID_FILLHATCH: + { + css::drawing::Hatch aUnoHatch; + + aUnoHatch.Style = aHatch.GetHatchStyle(); + aUnoHatch.Color = sal_Int32(aHatch.GetColor()); + aUnoHatch.Distance = aHatch.GetDistance(); + aUnoHatch.Angle = aHatch.GetAngle().get(); + rVal <<= aUnoHatch; + break; + } + + case MID_NAME: + { + rVal <<= SvxUnogetApiNameForItem(Which(), GetName()); + break; + } + + case MID_HATCH_STYLE: + rVal <<= aHatch.GetHatchStyle(); break; + case MID_HATCH_COLOR: + rVal <<= aHatch.GetColor(); break; + case MID_HATCH_DISTANCE: + rVal <<= aHatch.GetDistance(); break; + case MID_HATCH_ANGLE: + rVal <<= aHatch.GetAngle().get(); break; + + default: OSL_FAIL("Wrong MemberId!"); return false; + } + + return true; +} + +bool XFillHatchItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case 0: + { + uno::Sequence< beans::PropertyValue > aPropSeq; + if ( rVal >>= aPropSeq ) + { + css::drawing::Hatch aUnoHatch; + OUString aName; + bool bHatch( false ); + for ( const auto& rProp : std::as_const(aPropSeq) ) + { + if ( rProp.Name == "Name" ) + rProp.Value >>= aName; + else if ( rProp.Name == "FillHatch" ) + { + if ( rProp.Value >>= aUnoHatch ) + bHatch = true; + } + } + + SetName( aName ); + if ( bHatch ) + { + aHatch.SetHatchStyle( aUnoHatch.Style ); + aHatch.SetColor( Color(ColorTransparency, aUnoHatch.Color) ); + aHatch.SetDistance( aUnoHatch.Distance ); + aHatch.SetAngle( Degree10(aUnoHatch.Angle) ); + } + + return true; + } + + return false; + } + + case MID_FILLHATCH: + { + css::drawing::Hatch aUnoHatch; + if(!(rVal >>= aUnoHatch)) + return false; + + aHatch.SetHatchStyle( aUnoHatch.Style ); + aHatch.SetColor( Color(ColorTransparency, aUnoHatch.Color) ); + aHatch.SetDistance( aUnoHatch.Distance ); + aHatch.SetAngle( Degree10(aUnoHatch.Angle) ); + break; + } + + case MID_NAME: + { + OUString aName; + if (!(rVal >>= aName )) + return false; + SetName( aName ); + break; + } + + case MID_HATCH_STYLE: + { + sal_Int16 nVal = sal_Int16(); + if (!(rVal >>= nVal )) + return false; + aHatch.SetHatchStyle( static_cast<css::drawing::HatchStyle>(nVal) ); + break; + } + + case MID_HATCH_COLOR: + case MID_HATCH_DISTANCE: + case MID_HATCH_ANGLE: + { + sal_Int32 nVal = 0; + if (!(rVal >>= nVal )) + return false; + + if ( nMemberId == MID_HATCH_COLOR ) + aHatch.SetColor( Color(ColorTransparency, nVal) ); + else if ( nMemberId == MID_HATCH_DISTANCE ) + aHatch.SetDistance( nVal ); + else + aHatch.SetAngle( Degree10(nVal) ); + break; + } + + default: OSL_FAIL("Wrong MemberId!"); return false; + } + + return true; +} + +bool XFillHatchItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 ) +{ + return static_cast<const XFillHatchItem*>(p1)->GetHatchValue() == static_cast<const XFillHatchItem*>(p2)->GetHatchValue(); +} + +std::unique_ptr<XFillHatchItem> XFillHatchItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + const OUString aUniqueName = NameOrIndex::CheckNamedItem( + this, XATTR_FILLHATCH, &pModel->GetItemPool(), + XFillHatchItem::CompareValueFunc, RID_SVXSTR_HATCH10, + pModel->GetPropertyList( XPropertyListType::Hatch ) ); + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() ) + return std::make_unique<XFillHatchItem>( aUniqueName, aHatch ); + } + + return nullptr; +} + +// --- form text attributes --- + + +SfxPoolItem* XFormTextStyleItem::CreateDefault() { return new XFormTextStyleItem; } + +XFormTextStyleItem::XFormTextStyleItem(XFormTextStyle eTheStyle) : + SfxEnumItem(XATTR_FORMTXTSTYLE, eTheStyle) +{ +} + +XFormTextStyleItem* XFormTextStyleItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextStyleItem( *this ); +} + +sal_uInt16 XFormTextStyleItem::GetValueCount() const +{ + return 5; +} + +bool XFormTextStyleItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + rVal <<= static_cast<sal_Int32>(GetValue()); + return true; +} + +bool XFormTextStyleItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + SetValue(static_cast<XFormTextStyle>(nValue)); + + return true; +} + + +SfxPoolItem* XFormTextAdjustItem::CreateDefault() { return new XFormTextAdjustItem; } + +XFormTextAdjustItem::XFormTextAdjustItem(XFormTextAdjust eTheAdjust) : + SfxEnumItem(XATTR_FORMTXTADJUST, eTheAdjust) +{ +} + +XFormTextAdjustItem* XFormTextAdjustItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextAdjustItem( *this ); +} + +sal_uInt16 XFormTextAdjustItem::GetValueCount() const +{ + return 4; +} + +bool XFormTextAdjustItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + rVal <<= static_cast<sal_Int32>(GetValue()); + return true; +} + +bool XFormTextAdjustItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + SetValue(static_cast<XFormTextAdjust>(nValue)); + + return true; +} + + +SfxPoolItem* XFormTextDistanceItem::CreateDefault() { return new XFormTextDistanceItem; } + +XFormTextDistanceItem::XFormTextDistanceItem(tools::Long nDist) : + SfxMetricItem(XATTR_FORMTXTDISTANCE, nDist) +{ +} + +XFormTextDistanceItem* XFormTextDistanceItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextDistanceItem(*this); +} + +SfxPoolItem* XFormTextStartItem::CreateDefault() { return new XFormTextStartItem; } + +XFormTextStartItem::XFormTextStartItem(tools::Long nStart) : + SfxMetricItem(XATTR_FORMTXTSTART, nStart) +{ +} + +XFormTextStartItem* XFormTextStartItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextStartItem(*this); +} + +SfxPoolItem* XFormTextMirrorItem::CreateDefault() { return new XFormTextMirrorItem; } + +XFormTextMirrorItem::XFormTextMirrorItem(bool bMirror) : + SfxBoolItem(XATTR_FORMTXTMIRROR, bMirror) +{ +} + +XFormTextMirrorItem* XFormTextMirrorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextMirrorItem(*this); +} + +SfxPoolItem* XFormTextOutlineItem::CreateDefault() { return new XFormTextOutlineItem; } + +XFormTextOutlineItem::XFormTextOutlineItem(bool bOutline) : + SfxBoolItem(XATTR_FORMTXTOUTLINE, bOutline) +{ +} + +XFormTextOutlineItem* XFormTextOutlineItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextOutlineItem(*this); +} + +SfxPoolItem* XFormTextShadowItem::CreateDefault() { return new XFormTextShadowItem; } + +XFormTextShadowItem::XFormTextShadowItem(XFormTextShadow eFormTextShadow) : + SfxEnumItem(XATTR_FORMTXTSHADOW, eFormTextShadow) +{ +} + +XFormTextShadowItem* XFormTextShadowItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextShadowItem( *this ); +} + +sal_uInt16 XFormTextShadowItem::GetValueCount() const +{ + return 3; +} + +bool XFormTextShadowItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + rVal <<= static_cast<sal_Int32>(GetValue()); + return true; +} + +bool XFormTextShadowItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + sal_Int32 nValue = 0; + rVal >>= nValue; + SetValue(static_cast<XFormTextShadow>(nValue)); + + return true; +} + + +SfxPoolItem* XFormTextShadowColorItem::CreateDefault() { return new XFormTextShadowColorItem; } + +XFormTextShadowColorItem::XFormTextShadowColorItem(const OUString& rName, + const Color& rTheColor) : + XColorItem(XATTR_FORMTXTSHDWCOLOR, rName, rTheColor) +{ +} + +XFormTextShadowColorItem* XFormTextShadowColorItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextShadowColorItem(*this); +} + +SfxPoolItem* XFormTextShadowXValItem::CreateDefault() { return new XFormTextShadowXValItem; } + +XFormTextShadowXValItem::XFormTextShadowXValItem(tools::Long nVal) : + SfxMetricItem(XATTR_FORMTXTSHDWXVAL, nVal) +{ +} + +XFormTextShadowXValItem* XFormTextShadowXValItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextShadowXValItem(*this); +} + +SfxPoolItem* XFormTextShadowYValItem::CreateDefault() { return new XFormTextShadowYValItem; } + +XFormTextShadowYValItem::XFormTextShadowYValItem(tools::Long nVal) : + SfxMetricItem(XATTR_FORMTXTSHDWYVAL, nVal) +{ +} + +XFormTextShadowYValItem* XFormTextShadowYValItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextShadowYValItem(*this); +} + +SfxPoolItem* XFormTextHideFormItem::CreateDefault() { return new XFormTextHideFormItem; } + +XFormTextHideFormItem::XFormTextHideFormItem(bool bHide) : + SfxBoolItem(XATTR_FORMTXTHIDEFORM, bHide) +{ +} + +XFormTextHideFormItem* XFormTextHideFormItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextHideFormItem(*this); +} + +// --- SetItems --- + + +/// a line attribute set item +XLineAttrSetItem::XLineAttrSetItem( SfxItemSet&& pItemSet ) : + SfxSetItem( XATTRSET_LINE, std::move(pItemSet)) +{ +} + +XLineAttrSetItem::XLineAttrSetItem( SfxItemPool* pItemPool ) : + SfxSetItem( XATTRSET_LINE, + SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>( *pItemPool )) +{ +} + +XLineAttrSetItem::XLineAttrSetItem( const XLineAttrSetItem& rLineAttr ) : + SfxSetItem( rLineAttr ) +{ +} + +XLineAttrSetItem::XLineAttrSetItem( const XLineAttrSetItem& rLineAttr, + SfxItemPool* pItemPool) : + SfxSetItem( rLineAttr, pItemPool ) +{ +} + +XLineAttrSetItem* XLineAttrSetItem::Clone( SfxItemPool* pPool ) const +{ + return new XLineAttrSetItem( *this, pPool ); +} + +/// fill attribute set item +XFillAttrSetItem::XFillAttrSetItem( SfxItemSet&& pItemSet ) : + SfxSetItem( XATTRSET_FILL, std::move(pItemSet)) +{ +} + +XFillAttrSetItem::XFillAttrSetItem( SfxItemPool* pItemPool ) : + SfxSetItem( XATTRSET_FILL, + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>( *pItemPool )) +{ +} + +XFillAttrSetItem::XFillAttrSetItem( const XFillAttrSetItem& rFillAttr ) : + SfxSetItem( rFillAttr ) +{ +} + +XFillAttrSetItem::XFillAttrSetItem( const XFillAttrSetItem& rFillAttr, + SfxItemPool* pItemPool ) : + SfxSetItem( rFillAttr, pItemPool ) +{ +} + +XFillAttrSetItem* XFillAttrSetItem::Clone( SfxItemPool* pPool ) const +{ + return new XFillAttrSetItem( *this, pPool ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xattr2.cxx b/svx/source/xoutdev/xattr2.cxx new file mode 100644 index 0000000000..ad1b3b2959 --- /dev/null +++ b/svx/source/xoutdev/xattr2.cxx @@ -0,0 +1,731 @@ +/* -*- 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/drawing/LineJoint.hpp> +#include <com/sun/star/drawing/LineCap.hpp> +#include <com/sun/star/uno/Any.hxx> + +#include <osl/diagnose.h> +#include <i18nutil/unicode.hxx> +#include <svx/strings.hrc> +#include <svx/svxids.hrc> +#include <svx/xlinjoit.hxx> +#include <svx/xlncapit.hxx> +#include <svx/xlntrit.hxx> +#include <svx/xfltrit.hxx> +#include <xftshtit.hxx> +#include <svx/xgrscit.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbmpit.hxx> +#include <svx/xflbmsxy.hxx> +#include <svx/xflbmsli.hxx> +#include <svx/xflbtoxy.hxx> +#include <svx/xflbstit.hxx> +#include <svx/xflboxy.hxx> +#include <svx/xflbckit.hxx> +#include <svx/xfilluseslidebackgrounditem.hxx> +#include <svx/dialmgr.hxx> +#include <svx/xdef.hxx> +#include <AffineMatrixItem.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +#include <comphelper/lok.hxx> + +#include <libxml/xmlwriter.h> + +XLineTransparenceItem::XLineTransparenceItem(sal_uInt16 nLineTransparence) : + SfxUInt16Item(XATTR_LINETRANSPARENCE, nLineTransparence) +{ +} + +XLineTransparenceItem* XLineTransparenceItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineTransparenceItem(*this); +} + +bool XLineTransparenceItem::GetPresentation +( + SfxItemPresentation ePres, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + + switch ( ePres ) + { + case SfxItemPresentation::Complete: + rText = SvxResId(RID_SVXSTR_TRANSPARENCE) + ": "; + [[fallthrough]]; + case SfxItemPresentation::Nameless: + rText += unicode::formatPercent(GetValue(), + Application::GetSettings().GetUILanguageTag()); + return true; + default: + return false; + } +} + + +SfxPoolItem* XLineJointItem::CreateDefault() { return new XLineJointItem; } + +XLineJointItem::XLineJointItem( css::drawing::LineJoint eLineJoint ) : + SfxEnumItem(XATTR_LINEJOINT, eLineJoint) +{ +} + +XLineJointItem* XLineJointItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineJointItem( *this ); +} + +bool XLineJointItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const +{ + rText.clear(); + + TranslateId pId; + + switch( GetValue() ) + { + case css::drawing::LineJoint::LineJoint_MAKE_FIXED_SIZE: + case css::drawing::LineJoint_NONE: + pId = comphelper::LibreOfficeKit::isActive() ? RID_SVXSTR_INVISIBLE : RID_SVXSTR_NONE; + break; + + case css::drawing::LineJoint_MIDDLE: + pId = RID_SVXSTR_LINEJOINT_MIDDLE; + break; + + + case css::drawing::LineJoint_BEVEL: + pId = RID_SVXSTR_LINEJOINT_BEVEL; + break; + + + case css::drawing::LineJoint_MITER: + pId = RID_SVXSTR_LINEJOINT_MITER; + break; + + + case css::drawing::LineJoint_ROUND: + pId = RID_SVXSTR_LINEJOINT_ROUND; + break; + } + + if (pId) + rText = SvxResId(pId); + + return true; +} + +bool XLineJointItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + const css::drawing::LineJoint eJoint = GetValue(); + rVal <<= eJoint; + return true; +} + +bool XLineJointItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + css::drawing::LineJoint eUnoJoint; + + if(!(rVal >>= eUnoJoint)) + { + // also try an int (for Basic) + sal_Int32 nLJ = 0; + if(!(rVal >>= nLJ)) + return false; + eUnoJoint = static_cast<css::drawing::LineJoint>(nLJ); + } + + SetValue( eUnoJoint ); + + return true; +} + +sal_uInt16 XLineJointItem::GetValueCount() const +{ + // don't forget to update the api interface also + return 5; +} + + +AffineMatrixItem::AffineMatrixItem(const css::geometry::AffineMatrix2D* pMatrix) +: SfxPoolItem(SID_ATTR_TRANSFORM_MATRIX) +{ + if(pMatrix) + { + maMatrix = *pMatrix; + } + else + { + maMatrix.m00 = 1.0; + maMatrix.m01 = 0.0; + maMatrix.m02 = 0.0; + maMatrix.m10 = 0.0; + maMatrix.m11 = 1.0; + maMatrix.m12 = 0.0; + } +} + +AffineMatrixItem::AffineMatrixItem(const AffineMatrixItem& rRef) +: SfxPoolItem(rRef) +{ + maMatrix = rRef.maMatrix; +} + +AffineMatrixItem::~AffineMatrixItem() +{ +} + +bool AffineMatrixItem::operator==(const SfxPoolItem& rRef) const +{ + if(!SfxPoolItem::operator==(rRef)) + { + return false; + } + + const AffineMatrixItem* pRef = static_cast< const AffineMatrixItem* >(&rRef); + + if(!pRef) + { + return false; + } + + return (maMatrix.m00 == pRef->maMatrix.m00 + && maMatrix.m01 == pRef->maMatrix.m01 + && maMatrix.m02 == pRef->maMatrix.m02 + && maMatrix.m10 == pRef->maMatrix.m10 + && maMatrix.m11 == pRef->maMatrix.m11 + && maMatrix.m12 == pRef->maMatrix.m12); +} + +AffineMatrixItem* AffineMatrixItem::Clone( SfxItemPool* /*pPool*/ ) const +{ + return new AffineMatrixItem(*this); +} + +bool AffineMatrixItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const +{ + rVal <<= maMatrix; + return true; +} + +bool AffineMatrixItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) +{ + if (rVal >>= maMatrix) + { + return true; + } + + OSL_ENSURE(false, "AffineMatrixItem::PutValue - Wrong type!"); + return false; +} + + +SfxPoolItem* XLineCapItem::CreateDefault() { return new XLineCapItem; } + +XLineCapItem::XLineCapItem(css::drawing::LineCap eLineCap) +: SfxEnumItem(XATTR_LINECAP, eLineCap) +{ +} + +XLineCapItem* XLineCapItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XLineCapItem( *this ); +} + +bool XLineCapItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const +{ + TranslateId pId; + + switch( GetValue() ) + { + default: /*css::drawing::LineCap_BUTT*/ + pId = RID_SVXSTR_LINECAP_BUTT; + break; + + case css::drawing::LineCap_ROUND: + pId = RID_SVXSTR_LINECAP_ROUND; + break; + + case css::drawing::LineCap_SQUARE: + pId = RID_SVXSTR_LINECAP_SQUARE; + break; + } + + rText = SvxResId(pId); + + return true; +} + +bool XLineCapItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const +{ + const css::drawing::LineCap eCap(GetValue()); + rVal <<= eCap; + return true; +} + +bool XLineCapItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) +{ + css::drawing::LineCap eUnoCap; + + if(!(rVal >>= eUnoCap)) + { + // also try an int (for Basic) + sal_Int32 nLJ(0); + + if(!(rVal >>= nLJ)) + { + return false; + } + + eUnoCap = static_cast<css::drawing::LineCap>(nLJ); + } + + OSL_ENSURE(css::drawing::LineCap_BUTT == eUnoCap + || css::drawing::LineCap_ROUND == eUnoCap + || css::drawing::LineCap_SQUARE == eUnoCap, "Unknown enum value in XATTR_LINECAP (!)"); + + SetValue(eUnoCap); + + return true; +} + +sal_uInt16 XLineCapItem::GetValueCount() const +{ + // don't forget to update the api interface also + return 3; +} + +css::drawing::LineCap XLineCapItem::GetValue() const +{ + const css::drawing::LineCap eRetval(SfxEnumItem::GetValue()); + OSL_ENSURE(css::drawing::LineCap_BUTT == eRetval + || css::drawing::LineCap_ROUND == eRetval + || css::drawing::LineCap_SQUARE == eRetval, "Unknown enum value in XATTR_LINECAP (!)"); + + return eRetval; +} + +XFillTransparenceItem::XFillTransparenceItem(sal_uInt16 nFillTransparence) : + SfxUInt16Item(XATTR_FILLTRANSPARENCE, nFillTransparence) +{ +} + +XFillTransparenceItem* XFillTransparenceItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillTransparenceItem(*this); +} + +bool XFillTransparenceItem::GetPresentation +( + SfxItemPresentation ePres, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + + switch ( ePres ) + { + case SfxItemPresentation::Complete: + rText = SvxResId(RID_SVXSTR_TRANSPARENCE) + ": "; + [[fallthrough]]; + case SfxItemPresentation::Nameless: + rText += unicode::formatPercent(GetValue(), + Application::GetSettings().GetUILanguageTag()); + return true; + default: + return false; + } +} + +void XFillTransparenceItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillTransparenceItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + + +XFormTextShadowTranspItem::XFormTextShadowTranspItem(sal_uInt16 nShdwTransparence) : + SfxUInt16Item(XATTR_FORMTXTSHDWTRANSP, nShdwTransparence) +{ +} + +XFormTextShadowTranspItem* XFormTextShadowTranspItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFormTextShadowTranspItem(*this); +} + + +XGradientStepCountItem::XGradientStepCountItem( sal_uInt16 nStepCount ) : + SfxUInt16Item( XATTR_GRADIENTSTEPCOUNT, nStepCount ) +{ +} + +XGradientStepCountItem* XGradientStepCountItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XGradientStepCountItem( *this ); +} + +bool XGradientStepCountItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + + rText += OUString::number(GetValue()); + return true; +} + + +XFillBmpTileItem::XFillBmpTileItem( bool bTile ) : + SfxBoolItem( XATTR_FILLBMP_TILE, bTile ) +{ +} + +XFillBmpTileItem* XFillBmpTileItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpTileItem( *this ); +} + +bool XFillBmpTileItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +void XFillBmpTileItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpTileItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + + + +XFillBmpPosItem::XFillBmpPosItem( RectPoint eRP ) : + SfxEnumItem( XATTR_FILLBMP_POS, eRP ) +{ +} + +XFillBmpPosItem* XFillBmpPosItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpPosItem( *this ); +} + +bool XFillBmpPosItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +sal_uInt16 XFillBmpPosItem::GetValueCount() const +{ + return 9; +} + +void XFillBmpPosItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpPosItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(static_cast<int>(GetValue())).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + + +XFillBmpSizeXItem::XFillBmpSizeXItem( tools::Long nSizeX ) : + SfxMetricItem( XATTR_FILLBMP_SIZEX, nSizeX ) +{ +} + +XFillBmpSizeXItem* XFillBmpSizeXItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpSizeXItem( *this ); +} + +bool XFillBmpSizeXItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +bool XFillBmpSizeXItem::HasMetrics() const +{ + return GetValue() > 0; +} + + + +XFillBmpSizeYItem::XFillBmpSizeYItem( tools::Long nSizeY ) : + SfxMetricItem( XATTR_FILLBMP_SIZEY, nSizeY ) +{ +} + +XFillBmpSizeYItem* XFillBmpSizeYItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpSizeYItem( *this ); +} + +bool XFillBmpSizeYItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +bool XFillBmpSizeYItem::HasMetrics() const +{ + return GetValue() > 0; +} + + +XFillBmpSizeLogItem::XFillBmpSizeLogItem( bool bLog ) : + SfxBoolItem( XATTR_FILLBMP_SIZELOG, bLog ) +{ +} + +XFillBmpSizeLogItem* XFillBmpSizeLogItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpSizeLogItem( *this ); +} + +bool XFillBmpSizeLogItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + + + +XFillBmpTileOffsetXItem::XFillBmpTileOffsetXItem( sal_uInt16 nOffX ) : + SfxUInt16Item( XATTR_FILLBMP_TILEOFFSETX, nOffX ) +{ +} + +XFillBmpTileOffsetXItem* XFillBmpTileOffsetXItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpTileOffsetXItem( *this ); +} + +bool XFillBmpTileOffsetXItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + + +XFillBmpTileOffsetYItem::XFillBmpTileOffsetYItem( sal_uInt16 nOffY ) : + SfxUInt16Item( XATTR_FILLBMP_TILEOFFSETY, nOffY ) +{ +} + +XFillBmpTileOffsetYItem* XFillBmpTileOffsetYItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpTileOffsetYItem( *this ); +} + +bool XFillBmpTileOffsetYItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +XFillBmpStretchItem::XFillBmpStretchItem( bool bStretch ) : + SfxBoolItem( XATTR_FILLBMP_STRETCH, bStretch ) +{ +} + +XFillBmpStretchItem* XFillBmpStretchItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpStretchItem( *this ); +} + +bool XFillBmpStretchItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +void XFillBmpStretchItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpStretchItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + + +XFillBmpPosOffsetXItem::XFillBmpPosOffsetXItem( sal_uInt16 nOffPosX ) : + SfxUInt16Item( XATTR_FILLBMP_POSOFFSETX, nOffPosX ) +{ +} + +XFillBmpPosOffsetXItem* XFillBmpPosOffsetXItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpPosOffsetXItem( *this ); +} + +bool XFillBmpPosOffsetXItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + + +XFillBmpPosOffsetYItem::XFillBmpPosOffsetYItem( sal_uInt16 nOffPosY ) : + SfxUInt16Item( XATTR_FILLBMP_POSOFFSETY, nOffPosY ) +{ +} + +XFillBmpPosOffsetYItem* XFillBmpPosOffsetYItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBmpPosOffsetYItem( *this ); +} + +bool XFillBmpPosOffsetYItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, const IntlWrapper& +) const +{ + rText.clear(); + return true; +} + +XFillBackgroundItem::XFillBackgroundItem( bool bFill ) : + SfxBoolItem( XATTR_FILLBACKGROUND, bFill ) +{ +} + +XFillBackgroundItem* XFillBackgroundItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillBackgroundItem( *this ); +} + +bool XFillBackgroundItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const +{ + rText.clear(); + return true; +} + +void XFillBackgroundItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBackgroundItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + +XFillUseSlideBackgroundItem::XFillUseSlideBackgroundItem( bool bFill ) : + SfxBoolItem( XATTR_FILLUSESLIDEBACKGROUND, bFill ) +{ +} + +XFillUseSlideBackgroundItem* XFillUseSlideBackgroundItem::Clone( SfxItemPool* /*pPool*/) const +{ + return new XFillUseSlideBackgroundItem( *this ); +} + +bool XFillUseSlideBackgroundItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const +{ + rText.clear(); + return true; +} + +void XFillUseSlideBackgroundItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillUseSlideBackgroundItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xattrbmp.cxx b/svx/source/xoutdev/xattrbmp.cxx new file mode 100644 index 0000000000..2401bb361a --- /dev/null +++ b/svx/source/xoutdev/xattrbmp.cxx @@ -0,0 +1,342 @@ +/* -*- 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/graphic/XGraphic.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <tools/debug.hxx> +#include <vcl/virdev.hxx> +#include <vcl/bitmapex.hxx> +#include <svl/style.hxx> +#include <editeng/memberids.h> +#include <svx/strings.hrc> +#include <svx/xtable.hxx> +#include <svx/xdef.hxx> +#include <svx/unomid.hxx> +#include <svx/unoapi.hxx> +#include <svx/svdmodel.hxx> +#include <svx/xbitmap.hxx> +#include <svx/xbtmpit.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/BitmapTools.hxx> +#include <vcl/GraphicLoader.hxx> + +#include <libxml/xmlwriter.h> + +using namespace ::com::sun::star; + +XOBitmap::XOBitmap( const BitmapEx& rBmp ) : + xGraphicObject (new GraphicObject(rBmp)), + bGraphicDirty ( false ) +{ +} + +XOBitmap::~XOBitmap() +{ +} + +BitmapEx XOBitmap::GetBitmap() const +{ + return GetGraphicObject().GetGraphic().GetBitmapEx(); +} + +const GraphicObject& XOBitmap::GetGraphicObject() const +{ + if( bGraphicDirty ) + const_cast<XOBitmap*>(this)->Array2Bitmap(); + + return *xGraphicObject; +} + +void XOBitmap::Bitmap2Array() +{ + ScopedVclPtrInstance< VirtualDevice > pVDev; + bool bPixelColor = false; + const BitmapEx aBitmap( GetBitmap() ); + const sal_Int32 nLines = 8; // type dependent + + if( !pPixelArray ) + pPixelArray.reset( new sal_uInt16[ nLines * nLines ] ); + + pVDev->SetOutputSizePixel( aBitmap.GetSizePixel() ); + pVDev->DrawBitmapEx( Point(), aBitmap ); + aPixelColor = aBckgrColor = pVDev->GetPixel( Point() ); + + // create array and determine foreground and background color + for (sal_Int32 i = 0; i < nLines; ++i) + { + for (sal_Int32 j = 0; j < nLines; ++j) + { + if ( pVDev->GetPixel( Point( j, i ) ) == aBckgrColor ) + pPixelArray[ j + i * nLines ] = 0; + else + { + pPixelArray[ j + i * nLines ] = 1; + if( !bPixelColor ) + { + aPixelColor = pVDev->GetPixel( Point( j, i ) ); + bPixelColor = true; + } + } + } + } +} + +/// convert array, fore- and background color into a bitmap +void XOBitmap::Array2Bitmap() +{ + if (!pPixelArray) + return; + + ScopedVclPtrInstance< VirtualDevice > pVDev; + const sal_Int32 nLines = 8; // type dependent + + pVDev->SetOutputSizePixel( Size( nLines, nLines ) ); + + // create bitmap + for (sal_Int32 i = 0; i < nLines; ++i) + { + for (sal_Int32 j = 0; j < nLines; ++j) + { + if( pPixelArray[ j + i * nLines ] == 0 ) + pVDev->DrawPixel( Point( j, i ), aBckgrColor ); + else + pVDev->DrawPixel( Point( j, i ), aPixelColor ); + } + } + + xGraphicObject.reset(new GraphicObject(pVDev->GetBitmapEx(Point(), Size(nLines, nLines)))); + bGraphicDirty = false; +} + + +SfxPoolItem* XFillBitmapItem::CreateDefault() { return new XFillBitmapItem; } + +XFillBitmapItem::XFillBitmapItem(const OUString& rName, const GraphicObject& rGraphicObject) +: NameOrIndex(XATTR_FILLBITMAP, rName), + maGraphicObject(rGraphicObject) +{ +} + +XFillBitmapItem::XFillBitmapItem(const XFillBitmapItem& rItem) +: NameOrIndex(rItem), + maGraphicObject(rItem.maGraphicObject) +{ +} + +XFillBitmapItem::XFillBitmapItem(const GraphicObject& rGraphicObject) + : NameOrIndex(XATTR_FILLBITMAP, -1) + , maGraphicObject(rGraphicObject) +{ +} + +XFillBitmapItem* XFillBitmapItem::Clone(SfxItemPool* /*pPool*/) const +{ + return new XFillBitmapItem(*this); +} + +bool XFillBitmapItem::operator==(const SfxPoolItem& rItem) const +{ + return (NameOrIndex::operator==(rItem) + && maGraphicObject == static_cast<const XFillBitmapItem&>(rItem).maGraphicObject); +} + + +bool XFillBitmapItem::isPattern() const +{ + Color aBack, aFront; + return vcl::bitmap::isHistorical8x8(GetGraphicObject().GetGraphic().GetBitmapEx(), aBack, aFront); +} + +bool XFillBitmapItem::GetPresentation( + SfxItemPresentation /*ePres*/, + MapUnit /*eCoreUnit*/, + MapUnit /*ePresUnit*/, + OUString& rText, + const IntlWrapper&) const +{ + rText += GetName(); + return true; +} + +bool XFillBitmapItem::QueryValue(css::uno::Any& rVal, sal_uInt8 nMemberId) const +{ + nMemberId &= ~CONVERT_TWIPS; + + // needed for MID_NAME + OUString aApiName; + // needed for complete item (MID 0) + OUString aInternalName; + + css::uno::Reference< css::awt::XBitmap > xBmp; + + if( nMemberId == MID_NAME ) + { + aApiName = SvxUnogetApiNameForItem(Which(), GetName()); + } + else if( nMemberId == 0 ) + { + aInternalName = GetName(); + } + + if (nMemberId == MID_BITMAP || + nMemberId == 0) + { + xBmp.set(GetGraphicObject().GetGraphic().GetXGraphic(), uno::UNO_QUERY); + } + + if( nMemberId == MID_NAME ) + rVal <<= aApiName; + else if( nMemberId == MID_BITMAP ) + rVal <<= xBmp; + else + { + // member-id 0 => complete item (e.g. for toolbars) + DBG_ASSERT( nMemberId == 0, "invalid member-id" ); + uno::Sequence< beans::PropertyValue > aPropSeq{ + comphelper::makePropertyValue("Name", aInternalName), + comphelper::makePropertyValue("Bitmap", xBmp) + }; + + rVal <<= aPropSeq; + } + + return true; +} + +bool XFillBitmapItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) +{ + nMemberId &= ~CONVERT_TWIPS; + + OUString aName; + OUString aURL; + css::uno::Reference< css::awt::XBitmap > xBmp; + css::uno::Reference< css::graphic::XGraphic > xGraphic; + + bool bSetURL = false; + bool bSetName = false; + bool bSetBitmap = false; + + if( nMemberId == MID_NAME ) + bSetName = (rVal >>= aName); + else if( nMemberId == MID_BITMAP ) + { + if (rVal.has<OUString>()) + { + bSetURL = true; + aURL = rVal.get<OUString>(); + } + else if (rVal.has<uno::Reference<awt::XBitmap>>()) + { + bSetBitmap = true; + xBmp = rVal.get<uno::Reference<awt::XBitmap>>(); + } + else if (rVal.has<uno::Reference<graphic::XGraphic>>()) + { + bSetBitmap = true; + xGraphic = rVal.get<uno::Reference<graphic::XGraphic>>(); + } + } + else + { + DBG_ASSERT( nMemberId == 0, "invalid member-id" ); + uno::Sequence< beans::PropertyValue > aPropSeq; + if( rVal >>= aPropSeq ) + { + for ( const auto& rProp : std::as_const(aPropSeq) ) + { + if ( rProp.Name == "Name" ) + bSetName = (rProp.Value >>= aName); + else if ( rProp.Name == "Bitmap" ) + bSetBitmap = (rProp.Value >>= xBmp); + else if ( rProp.Name == "FillBitmapURL" ) + bSetURL = (rProp.Value >>= aURL); + } + } + } + + if( bSetName ) + { + SetName( aName ); + } + if (bSetURL && !aURL.isEmpty()) + { + Graphic aGraphic = vcl::graphic::loadFromURL(aURL); + if (!aGraphic.IsNone()) + { + maGraphicObject.SetGraphic(aGraphic.GetXGraphic()); + } + } + else if( bSetBitmap ) + { + if (xBmp.is()) + { + xGraphic.set(xBmp, uno::UNO_QUERY); + } + if (xGraphic.is()) + { + maGraphicObject.SetGraphic(xGraphic); + } + } + + return (bSetURL || bSetName || bSetBitmap); +} + +bool XFillBitmapItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 ) +{ + const GraphicObject& aGraphicObjectA(static_cast<const XFillBitmapItem*>(p1)->GetGraphicObject()); + const GraphicObject& aGraphicObjectB(static_cast<const XFillBitmapItem*>(p2)->GetGraphicObject()); + + return aGraphicObjectA == aGraphicObjectB; +} + +std::unique_ptr<XFillBitmapItem> XFillBitmapItem::checkForUniqueItem( SdrModel* pModel ) const +{ + if( pModel ) + { + XPropertyListType aListType = XPropertyListType::Bitmap; + if(isPattern()) + aListType = XPropertyListType::Pattern; + const OUString aUniqueName = NameOrIndex::CheckNamedItem( + this, XATTR_FILLBITMAP, &pModel->GetItemPool(), + XFillBitmapItem::CompareValueFunc, RID_SVXSTR_BMP21, + pModel->GetPropertyList( aListType ) ); + + // if the given name is not valid, replace it! + if( aUniqueName != GetName() ) + { + return std::make_unique<XFillBitmapItem>(aUniqueName, maGraphicObject); + } + } + + return nullptr; +} + +void XFillBitmapItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBitmapItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); + + NameOrIndex::dumpAsXml(pWriter); + + (void)xmlTextWriterEndElement(pWriter); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xpool.cxx b/svx/source/xoutdev/xpool.cxx new file mode 100644 index 0000000000..017401983c --- /dev/null +++ b/svx/source/xoutdev/xpool.cxx @@ -0,0 +1,242 @@ +/* -*- 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 <svx/xflbckit.hxx> +#include <xftshtit.hxx> +#include <svx/xflboxy.hxx> +#include <svx/xflbstit.hxx> +#include <svx/xflclit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xflftrit.hxx> +#include <svx/xsflclit.hxx> +#include <svx/xlntrit.hxx> +#include <svx/xfltrit.hxx> +#include <svx/xgrscit.hxx> +#include <svx/xflasit.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbmpit.hxx> +#include <svx/xflbmsxy.hxx> +#include <svx/xflbmsli.hxx> +#include <svx/xflbtoxy.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlinjoit.hxx> +#include <svx/xlncapit.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xfilluseslidebackgrounditem.hxx> +#include <svx/xtextit0.hxx> +#include <svx/xlnasit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnwtit.hxx> +#include <svx/xlnclit.hxx> +#include <svx/xlnstit.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xlnstwit.hxx> +#include <svx/xlnedwit.hxx> +#include <svx/xlnstcit.hxx> +#include <svx/xlnedcit.hxx> +#include <svx/xpool.hxx> +#include <svx/svddef.hxx> +#include <svx/svxids.hrc> +#include <svl/itemset.hxx> +#include <svx/xftadit.hxx> +#include <svx/xftdiit.hxx> +#include <svx/xftstit.hxx> +#include <svx/xftmrit.hxx> +#include <svx/xftouit.hxx> +#include <svx/xftshit.hxx> +#include <svx/xftshcit.hxx> +#include <svx/xftshxy.hxx> + +XOutdevItemPool::XOutdevItemPool(SfxItemPool* _pMaster) + : SfxItemPool("XOutdevItemPool", SDRATTR_START, SDRATTR_END, nullptr, nullptr) + , mpLocalPoolDefaults(new std::vector<SfxPoolItem*>(SDRATTR_END - SDRATTR_START + 1)) + , mpLocalItemInfos(new SfxItemInfo[SDRATTR_END - SDRATTR_START + 1]) +{ + // prepare some defaults + const OUString aNullStr; + const basegfx::B2DPolyPolygon aNullPol; + const Color aNullLineCol(COL_DEFAULT_SHAPE_STROKE); // #i121448# Use defined default color + const Color aNullFillCol(COL_DEFAULT_SHAPE_FILLING); // #i121448# Use defined default color + const Color aNullShadowCol(COL_LIGHTGRAY); + const XDash aNullDash; + const XHatch aNullHatch(aNullLineCol); + + // get master pointer, evtl. add myself to the end of the pools + if(!_pMaster) + { + _pMaster = this; + } + else + { + _pMaster->GetLastPoolInChain()->SetSecondaryPool(this); + } + + // prepare PoolDefaults + std::vector<SfxPoolItem*>& rPoolDefaults = *mpLocalPoolDefaults; + rPoolDefaults[XATTR_LINESTYLE -XATTR_START] = new XLineStyleItem; + rPoolDefaults[XATTR_LINEDASH -XATTR_START] = new XLineDashItem(aNullDash); + rPoolDefaults[XATTR_LINEWIDTH -XATTR_START] = new XLineWidthItem; + rPoolDefaults[XATTR_LINECOLOR -XATTR_START] = new XLineColorItem(aNullStr,aNullLineCol); + rPoolDefaults[XATTR_LINESTART -XATTR_START] = new XLineStartItem(aNullPol); + rPoolDefaults[XATTR_LINEEND -XATTR_START] = new XLineEndItem (aNullPol); + rPoolDefaults[XATTR_LINESTARTWIDTH -XATTR_START] = new XLineStartWidthItem; + rPoolDefaults[XATTR_LINEENDWIDTH -XATTR_START] = new XLineEndWidthItem; + rPoolDefaults[XATTR_LINESTARTCENTER -XATTR_START] = new XLineStartCenterItem; + rPoolDefaults[XATTR_LINEENDCENTER -XATTR_START] = new XLineEndCenterItem; + rPoolDefaults[XATTR_LINETRANSPARENCE -XATTR_START] = new XLineTransparenceItem; + rPoolDefaults[XATTR_LINEJOINT -XATTR_START] = new XLineJointItem; + rPoolDefaults[XATTR_LINECAP -XATTR_START] = new XLineCapItem; + rPoolDefaults[XATTR_FILLSTYLE -XATTR_START] = new XFillStyleItem; + rPoolDefaults[XATTR_FILLCOLOR -XATTR_START] = new XFillColorItem (aNullStr,aNullFillCol); + + // basegfx::BGradient() default already creates [COL_BLACK, COL_WHITE] as defaults + rPoolDefaults[XATTR_FILLGRADIENT -XATTR_START] = new XFillGradientItem(basegfx::BGradient()); + + rPoolDefaults[XATTR_FILLHATCH -XATTR_START] = new XFillHatchItem (aNullHatch); + rPoolDefaults[XATTR_FILLBITMAP -XATTR_START] = new XFillBitmapItem (Graphic()); + rPoolDefaults[XATTR_FILLTRANSPARENCE -XATTR_START] = new XFillTransparenceItem; + rPoolDefaults[XATTR_GRADIENTSTEPCOUNT -XATTR_START] = new XGradientStepCountItem; + rPoolDefaults[XATTR_FILLBMP_TILE -XATTR_START] = new XFillBmpTileItem; + rPoolDefaults[XATTR_FILLBMP_POS -XATTR_START] = new XFillBmpPosItem; + rPoolDefaults[XATTR_FILLBMP_SIZEX -XATTR_START] = new XFillBmpSizeXItem; + rPoolDefaults[XATTR_FILLBMP_SIZEY -XATTR_START] = new XFillBmpSizeYItem; + rPoolDefaults[XATTR_FILLBMP_SIZELOG -XATTR_START] = new XFillBmpSizeLogItem; + rPoolDefaults[XATTR_FILLBMP_TILEOFFSETX -XATTR_START] = new XFillBmpTileOffsetXItem; + rPoolDefaults[XATTR_FILLBMP_TILEOFFSETY -XATTR_START] = new XFillBmpTileOffsetYItem; + rPoolDefaults[XATTR_FILLBMP_STRETCH -XATTR_START] = new XFillBmpStretchItem; + rPoolDefaults[XATTR_FILLBMP_POSOFFSETX -XATTR_START] = new XFillBmpPosOffsetXItem; + rPoolDefaults[XATTR_FILLBMP_POSOFFSETY -XATTR_START] = new XFillBmpPosOffsetYItem; + + rPoolDefaults[XATTR_FILLFLOATTRANSPARENCE -XATTR_START] = new XFillFloatTransparenceItem( + basegfx::BGradient( + basegfx::BColorStops( + COL_BLACK.getBColor(), + COL_BLACK.getBColor())), + false); + + rPoolDefaults[XATTR_SECONDARYFILLCOLOR -XATTR_START] = new XSecondaryFillColorItem(aNullStr, aNullFillCol); + rPoolDefaults[XATTR_FILLBACKGROUND -XATTR_START] = new XFillBackgroundItem; + rPoolDefaults[XATTR_FILLUSESLIDEBACKGROUND -XATTR_START] = new XFillUseSlideBackgroundItem; + rPoolDefaults[XATTR_FORMTXTSTYLE -XATTR_START] = new XFormTextStyleItem; + rPoolDefaults[XATTR_FORMTXTADJUST -XATTR_START] = new XFormTextAdjustItem; + rPoolDefaults[XATTR_FORMTXTDISTANCE -XATTR_START] = new XFormTextDistanceItem; + rPoolDefaults[XATTR_FORMTXTSTART -XATTR_START] = new XFormTextStartItem; + rPoolDefaults[XATTR_FORMTXTMIRROR -XATTR_START] = new XFormTextMirrorItem; + rPoolDefaults[XATTR_FORMTXTOUTLINE -XATTR_START] = new XFormTextOutlineItem; + rPoolDefaults[XATTR_FORMTXTSHADOW -XATTR_START] = new XFormTextShadowItem; + rPoolDefaults[XATTR_FORMTXTSHDWCOLOR -XATTR_START] = new XFormTextShadowColorItem(aNullStr,aNullShadowCol); + rPoolDefaults[XATTR_FORMTXTSHDWXVAL -XATTR_START] = new XFormTextShadowXValItem; + rPoolDefaults[XATTR_FORMTXTSHDWYVAL -XATTR_START] = new XFormTextShadowYValItem; + rPoolDefaults[XATTR_FORMTXTHIDEFORM -XATTR_START] = new XFormTextHideFormItem; + rPoolDefaults[XATTR_FORMTXTSHDWTRANSP -XATTR_START] = new XFormTextShadowTranspItem; + + // create SetItems + rPoolDefaults[XATTRSET_LINE - XATTR_START] = new XLineAttrSetItem( + SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>( *_pMaster ) ); + rPoolDefaults[XATTRSET_FILL - XATTR_START] = new XFillAttrSetItem( + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>( *_pMaster ) ); + + // create ItemInfos + for(sal_uInt16 i(GetFirstWhich()); i <= GetLastWhich(); i++) + { + // _nSID, _bNeedsPoolRegistration, _bShareable + mpLocalItemInfos[i - XATTR_START]._nSID = 0; + mpLocalItemInfos[i - XATTR_START]._bNeedsPoolRegistration = false; + mpLocalItemInfos[i - XATTR_START]._bShareable = true; + } + + // these slots need _bNeedsPoolRegistration == true, see + // text @svl/source/items/itempool.cxx + mpLocalItemInfos[XATTR_FILLBITMAP -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_FILLGRADIENT -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_FILLHATCH -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_FILLFLOATTRANSPARENCE - XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_LINEEND -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_LINESTART -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_LINEDASH -XATTR_START]._bNeedsPoolRegistration = true; + mpLocalItemInfos[XATTR_FILLCOLOR -XATTR_START]._bNeedsPoolRegistration = true; + + // set the SlotIDs, this is a mapping used by GetWhich()/GetSlotId() + mpLocalItemInfos[XATTR_LINESTYLE -XATTR_START]._nSID = SID_ATTR_LINE_STYLE; + mpLocalItemInfos[XATTR_LINEDASH -XATTR_START]._nSID = SID_ATTR_LINE_DASH; + mpLocalItemInfos[XATTR_LINEWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_WIDTH; + mpLocalItemInfos[XATTR_LINECOLOR -XATTR_START]._nSID = SID_ATTR_LINE_COLOR; + mpLocalItemInfos[XATTR_LINESTART -XATTR_START]._nSID = SID_ATTR_LINE_START; + mpLocalItemInfos[XATTR_LINEEND -XATTR_START]._nSID = SID_ATTR_LINE_END; + mpLocalItemInfos[XATTR_LINESTARTWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_STARTWIDTH; + mpLocalItemInfos[XATTR_LINEENDWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_ENDWIDTH; + mpLocalItemInfos[XATTR_LINESTARTCENTER -XATTR_START]._nSID = SID_ATTR_LINE_STARTCENTER; + mpLocalItemInfos[XATTR_LINEENDCENTER -XATTR_START]._nSID = SID_ATTR_LINE_ENDCENTER; + mpLocalItemInfos[XATTR_FILLSTYLE -XATTR_START]._nSID = SID_ATTR_FILL_STYLE; + mpLocalItemInfos[XATTR_FILLCOLOR -XATTR_START]._nSID = SID_ATTR_FILL_COLOR; + mpLocalItemInfos[XATTR_FILLGRADIENT -XATTR_START]._nSID = SID_ATTR_FILL_GRADIENT; + mpLocalItemInfos[XATTR_FILLHATCH -XATTR_START]._nSID = SID_ATTR_FILL_HATCH; + mpLocalItemInfos[XATTR_FILLBITMAP -XATTR_START]._nSID = SID_ATTR_FILL_BITMAP; + mpLocalItemInfos[XATTR_FORMTXTSTYLE -XATTR_START]._nSID = SID_FORMTEXT_STYLE; + mpLocalItemInfos[XATTR_FORMTXTADJUST -XATTR_START]._nSID = SID_FORMTEXT_ADJUST; + mpLocalItemInfos[XATTR_FORMTXTDISTANCE -XATTR_START]._nSID = SID_FORMTEXT_DISTANCE; + mpLocalItemInfos[XATTR_FORMTXTSTART -XATTR_START]._nSID = SID_FORMTEXT_START; + mpLocalItemInfos[XATTR_FORMTXTMIRROR -XATTR_START]._nSID = SID_FORMTEXT_MIRROR; + mpLocalItemInfos[XATTR_FORMTXTOUTLINE -XATTR_START]._nSID = SID_FORMTEXT_OUTLINE; + mpLocalItemInfos[XATTR_FORMTXTSHADOW -XATTR_START]._nSID = SID_FORMTEXT_SHADOW; + mpLocalItemInfos[XATTR_FORMTXTSHDWCOLOR -XATTR_START]._nSID = SID_FORMTEXT_SHDWCOLOR; + mpLocalItemInfos[XATTR_FORMTXTSHDWXVAL -XATTR_START]._nSID = SID_FORMTEXT_SHDWXVAL; + mpLocalItemInfos[XATTR_FORMTXTSHDWYVAL -XATTR_START]._nSID = SID_FORMTEXT_SHDWYVAL; + mpLocalItemInfos[XATTR_FORMTXTHIDEFORM -XATTR_START]._nSID = SID_FORMTEXT_HIDEFORM; + + // associate new slots for panels with known items + mpLocalItemInfos[XATTR_FILLUSESLIDEBACKGROUND - XATTR_START]._nSID = SID_ATTR_FILL_USE_SLIDE_BACKGROUND; + mpLocalItemInfos[XATTR_FILLTRANSPARENCE - XATTR_START]._nSID = SID_ATTR_FILL_TRANSPARENCE; + mpLocalItemInfos[XATTR_FILLFLOATTRANSPARENCE - XATTR_START]._nSID = SID_ATTR_FILL_FLOATTRANSPARENCE; + mpLocalItemInfos[XATTR_LINETRANSPARENCE - XATTR_START]._nSID = SID_ATTR_LINE_TRANSPARENCE; + mpLocalItemInfos[XATTR_LINEJOINT - XATTR_START]._nSID = SID_ATTR_LINE_JOINT; + mpLocalItemInfos[XATTR_LINECAP - XATTR_START]._nSID = SID_ATTR_LINE_CAP; + + // if it's my own creation level, set Defaults and ItemInfos + if(XATTR_START == GetFirstWhich() && XATTR_END == GetLastWhich()) + { + SetDefaults(mpLocalPoolDefaults); + SetItemInfos(mpLocalItemInfos.get()); + } +} + +// copy ctor, clones all static defaults +XOutdevItemPool::XOutdevItemPool(const XOutdevItemPool& rPool) +: SfxItemPool(rPool, true), + mpLocalPoolDefaults(nullptr) +{ +} + +rtl::Reference<SfxItemPool> XOutdevItemPool::Clone() const +{ + return new XOutdevItemPool(*this); +} + +XOutdevItemPool::~XOutdevItemPool() +{ + Delete(); + // release and delete static pool default items + ReleaseDefaults(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabbtmp.cxx b/svx/source/xoutdev/xtabbtmp.cxx new file mode 100644 index 0000000000..178ba8ab2d --- /dev/null +++ b/svx/source/xoutdev/xtabbtmp.cxx @@ -0,0 +1,114 @@ +/* -*- 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 <XPropertyTable.hxx> + +#include <osl/diagnose.h> +#include <vcl/virdev.hxx> +#include <svx/xtable.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +using namespace com::sun::star; + +XBitmapEntry* XBitmapList::GetBitmap(tools::Long nIndex) const +{ + return static_cast<XBitmapEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XBitmapList::createInstance() +{ + return SvxUnoXBitmapTable_createInstance( *this ); +} + +bool XBitmapList::Create() +{ + return true; +} + +BitmapEx XBitmapList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const +{ + OSL_ENSURE( nIndex < Count(), "Access out of range" ); + + if(nIndex < Count()) + { + BitmapEx rBitmapEx = GetBitmap( nIndex )->GetGraphicObject().GetGraphic().GetBitmapEx(); + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + pVirtualDevice->SetOutputSizePixel(rSize); + + if(rBitmapEx.IsAlpha()) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + if(rStyleSettings.GetPreviewUsesCheckeredBackground()) + { + const Point aNull(0, 0); + static const sal_uInt32 nLen(8); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + + pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG); + } + else + { + pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor()); + pVirtualDevice->Erase(); + } + } + + if(rBitmapEx.GetSizePixel().Width() >= rSize.Width() && rBitmapEx.GetSizePixel().Height() >= rSize.Height()) + { + rBitmapEx.Scale(rSize); + pVirtualDevice->DrawBitmapEx(Point(0, 0), rBitmapEx); + } + else + { + const Size aBitmapSize(rBitmapEx.GetSizePixel()); + + for(tools::Long y(0); y < rSize.Height(); y += aBitmapSize.Height()) + { + for(tools::Long x(0); x < rSize.Width(); x += aBitmapSize.Width()) + { + pVirtualDevice->DrawBitmapEx( + Point(x, y), + rBitmapEx); + } + } + } + rBitmapEx = pVirtualDevice->GetBitmapEx(Point(0, 0), rSize); + return rBitmapEx; + } + else + return BitmapEx(); +} + +BitmapEx XBitmapList::CreateBitmapForUI( tools::Long nIndex ) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + return CreateBitmap(nIndex, rSize); +} + +BitmapEx XBitmapList::GetBitmapForPreview( tools::Long nIndex, const Size& rSize ) +{ + return CreateBitmap(nIndex, rSize); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabcolr.cxx b/svx/source/xoutdev/xtabcolr.cxx new file mode 100644 index 0000000000..e952d6f8a4 --- /dev/null +++ b/svx/source/xoutdev/xtabcolr.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <XPropertyTable.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/pathoptions.hxx> + +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/xtable.hxx> + +using namespace com::sun::star; + +XColorListRef XColorList::CreateStdColorList() +{ + return XPropertyList::AsColorList( + XPropertyList::CreatePropertyList( + XPropertyListType::Color, !utl::ConfigManager::IsFuzzing() ? + SvtPathOptions().GetPalettePath() : + "", "")); +} + +XColorListRef XColorList::GetStdColorList() +{ + XColorListRef aTable( CreateStdColorList() ); + return aTable; +} + +void XColorList::Replace(tools::Long nIndex, std::unique_ptr<XColorEntry> pEntry) +{ + XPropertyList::Replace(std::move(pEntry), nIndex); +} +XColorEntry* XColorList::GetColor(tools::Long nIndex) const +{ + return static_cast<XColorEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XColorList::createInstance() +{ + return SvxUnoXColorTable_createInstance( *this ); +} + +bool XColorList::Create() +{ + sal_uInt32 a(0); + sal_uInt32 b(0); + + // <!-- Gray palette from white to black --> + const OUString aStrGrey( SvxResId( RID_SVXSTR_COLOR_GREY ) ); + + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xff, 0xff ), SvxResId( RID_SVXSTR_COLOR_WHITE ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xee, 0xee, 0xee ), aStrGrey + " 1" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xdd, 0xdd, 0xdd ), aStrGrey + " 2" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xcc, 0xcc, 0xcc ), aStrGrey + " 3" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xb2, 0xb2, 0xb2 ), aStrGrey + " 4" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x99, 0x99 ), aStrGrey + " 5" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x80, 0x80, 0x80 ), aStrGrey + " 6" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x66, 0x66, 0x66 ), aStrGrey + " 7" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x33, 0x33, 0x33 ), aStrGrey + " 8" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x1c, 0x1c, 0x1c ), aStrGrey + " 9" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x11, 0x11, 0x11 ), aStrGrey + " 10") ); + Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x00, 0x00 ), SvxResId( RID_SVXSTR_COLOR_BLACK ) ) ); + + // <!-- Base colors step 0 to 10 --> + const sal_uInt32 nNumColorsInGroup(12); + const sal_uInt32 nNumGroups(11); + const OUString aStrCol[nNumColorsInGroup] = { + SvxResId(RID_SVXSTR_COLOR_YELLOW), + SvxResId(RID_SVXSTR_COLOR_ORANGE), + SvxResId(RID_SVXSTR_COLOR_RED), + SvxResId(RID_SVXSTR_COLOR_PINK), + SvxResId(RID_SVXSTR_COLOR_MAGENTA), + SvxResId(RID_SVXSTR_COLOR_PURPLE), + SvxResId(RID_SVXSTR_COLOR_BLUE), + SvxResId(RID_SVXSTR_COLOR_SKYBLUE), + SvxResId(RID_SVXSTR_COLOR_CYAN), + SvxResId(RID_SVXSTR_COLOR_TURQUOISE), + SvxResId(RID_SVXSTR_COLOR_GREEN), + SvxResId(RID_SVXSTR_COLOR_YELLOWGREEN) }; + static const sal_uInt32 aStdCol[nNumColorsInGroup * nNumGroups] = { + 0xffff99, 0xff6600, 0xff3333, 0xff00cc, 0xff33ff, 0x9900ff, 0x6666ff, 0x00ccff, 0x66ffff, 0x33ff99, 0x99ff66, 0xccff00, + 0xffff66, 0xffcc00, 0xff9999, 0xff66cc, 0xff99ff, 0xcc66ff, 0x9999ff, 0x9999ff, 0x99ffff, 0x66ff99, 0x99ff99, 0xccff66, + 0xffff00, 0xff9900, 0xff6666, 0xff3399, 0xff66ff, 0x9933ff, 0x3333ff, 0x3399ff, 0x00ffff, 0x00ff66, 0x66ff66, 0x99ff33, + 0xcc9900, 0xff3300, 0xff0000, 0xff0066, 0xff00ff, 0x6600ff, 0x0000ff, 0x0066ff, 0x00cccc, 0x00cc33, 0x00cc00, 0x66ff00, + 0x996600, 0xcc3300, 0xcc0000, 0xcc0066, 0xcc00cc, 0x6600cc, 0x0000cc, 0x0066cc, 0x009999, 0x009933, 0x009900, 0x66cc00, + 0x663300, 0x801900, 0x990000, 0x990066, 0x990099, 0x330099, 0x000099, 0x006699, 0x006666, 0x007826, 0x006600, 0x669900, + 0x333300, 0x461900, 0x330000, 0x330033, 0x660066, 0x000033, 0x000066, 0x000080, 0x003333, 0x00331a, 0x003300, 0x193300, + 0x666633, 0x661900, 0x663333, 0x660033, 0x663366, 0x330066, 0x333366, 0x003366, 0x336666, 0x006633, 0x336633, 0x336600, + 0x999966, 0x996633, 0x996666, 0x993366, 0x996699, 0x663399, 0x666699, 0x336699, 0x669999, 0x339966, 0x669966, 0x669933, + 0xcccc99, 0xcc9966, 0xcc9999, 0xcc6699, 0xcc99cc, 0x9966cc, 0x9999cc, 0x6699cc, 0x99cccc, 0x66cc99, 0x99cc99, 0x99cc66, + 0xffffcc, 0xffcc99, 0xffcccc, 0xff99cc, 0xffccff, 0xcc99ff, 0xccccff, 0x99ccff, 0xccffff, 0x99ffcc, 0xccffcc, 0xccff99 }; + + for(a = 0; a < nNumGroups; a++) + { + OUString aSuffix; + if (a > 0) aSuffix = OUString::number(a); + + const sal_uInt32 nOffset(a * nNumColorsInGroup); + + for(b = 0; b < nNumColorsInGroup; b++) + { + Insert( std::make_unique<XColorEntry>( Color(ColorTransparency, aStdCol[nOffset + b]), aStrCol[b] + aSuffix ) ); + } + } + + // <!-- use some 'nice' colors from original palette --> + Insert( std::make_unique<XColorEntry>( Color( 0xe6, 0xe6, 0xff ), SvxResId( RID_SVXSTR_COLOR_BLUEGREY) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xCF, 0xE7, 0xF5 ), SvxResId( RID_SVXSTR_COLOR_BLUE_CLASSIC ) ) ); + + // <!-- add 'pale' colors from original palette --> + Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x99, 0xff ), SvxResId( RID_SVXSTR_COLOR_VIOLET ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x33, 0x66 ), SvxResId( RID_SVXSTR_COLOR_BORDEAUX ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xff, 0xcc ), SvxResId( RID_SVXSTR_COLOR_PALE_YELLOW ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xcc, 0xff, 0xff ), SvxResId( RID_SVXSTR_COLOR_PALE_GREEN ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x66, 0x00, 0x66 ), SvxResId( RID_SVXSTR_COLOR_DARKVIOLET ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x80, 0x80 ), SvxResId( RID_SVXSTR_COLOR_SALMON ) ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x66, 0xcc ), SvxResId( RID_SVXSTR_COLOR_SEABLUE ) ) ); + + // <!-- add Chart colors from original palette (also 12, coincidence?) --> + const OUString aStrChart( SvxResId( RID_SVXSTR_COLOR_CHART ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x45, 0x86 ), aStrChart + " 1" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x42, 0x0e ), aStrChart + " 2" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xd3, 0x20 ), aStrChart + " 3" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x57, 0x9d, 0x1c ), aStrChart + " 4" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x7e, 0x00, 0x21 ), aStrChart + " 5" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x83, 0xca, 0xff ), aStrChart + " 6" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x31, 0x40, 0x04 ), aStrChart + " 7" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xae, 0xcf, 0x00 ), aStrChart + " 8" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x4b, 0x1f, 0x6f ), aStrChart + " 9" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x95, 0x0e ), aStrChart + " 10" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0xc5, 0x00, 0x0b ), aStrChart + " 11" ) ); + Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x84, 0xd1 ), aStrChart + " 12" ) ); + + return(165 == Count()); +} + +BitmapEx XColorList::CreateBitmapForUI( tools::Long /*nIndex*/ ) +{ + return BitmapEx(); +} + +tools::Long XColorList::GetIndexOfColor( const Color& rColor ) const +{ + for( tools::Long i = 0, n = maList.size(); i < n; ++i ) + { + const Color aColor = static_cast<XColorEntry*>( maList[i].get() )->GetColor(); + + if (aColor == rColor ) + return i; + } + + return -1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabdash.cxx b/svx/source/xoutdev/xtabdash.cxx new file mode 100644 index 0000000000..ad6480c6a5 --- /dev/null +++ b/svx/source/xoutdev/xtabdash.cxx @@ -0,0 +1,225 @@ +/* -*- 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 <XPropertyTable.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +#include <vcl/virdev.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/xtable.hxx> + +#include <comphelper/lok.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/attribute/lineattribute.hxx> +#include <drawinglayer/attribute/strokeattribute.hxx> +#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <memory> + +using namespace com::sun::star; + +XDashList::XDashList(const OUString& rPath, const OUString& rReferer) + : XPropertyList(XPropertyListType::Dash, rPath, rReferer) +{ +} + +XDashList::~XDashList() +{ +} + +void XDashList::Replace(std::unique_ptr<XDashEntry> pEntry, tools::Long nIndex) +{ + XPropertyList::Replace(std::move(pEntry), nIndex); +} + +XDashEntry* XDashList::GetDash(tools::Long nIndex) const +{ + return static_cast<XDashEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XDashList::createInstance() +{ + return SvxUnoXDashTable_createInstance( *this ); +} + +bool XDashList::Create() +{ + const OUString aStr(SvxResId(RID_SVXSTR_LINESTYLE)); + + Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,1, 50,1, 50, 50),aStr + " 1")); + Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,1,500,1,500,500),aStr + " 2")); + Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,2, 50,3,250,120),aStr + " 3")); + + return true; +} + +double XDashList::ImpGetDefaultLineThickness() +{ + return StyleSettings::GetListBoxPreviewDefaultLineWidth() * 1.1; +} + +BitmapEx XDashList::CreateBitmapForXDash(const XDash* pDash, double fLineThickness) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + const sal_uInt32 nFactor(2); + const Size aSize((rSize.Width() * 5 * 2) / 2, rSize.Height() * nFactor); + + // prepare polygon geometry for line + basegfx::B2DPolygon aLine; + + aLine.append(basegfx::B2DPoint(0.0, aSize.Height() / 2.0)); + aLine.append(basegfx::B2DPoint(aSize.Width(), aSize.Height() / 2.0)); + + // prepare LineAttribute + const basegfx::BColor aLineColor(rStyleSettings.GetFieldTextColor().getBColor()); + const double fLineWidth(fLineThickness * nFactor); + const drawinglayer::attribute::LineAttribute aLineAttribute( + aLineColor, + fLineWidth); + + // prepare StrokeAttribute + ::std::vector< double > aDotDashArray; + double fFullDotDashLen(0.0); + + if(pDash && (pDash->GetDots() || pDash->GetDashes())) + { + const basegfx::B2DHomMatrix aScaleMatrix(OutputDevice::LogicToLogic(MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel))); + const basegfx::B2DVector aScaleVector(aScaleMatrix * basegfx::B2DVector(1.0, 0.0)); + const double fScaleValue(aScaleVector.getLength() * (nFactor * (1.4 / 2.0))); + const double fLineWidthInUnits(fLineWidth / fScaleValue); + + fFullDotDashLen = pDash->CreateDotDashArray(aDotDashArray, fLineWidthInUnits); + + if(!aDotDashArray.empty()) + { + for(double & a : aDotDashArray) + { + a *= fScaleValue; + // ~zero length dash is a dot-like dot (with line width size round cap), so show it + if (a < 0.1) + a += 1.0; + } + + fFullDotDashLen *= fScaleValue; + } + } + + drawinglayer::attribute::StrokeAttribute aStrokeAttribute( + std::move(aDotDashArray), + fFullDotDashLen); + + // create LinePrimitive + const drawinglayer::primitive2d::Primitive2DReference aLinePrimitive( + new drawinglayer::primitive2d::PolygonStrokePrimitive2D( + std::move(aLine), + aLineAttribute, + std::move(aStrokeAttribute))); + + // prepare VirtualDevice + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + + pVirtualDevice->SetOutputSizePixel(aSize); + pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode() + ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient + : DrawModeFlags::Default); + + if(rStyleSettings.GetPreviewUsesCheckeredBackground()) + { + const Point aNull(0, 0); + static const sal_uInt32 nLen(8 * nFactor); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + + pVirtualDevice->DrawCheckered(aNull, aSize, nLen, aW, aG); + } + else + { + pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor()); + pVirtualDevice->Erase(); + } + + // create processor and draw primitives + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + *pVirtualDevice, + aNewViewInformation2D)); + + const drawinglayer::primitive2d::Primitive2DContainer aSequence { aLinePrimitive }; + + pProcessor2D->process(aSequence); + pProcessor2D.reset(); + + // get result bitmap and scale + BitmapEx aRetval(pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel())); + + if(1 != nFactor) + { + aRetval.Scale(Size((rSize.Width() * 5) / 2, rSize.Height())); + } + + return aRetval; +} + +BitmapEx XDashList::CreateBitmapForUI( tools::Long nIndex ) +{ + const XDash& rDash = GetDash(nIndex)->GetDash(); + + return CreateBitmapForXDash(&rDash, ImpGetDefaultLineThickness()); +} + +BitmapEx const & XDashList::GetBitmapForUISolidLine() const +{ + if(maBitmapSolidLine.IsEmpty()) + { + const_cast< XDashList* >(this)->maBitmapSolidLine = XDashList::CreateBitmapForXDash(nullptr, ImpGetDefaultLineThickness()); + } + + return maBitmapSolidLine; +} + +OUString const & XDashList::GetStringForUiSolidLine() const +{ + if(maStringSolidLine.isEmpty()) + { + const_cast< XDashList* >(this)->maStringSolidLine = SvxResId(RID_SVXSTR_SOLID); + } + + return maStringSolidLine; +} + +OUString const & XDashList::GetStringForUiNoLine() const +{ + if(maStringNoLine.isEmpty()) + { + // formerly was RID_SVXSTR_INVISIBLE, but to make equal + // everywhere, use RID_SVXSTR_NONE + const_cast< XDashList* >(this)->maStringNoLine = comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE) : + SvxResId(RID_SVXSTR_NONE); + } + + return maStringNoLine; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabgrdt.cxx b/svx/source/xoutdev/xtabgrdt.cxx new file mode 100644 index 0000000000..40d881c19d --- /dev/null +++ b/svx/source/xoutdev/xtabgrdt.cxx @@ -0,0 +1,175 @@ +/* -*- 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 <XPropertyTable.hxx> + +#include <vcl/virdev.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/xtable.hxx> + +#include <rtl/ustrbuf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <osl/diagnose.h> + +#include <drawinglayer/attribute/fillgradientattribute.hxx> +#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/utils/gradienttools.hxx> +#include <memory> + +using namespace com::sun::star; + +XGradientList::XGradientList( const OUString& rPath, const OUString& rReferer ) +: XPropertyList( XPropertyListType::Gradient, rPath, rReferer ) +{ +} + +XGradientList::~XGradientList() +{ +} + +void XGradientList::Replace(std::unique_ptr<XGradientEntry> pEntry, tools::Long nIndex) +{ + XPropertyList::Replace(std::move(pEntry), nIndex); +} + +XGradientEntry* XGradientList::GetGradient(tools::Long nIndex) const +{ + return static_cast<XGradientEntry*>( XPropertyList::Get( nIndex ) ); +} + +uno::Reference< container::XNameContainer > XGradientList::createInstance() +{ + return SvxUnoXGradientTable_createInstance( *this ); +} + +bool XGradientList::Create() +{ + OUStringBuffer aStr(SvxResId(RID_SVXSTR_GRADIENT) + " 1"); + sal_Int32 nLen = aStr.getLength() - 1; + + // XGradient() default already creates [COL_BLACK, COL_WHITE] as defaults + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(),aStr.toString())); + + aStr[nLen] = '2'; + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(basegfx::BColorStops(COL_BLUE.getBColor(), COL_RED.getBColor()), css::awt::GradientStyle_AXIAL , 300_deg10,20,20,10,100,100),aStr.toString())); + aStr[nLen] = '3'; + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(basegfx::BColorStops(COL_RED.getBColor(), COL_YELLOW.getBColor()), css::awt::GradientStyle_RADIAL , 600_deg10,30,30,20,100,100),aStr.toString())); + aStr[nLen] = '4'; + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(basegfx::BColorStops(COL_YELLOW.getBColor(), COL_GREEN.getBColor()), css::awt::GradientStyle_ELLIPTICAL, 900_deg10,40,40,30,100,100),aStr.toString())); + aStr[nLen] = '5'; + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(basegfx::BColorStops(COL_GREEN.getBColor(), COL_MAGENTA.getBColor()), css::awt::GradientStyle_SQUARE , 1200_deg10,50,50,40,100,100),aStr.toString())); + aStr[nLen] = '6'; + Insert(std::make_unique<XGradientEntry>(basegfx::BGradient(basegfx::BColorStops(COL_MAGENTA.getBColor(), COL_YELLOW.getBColor()), css::awt::GradientStyle_RECT , 1900_deg10,60,60,50,100,100),aStr.toString())); + + return true; +} + +BitmapEx XGradientList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const +{ + BitmapEx aRetval; + + OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)"); + + if(nIndex < Count()) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + // prepare polygon geometry for rectangle + basegfx::B2DPolygon aRectangle( + basegfx::utils::createPolygonFromRect( + basegfx::B2DRange(0.0, 0.0, rSize.Width(), rSize.Height()))); + + const basegfx::BGradient& rGradient = GetGradient(nIndex)->GetGradient(); + basegfx::BColorStops aColorStops(rGradient.GetColorStops()); + + if (rGradient.GetStartIntens() != 100 || rGradient.GetEndIntens() != 100) + { + // Need to do the (old, crazy) blend against black + aColorStops.blendToIntensity( + rGradient.GetStartIntens() * 0.01, + rGradient.GetEndIntens() * 0.01, + basegfx::BColor()); // COL_BLACK + } + + drawinglayer::attribute::FillGradientAttribute aFillGradient( + rGradient.GetGradientStyle(), + static_cast<double>(rGradient.GetBorder()) * 0.01, + static_cast<double>(rGradient.GetXOffset()) * 0.01, + static_cast<double>(rGradient.GetYOffset()) * 0.01, + toRadians(rGradient.GetAngle()), + aColorStops); + + const drawinglayer::primitive2d::Primitive2DReference aGradientPrimitive( + new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D( + basegfx::B2DPolyPolygon(aRectangle), + std::move(aFillGradient))); + + const basegfx::BColor aBlack(0.0, 0.0, 0.0); + const drawinglayer::primitive2d::Primitive2DReference aBlackRectanglePrimitive( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + std::move(aRectangle), + aBlack)); + + // prepare VirtualDevice + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + + pVirtualDevice->SetOutputSizePixel(rSize); + pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode() + ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient + : DrawModeFlags::Default); + + // create processor and draw primitives + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + *pVirtualDevice, + aNewViewInformation2D)); + + drawinglayer::primitive2d::Primitive2DContainer aSequence(2); + + aSequence[0] = aGradientPrimitive; + aSequence[1] = aBlackRectanglePrimitive; + + pProcessor2D->process(aSequence); + pProcessor2D.reset(); + + // get result bitmap and scale + aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel()); + } + + return aRetval; +} + +BitmapEx XGradientList::CreateBitmapForUI(tools::Long nIndex) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + return CreateBitmap(nIndex, rSize); +} + +BitmapEx XGradientList::GetBitmapForPreview(tools::Long nIndex, const Size& rSize) +{ + return CreateBitmap(nIndex, rSize); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabhtch.cxx b/svx/source/xoutdev/xtabhtch.cxx new file mode 100644 index 0000000000..1a4219db89 --- /dev/null +++ b/svx/source/xoutdev/xtabhtch.cxx @@ -0,0 +1,194 @@ +/* -*- 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 <XPropertyTable.hxx> +#include <vcl/svapp.hxx> + +#include <vcl/virdev.hxx> +#include <vcl/settings.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> + +#include <drawinglayer/attribute/fillhatchattribute.hxx> +#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> +#include <memory> + +using namespace ::com::sun::star; + +XHatchList::XHatchList(const OUString& rPath, const OUString& rReferer) + : XPropertyList( XPropertyListType::Hatch, rPath, rReferer ) +{ +} + +XHatchList::~XHatchList() +{ +} + +void XHatchList::Replace(std::unique_ptr<XHatchEntry> pEntry, tools::Long nIndex) +{ + XPropertyList::Replace(std::move(pEntry), nIndex); +} + +XHatchEntry* XHatchList::GetHatch(tools::Long nIndex) const +{ + return static_cast<XHatchEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XHatchList::createInstance() +{ + return SvxUnoXHatchTable_createInstance( *this ); +} + +bool XHatchList::Create() +{ + OUStringBuffer aStr(SvxResId(RID_SVXSTR_HATCH) + " 1"); + + sal_Int32 nLen = aStr.getLength() - 1; + Insert(std::make_unique<XHatchEntry>(XHatch(COL_BLACK,css::drawing::HatchStyle_SINGLE,100, 0_deg10),aStr.toString())); + aStr[nLen] = '2'; + Insert(std::make_unique<XHatchEntry>(XHatch(COL_RED ,css::drawing::HatchStyle_DOUBLE, 80,450_deg10),aStr.toString())); + aStr[nLen] = '3'; + Insert(std::make_unique<XHatchEntry>(XHatch(COL_BLUE ,css::drawing::HatchStyle_TRIPLE,120, 0_deg10),aStr.toString())); + + return true; +} + +BitmapEx XHatchList::CreateBitmap( tools::Long nIndex, const Size& rSize) const +{ + BitmapEx aRetval; + OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)"); + + if(nIndex < Count()) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + // prepare polygon geometry for rectangle + basegfx::B2DPolygon aRectangle( + basegfx::utils::createPolygonFromRect( + basegfx::B2DRange(0.0, 0.0, rSize.Width(), rSize.Height()))); + + const XHatch& rHatch = GetHatch(nIndex)->GetHatch(); + drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HatchStyle::Triple); + + switch(rHatch.GetHatchStyle()) + { + case css::drawing::HatchStyle_SINGLE : + { + aHatchStyle = drawinglayer::attribute::HatchStyle::Single; + break; + } + case css::drawing::HatchStyle_DOUBLE : + { + aHatchStyle = drawinglayer::attribute::HatchStyle::Double; + break; + } + default : + { + aHatchStyle = drawinglayer::attribute::HatchStyle::Triple; // css::drawing::HatchStyle_TRIPLE + break; + } + } + + const basegfx::B2DHomMatrix aScaleMatrix(OutputDevice::LogicToLogic(MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel))); + const basegfx::B2DVector aScaleVector(aScaleMatrix * basegfx::B2DVector(1.0, 0.0)); + const double fScaleValue(aScaleVector.getLength()); + + drawinglayer::attribute::FillHatchAttribute aFillHatch( + aHatchStyle, + static_cast<double>(rHatch.GetDistance()) * fScaleValue, + toRadians(rHatch.GetAngle()), + rHatch.GetColor().getBColor(), + 3, // same default as VCL, a minimum of three discrete units (pixels) offset + false); + + const basegfx::BColor aBlack(0.0, 0.0, 0.0); + const drawinglayer::primitive2d::Primitive2DReference aHatchPrimitive( + new drawinglayer::primitive2d::PolyPolygonHatchPrimitive2D( + basegfx::B2DPolyPolygon(aRectangle), + aBlack, + std::move(aFillHatch))); + + const drawinglayer::primitive2d::Primitive2DReference aBlackRectanglePrimitive( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + std::move(aRectangle), + aBlack)); + + // prepare VirtualDevice + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + + pVirtualDevice->SetOutputSizePixel(rSize); + pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode() + ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient + : DrawModeFlags::Default); + + if(rStyleSettings.GetPreviewUsesCheckeredBackground()) + { + const Point aNull(0, 0); + static const sal_uInt32 nLen(8); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG); + } + else + { + pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor()); + pVirtualDevice->Erase(); + } + + // create processor and draw primitives + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + *pVirtualDevice, + aNewViewInformation2D)); + + drawinglayer::primitive2d::Primitive2DContainer aSequence(2); + + aSequence[0] = aHatchPrimitive; + aSequence[1] = aBlackRectanglePrimitive; + pProcessor2D->process(aSequence); + pProcessor2D.reset(); + + // get result bitmap and scale + aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel()); + } + + return aRetval; +} + +BitmapEx XHatchList::CreateBitmapForUI(tools::Long nIndex) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + BitmapEx aRetVal = CreateBitmap(nIndex, rSize); + return aRetVal; +} + +BitmapEx XHatchList::GetBitmapForPreview(tools::Long nIndex, const Size& rSize) +{ + return CreateBitmap(nIndex, rSize); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtable.cxx b/svx/source/xoutdev/xtable.cxx new file mode 100644 index 0000000000..9818fd1939 --- /dev/null +++ b/svx/source/xoutdev/xtable.cxx @@ -0,0 +1,393 @@ +/* -*- 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 <xmlxtexp.hxx> +#include <xmlxtimp.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <tools/urlobj.hxx> +#include <svx/xtable.hxx> +#include <tools/debug.hxx> +#include <stack> + +using namespace com::sun::star; + +XColorEntry::XColorEntry(const Color& rColor, const OUString& rName) +: XPropertyEntry(rName), + aColor(rColor) +{ +} + +XLineEndEntry::XLineEndEntry(basegfx::B2DPolyPolygon _aB2DPolyPolygon, const OUString& rName) +: XPropertyEntry(rName), + aB2DPolyPolygon(std::move(_aB2DPolyPolygon)) +{ +} + +XLineEndEntry::XLineEndEntry(const XLineEndEntry& rOther) +: XPropertyEntry(rOther), + aB2DPolyPolygon(rOther.aB2DPolyPolygon) +{ +} + +XDashEntry::XDashEntry(const XDash& rDash, const OUString& rName) +: XPropertyEntry(rName), + aDash(rDash) +{ +} + +XDashEntry::XDashEntry(const XDashEntry& rOther) +: XPropertyEntry(rOther), +aDash(rOther.aDash) +{ +} + +XHatchEntry::XHatchEntry(const XHatch& rHatch, const OUString& rName) +: XPropertyEntry(rName), + aHatch(rHatch) +{ +} + +XHatchEntry::XHatchEntry(const XHatchEntry& rOther) +: XPropertyEntry(rOther), + aHatch(rOther.aHatch) +{ +} + +XGradientEntry::XGradientEntry(const basegfx::BGradient& rGradient, const OUString& rName) +: XPropertyEntry(rName), + aGradient(rGradient) +{ +} + +XGradientEntry::XGradientEntry(const XGradientEntry& rOther) +: XPropertyEntry(rOther), + aGradient(rOther.aGradient) +{ +} + +XBitmapEntry::XBitmapEntry(const GraphicObject& rGraphicObject, const OUString& rName) +: XPropertyEntry(rName), + maGraphicObject(rGraphicObject) +{ +} + +XBitmapEntry::XBitmapEntry(const XBitmapEntry& rOther) +: XPropertyEntry(rOther), + maGraphicObject(rOther.maGraphicObject) +{ +} + +XPropertyList::XPropertyList( + XPropertyListType type, + OUString aPath, OUString aReferer +) : meType ( type ), + maName ( "standard" ), + maPath (std::move( aPath )), + maReferer (std::move( aReferer )), + mbListDirty ( true ), + mbEmbedInDocument( false ) +{ +// fprintf (stderr, "Create type %d count %d\n", (int)meType, count++); +} + +bool XPropertyList::isValidIdx(tools::Long nIndex) const +{ + return (nIndex >= 0 && o3tl::make_unsigned(nIndex) < maList.size()); +} + + +XPropertyList::~XPropertyList() +{ +} + +tools::Long XPropertyList::Count() const +{ + if( mbListDirty ) + { + if( !const_cast<XPropertyList*>(this)->Load() ) + const_cast<XPropertyList*>(this)->Create(); + } + return maList.size(); +} + +XPropertyEntry* XPropertyList::Get( tools::Long nIndex ) const +{ + if( mbListDirty ) + { + if( !const_cast<XPropertyList*>(this)->Load() ) + const_cast<XPropertyList*>(this)->Create(); + } + if (!isValidIdx(nIndex)) + return nullptr; + + return maList[nIndex].get(); +} + +tools::Long XPropertyList::GetIndex(std::u16string_view rName) const +{ + if( mbListDirty ) + { + if( !const_cast<XPropertyList*>(this)->Load() ) + const_cast<XPropertyList*>(this)->Create(); + } + + for( tools::Long i = 0, n = maList.size(); i < n; ++i ) { + if (rName == maList[ i ]->GetName()) { + return i; + } + } + return -1; +} + +BitmapEx XPropertyList::GetUiBitmap( tools::Long nIndex ) const +{ + BitmapEx aRetval; + if (!isValidIdx(nIndex)) + return aRetval; + + XPropertyEntry* pEntry = maList[nIndex].get(); + aRetval = pEntry->GetUiBitmap(); + + if(aRetval.IsEmpty()) + { + aRetval = const_cast< XPropertyList* >(this)->CreateBitmapForUI(nIndex); + pEntry->SetUiBitmap(aRetval); + } + return aRetval; +} + +void XPropertyList::Insert(std::unique_ptr<XPropertyEntry> pEntry, tools::Long nIndex) +{ + if (!pEntry) + { + assert(!"empty XPropertyEntry not allowed in XPropertyList"); + return; + } + + if (isValidIdx(nIndex)) { + maList.insert( maList.begin()+nIndex, std::move(pEntry) ); + } else { + maList.push_back( std::move(pEntry) ); + } +} + +void XPropertyList::Replace(std::unique_ptr<XPropertyEntry> pEntry, tools::Long nIndex) +{ + if (!pEntry) + { + assert(!"empty XPropertyEntry not allowed in XPropertyList"); + return; + } + if (!isValidIdx(nIndex)) + { + assert(!"trying to replace invalid entry in XPropertyList"); + return; + } + + maList[nIndex] = std::move(pEntry); +} + +void XPropertyList::Remove(tools::Long nIndex) +{ + if (!isValidIdx(nIndex)) + { + assert(!"trying to remove invalid entry in XPropertyList"); + return; + } + + maList.erase(maList.begin() + nIndex); +} + +void XPropertyList::SetName( const OUString& rString ) +{ + if(!rString.isEmpty()) + { + maName = rString; + } +} + +bool XPropertyList::Load() +{ + if( mbListDirty ) + { + mbListDirty = false; + std::stack<OUString> aDirs; + + sal_Int32 nIndex = 0; + do + { + aDirs.push(maPath.getToken(0, ';', nIndex)); + } + while (nIndex >= 0); + + //try all entries palette path list working back to front until one + //succeeds + while (!aDirs.empty()) + { + OUString aPath(aDirs.top()); + aDirs.pop(); + + INetURLObject aURL(aPath); + + if( INetProtocol::NotValid == aURL.GetProtocol() ) + { + DBG_ASSERT( aPath.isEmpty(), "invalid URL" ); + return false; + } + + aURL.Append( maName ); + + if( aURL.getExtension().isEmpty() ) + aURL.setExtension( GetDefaultExt() ); + + bool bRet = SvxXMLXTableImport::load(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), + maReferer, uno::Reference < embed::XStorage >(), + createInstance(), nullptr ); + if (bRet) + return bRet; + } + } + return false; +} + +bool XPropertyList::LoadFrom( const uno::Reference < embed::XStorage > &xStorage, + const OUString &rURL, const OUString &rReferer ) +{ + if( !mbListDirty ) + return false; + mbListDirty = false; + return SvxXMLXTableImport::load( rURL, rReferer, xStorage, createInstance(), &mbEmbedInDocument ); +} + +bool XPropertyList::Save() +{ + //save to the last path in the palette path list + OUString aLastDir; + sal_Int32 nIndex = 0; + do + { + aLastDir = maPath.getToken(0, ';', nIndex); + } + while (nIndex >= 0); + + INetURLObject aURL(aLastDir); + + if( INetProtocol::NotValid == aURL.GetProtocol() ) + { + DBG_ASSERT( aLastDir.isEmpty(), "invalid URL" ); + return false; + } + + aURL.Append( maName ); + + if( aURL.getExtension().isEmpty() ) + aURL.setExtension( GetDefaultExt() ); + + return SvxXMLXTableExportComponent::save( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), + createInstance(), + uno::Reference< embed::XStorage >(), nullptr ); +} + +bool XPropertyList::SaveTo( const uno::Reference< embed::XStorage > &xStorage, + const OUString &rURL, OUString *pOptName ) +{ + return SvxXMLXTableExportComponent::save( rURL, createInstance(), xStorage, pOptName ); +} + +XPropertyListRef XPropertyList::CreatePropertyList( XPropertyListType aType, + const OUString& rPath, + const OUString& rReferer ) +{ + XPropertyListRef pRet; + + switch (aType) { + case XPropertyListType::Color: + pRet = XPropertyListRef(new XColorList(rPath, rReferer)); + break; + case XPropertyListType::LineEnd: + pRet = XPropertyListRef(new XLineEndList(rPath, rReferer)); + break; + case XPropertyListType::Dash: + pRet = XPropertyListRef(new XDashList(rPath, rReferer)); + break; + case XPropertyListType::Hatch: + pRet = XPropertyListRef(new XHatchList(rPath, rReferer)); + break; + case XPropertyListType::Gradient: + pRet = XPropertyListRef(new XGradientList(rPath, rReferer)); + break; + case XPropertyListType::Bitmap: + pRet = XPropertyListRef(new XBitmapList(rPath, rReferer)); + break; + case XPropertyListType::Pattern: + pRet = XPropertyListRef(new XPatternList(rPath, rReferer)); + break; + default: + OSL_FAIL("unknown xproperty type"); + break; + } + OSL_ASSERT( !pRet.is() || pRet->meType == aType ); + + return pRet; +} + +XPropertyListRef +XPropertyList::CreatePropertyListFromURL( XPropertyListType t, + std::u16string_view rURLStr ) +{ + INetURLObject aURL( rURLStr ); + INetURLObject aPathURL( aURL ); + + aPathURL.removeSegment(); + aPathURL.removeFinalSlash(); + + XPropertyListRef pList = XPropertyList::CreatePropertyList( + t, aPathURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), "" ); + pList->SetName( aURL.getName() ); + + return pList; +} + +struct { + XPropertyListType t; + const char *pExt; +} const pExtnMap[] = { + { XPropertyListType::Color, "soc" }, + { XPropertyListType::LineEnd, "soe" }, + { XPropertyListType::Dash, "sod" }, + { XPropertyListType::Hatch, "soh" }, + { XPropertyListType::Gradient, "sog" }, + { XPropertyListType::Bitmap, "sob" }, + { XPropertyListType::Pattern, "sop"} +}; + +OUString XPropertyList::GetDefaultExt( XPropertyListType t ) +{ + for (const auto & i : pExtnMap) + { + if( i.t == t ) + return OUString::createFromAscii( i.pExt ); + } + return OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtablend.cxx b/svx/source/xoutdev/xtablend.cxx new file mode 100644 index 0000000000..fcca059601 --- /dev/null +++ b/svx/source/xoutdev/xtablend.cxx @@ -0,0 +1,163 @@ +/* -*- 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 <XPropertyTable.hxx> +#include <vcl/virdev.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <osl/diagnose.h> + +#include <svx/xtable.hxx> +#include <drawinglayer/attribute/linestartendattribute.hxx> +#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <memory> + +using namespace com::sun::star; + +XLineEndList::XLineEndList( const OUString& rPath, const OUString& rReferer ) + : XPropertyList( XPropertyListType::LineEnd, rPath, rReferer ) +{ +} + +XLineEndList::~XLineEndList() +{ +} + +XLineEndEntry* XLineEndList::GetLineEnd(tools::Long nIndex) const +{ + return static_cast<XLineEndEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XLineEndList::createInstance() +{ + return SvxUnoXLineEndTable_createInstance( *this ); +} + +bool XLineEndList::Create() +{ + basegfx::B2DPolygon aTriangle; + aTriangle.append(basegfx::B2DPoint(10.0, 0.0)); + aTriangle.append(basegfx::B2DPoint(0.0, 30.0)); + aTriangle.append(basegfx::B2DPoint(20.0, 30.0)); + aTriangle.setClosed(true); + Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aTriangle), SvxResId( RID_SVXSTR_ARROW ) ) ); + + basegfx::B2DPolygon aSquare; + aSquare.append(basegfx::B2DPoint(0.0, 0.0)); + aSquare.append(basegfx::B2DPoint(10.0, 0.0)); + aSquare.append(basegfx::B2DPoint(10.0, 10.0)); + aSquare.append(basegfx::B2DPoint(0.0, 10.0)); + aSquare.setClosed(true); + Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aSquare), SvxResId( RID_SVXSTR_SQUARE ) ) ); + + basegfx::B2DPolygon aCircle(basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 100.0)); + Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aCircle), SvxResId( RID_SVXSTR_CIRCLE ) ) ); + + return true; +} + +BitmapEx XLineEndList::CreateBitmapForUI( tools::Long nIndex ) +{ + BitmapEx aRetval; + OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)"); + + if(nIndex < Count()) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + + const Size aSize(rSize.Width() * 2, rSize.Height()); + + // prepare line geometry + basegfx::B2DPolygon aLine; + const double fBorderDistance(aSize.Height() * 0.1); + + aLine.append(basegfx::B2DPoint(fBorderDistance, aSize.Height() / 2)); + aLine.append(basegfx::B2DPoint(aSize.Width() - fBorderDistance, aSize.Height() / 2)); + + // prepare LineAttribute + const basegfx::BColor aLineColor(rStyleSettings.GetFieldTextColor().getBColor()); + const double fLineWidth(StyleSettings::GetListBoxPreviewDefaultLineWidth() * 1.1); + const drawinglayer::attribute::LineAttribute aLineAttribute( + aLineColor, + fLineWidth); + + const basegfx::B2DPolyPolygon aLineEnd(GetLineEnd(nIndex)->GetLineEnd()); + const double fArrowHeight(aSize.Height() - (2.0 * fBorderDistance)); + const drawinglayer::attribute::LineStartEndAttribute aLineStartEndAttribute( + fArrowHeight, + aLineEnd, + false); + + // prepare line primitive + const drawinglayer::primitive2d::Primitive2DReference aLineStartEndPrimitive( + new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D( + aLine, + aLineAttribute, + aLineStartEndAttribute, + aLineStartEndAttribute)); + + // prepare VirtualDevice + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + + pVirtualDevice->SetOutputSizePixel(aSize); + pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode() + ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient + : DrawModeFlags::Default); + + if(rStyleSettings.GetPreviewUsesCheckeredBackground()) + { + const Point aNull(0, 0); + static const sal_uInt32 nLen(8); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + pVirtualDevice->DrawCheckered(aNull, aSize, nLen, aW, aG); + } + else + { + pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor()); + pVirtualDevice->Erase(); + } + + // create processor and draw primitives + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + *pVirtualDevice, + aNewViewInformation2D)); + + const drawinglayer::primitive2d::Primitive2DContainer aSequence { aLineStartEndPrimitive }; + + pProcessor2D->process(aSequence); + pProcessor2D.reset(); + + // get result bitmap and scale + aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel()); + } + + return aRetval; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/xoutdev/xtabptrn.cxx b/svx/source/xoutdev/xtabptrn.cxx new file mode 100644 index 0000000000..29697880f0 --- /dev/null +++ b/svx/source/xoutdev/xtabptrn.cxx @@ -0,0 +1,149 @@ +/* -*- 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 <XPropertyTable.hxx> + +#include <vcl/virdev.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/xtable.hxx> +#include <rtl/ustrbuf.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/BitmapTools.hxx> + +using namespace com::sun::star; + +XBitmapEntry* XPatternList::GetBitmap(tools::Long nIndex) const +{ + return static_cast<XBitmapEntry*>( XPropertyList::Get(nIndex) ); +} + +uno::Reference< container::XNameContainer > XPatternList::createInstance() +{ + return SvxUnoXBitmapTable_createInstance( *this ); +} + +bool XPatternList::Create() +{ + OUStringBuffer aStr(SvxResId(RID_SVXSTR_PATTERN)); + std::array<sal_uInt8,64> aArray; + BitmapEx aBitmap; + const sal_Int32 nLen(aStr.getLength() - 1); + + aArray.fill(0); + + // white/white bitmap + aStr.append(" 1"); + aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_WHITE, COL_WHITE); + Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString())); + + // black/white bitmap + aArray[ 0] = 1; aArray[ 9] = 1; aArray[18] = 1; aArray[27] = 1; + aArray[36] = 1; aArray[45] = 1; aArray[54] = 1; aArray[63] = 1; + aStr[nLen] = '2'; + aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_BLACK, COL_WHITE); + Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString())); + + // lightred/white bitmap + aArray[ 7] = 1; aArray[14] = 1; aArray[21] = 1; aArray[28] = 1; + aArray[35] = 1; aArray[42] = 1; aArray[49] = 1; aArray[56] = 1; + aStr[nLen] = '3'; + aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_LIGHTRED, COL_WHITE); + Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString())); + + // lightblue/white bitmap + aArray[24] = 1; aArray[25] = 1; aArray[26] = 1; + aArray[29] = 1; aArray[30] = 1; aArray[31] = 1; + aStr[nLen] = '4'; + aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_LIGHTBLUE, COL_WHITE); + Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString())); + + return true; +} + +BitmapEx XPatternList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const +{ + assert( nIndex < Count() ); + + if(nIndex < Count()) + { + BitmapEx rBitmapEx = GetBitmap( nIndex )->GetGraphicObject().GetGraphic().GetBitmapEx(); + ScopedVclPtrInstance< VirtualDevice > pVirtualDevice; + pVirtualDevice->SetOutputSizePixel(rSize); + + if(rBitmapEx.IsAlpha()) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + if(rStyleSettings.GetPreviewUsesCheckeredBackground()) + { + const Point aNull(0, 0); + static const sal_uInt32 nLen(8); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + + pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG); + } + else + { + pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor()); + pVirtualDevice->Erase(); + } + } + + if(rBitmapEx.GetSizePixel().Width() >= rSize.Width() && rBitmapEx.GetSizePixel().Height() >= rSize.Height()) + { + rBitmapEx.Scale(rSize); + pVirtualDevice->DrawBitmapEx(Point(0, 0), rBitmapEx); + } + else + { + const Size aBitmapSize(rBitmapEx.GetSizePixel()); + + for(tools::Long y(0); y < rSize.Height(); y += aBitmapSize.Height()) + { + for(tools::Long x(0); x < rSize.Width(); x += aBitmapSize.Width()) + { + pVirtualDevice->DrawBitmapEx( + Point(x, y), + rBitmapEx); + } + } + } + rBitmapEx = pVirtualDevice->GetBitmapEx(Point(0, 0), rSize); + return rBitmapEx; + } + else + return BitmapEx(); +} + +BitmapEx XPatternList::CreateBitmapForUI( tools::Long nIndex ) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize(); + return CreateBitmap(nIndex, rSize); +} + +BitmapEx XPatternList::GetBitmapForPreview( tools::Long nIndex, const Size& rSize ) +{ + return CreateBitmap(nIndex, rSize); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |