diff options
Diffstat (limited to 'svx/source/tbxctrls')
28 files changed, 16434 insertions, 0 deletions
diff --git a/svx/source/tbxctrls/Palette.cxx b/svx/source/tbxctrls/Palette.cxx new file mode 100644 index 0000000000..b3f1965de3 --- /dev/null +++ b/svx/source/tbxctrls/Palette.cxx @@ -0,0 +1,383 @@ +/* -*- 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/Palette.hxx> +#include <tools/stream.hxx> + +#include <palettes.hxx> +#include <utility> + +Palette::~Palette() +{ +} + +PaletteASE::~PaletteASE() +{ +} + +PaletteASE::PaletteASE( OUString aFPath, OUString aFName ) : + mbValidPalette( false ), + maFPath (std::move( aFPath )), + maASEPaletteName (std::move( aFName )) +{ + LoadPalette(); +} + +void PaletteASE::LoadColorSet(SvxColorValueSet& rColorSet) +{ + rColorSet.Clear(); + int nIx = 1; + for (const auto& rColor : maColors) + { + rColorSet.InsertItem(nIx, rColor.m_aColor, rColor.m_aName); + ++nIx; + } +} + +const OUString& PaletteASE::GetName() +{ + return maASEPaletteName; +} + +const OUString& PaletteASE::GetPath() +{ + return maFPath; +} + +bool PaletteASE::IsValid() +{ + return mbValidPalette; +} + +// CMYK values from 0 to 1 +// TODO: Deduplicate me (taken from core/cui/source/dialogs/colorpicker.cxx) +static void lcl_CMYKtoRGB( float fCyan, float fMagenta, float fYellow, float fKey, float& dR, float& dG, float& dB ) +{ + fCyan = (fCyan * ( 1.0 - fKey )) + fKey; + fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey; + fYellow = (fYellow * ( 1.0 - fKey )) + fKey; + + dR = std::clamp( 1.0 - fCyan, 0.0, 1.0 ); + dG = std::clamp( 1.0 - fMagenta, 0.0, 1.0 ); + dB = std::clamp( 1.0 - fYellow, 0.0, 1.0 ); +} + +void PaletteASE::LoadPalette() +{ + SvFileStream aFile(maFPath, StreamMode::READ); + aFile.SetEndian(SvStreamEndian::BIG); + + // Verify magic first 4 characters + char cMagic[5] = {0}; + if ((aFile.ReadBytes(cMagic, 4) != 4) || (strncmp(cMagic, "ASEF", 4) != 0)) + { + mbValidPalette = false; + return; + } + + // Ignore the version number + aFile.SeekRel(4); + + sal_uInt32 nBlocks = 0; + aFile.ReadUInt32(nBlocks); + for (sal_uInt32 nI = 0; nI < nBlocks; nI++) { + sal_uInt32 nChunkType = 0; + aFile.ReadUInt32(nChunkType); + // End chunk + if (nChunkType == 0) + break; + + // Grab chunk size, name length + sal_uInt16 nChunkSize = 0; + sal_uInt16 nChars = 0; + aFile.ReadUInt16(nChunkSize); + aFile.ReadUInt16(nChars); + + OUString aPaletteName(""); + if (nChars > 1) + aPaletteName = read_uInt16s_ToOUString(aFile, nChars); + else + aFile.SeekRel(2); + + if (nChunkType == 0xC0010000) + { + // Got a start chunk, so set palette name + maASEPaletteName = aPaletteName; + // Is there color data? (shouldn't happen in a start block, but check anyway) + if (nChunkSize > ((nChars * 2) + 2)) + aPaletteName.clear(); + else + continue; + } + + char cColorModel[5] = {0}; + aFile.ReadBytes(cColorModel, 4); + OString aColorModel(cColorModel); + // r, g, and b are floats ranging from 0 to 1 + float r = 0, g = 0, b = 0; + + if (aColorModel.equalsIgnoreAsciiCase("cmyk")) + { + float c = 0, m = 0, y = 0, k = 0; + aFile.ReadFloat(c); + aFile.ReadFloat(m); + aFile.ReadFloat(y); + aFile.ReadFloat(k); + lcl_CMYKtoRGB(c, m, y, k, r, g, b); + } + else if (aColorModel.equalsIgnoreAsciiCase("rgb ")) + { + aFile.ReadFloat(r); + aFile.ReadFloat(g); + aFile.ReadFloat(b); + } + else if (aColorModel.equalsIgnoreAsciiCase("gray")) + { + float nVal = 0; + aFile.ReadFloat(nVal); + r = g = b = nVal; + } + else + { + float nL = 0, nA = 0, nB = 0; + aFile.ReadFloat(nL); + aFile.ReadFloat(nA); + aFile.ReadFloat(nB); + // TODO: How to convert LAB to RGB? + r = g = b = 0; + } + + // Ignore color type + aFile.SeekRel(2); + maColors.emplace_back(Color(r * 255, g * 255, b * 255), aPaletteName); + } + + mbValidPalette = true; +} + +Palette* PaletteASE::Clone() const +{ + return new PaletteASE(*this); +} + +// PaletteGPL ------------------------------------------------------------------ + +static OString lcl_getToken(OStringBuffer& rStr, sal_Int32& index); + +PaletteGPL::PaletteGPL( OUString aFPath, OUString aFName ) : + mbLoadedPalette( false ), + mbValidPalette( false ), + maFName(std::move( aFName )), + maFPath(std::move( aFPath )) +{ + LoadPaletteHeader(); +} + +PaletteGPL::~PaletteGPL() +{ +} + +const OUString& PaletteGPL::GetName() +{ + return maGPLPaletteName; +} + +const OUString& PaletteGPL::GetPath() +{ + return maFPath; +} + +void PaletteGPL::LoadColorSet(SvxColorValueSet& rColorSet) +{ + LoadPalette(); + + rColorSet.Clear(); + int nIx = 1; + for (const auto& rColor : maColors) + { + rColorSet.InsertItem(nIx, rColor.m_aColor, rColor.m_aName); + ++nIx; + } +} + +bool PaletteGPL::IsValid() +{ + return mbValidPalette; +} + +bool PaletteGPL::ReadPaletteHeader(SvFileStream& rFileStream) +{ + OString aLine; + OString aPaletteName; + + rFileStream.ReadLine(aLine); + if( !aLine.startsWith("GIMP Palette") ) return false; + rFileStream.ReadLine(aLine); + if( aLine.startsWith("Name: ", &aPaletteName) ) + { + maGPLPaletteName = OStringToOUString(aPaletteName, RTL_TEXTENCODING_ASCII_US); + rFileStream.ReadLine(aLine); + if( aLine.startsWith("Columns: ")) + rFileStream.ReadLine(aLine); // we can ignore this + } + else + { + maGPLPaletteName = maFName; + } + return true; +} + +void PaletteGPL::LoadPaletteHeader() +{ + SvFileStream aFile(maFPath, StreamMode::READ); + mbValidPalette = ReadPaletteHeader( aFile ); +} + +void PaletteGPL::LoadPalette() +{ + if( mbLoadedPalette ) return; + mbLoadedPalette = true; + + // TODO add error handling!!! + SvFileStream aFile(maFPath, StreamMode::READ); + mbValidPalette = ReadPaletteHeader( aFile ); + + if( !mbValidPalette ) return; + + OStringBuffer aLine; + do { + if (aLine.isEmpty()) + continue; + + if (aLine[0] != '#' && aLine[0] != '\n') + { + // TODO check if r,g,b are 0<= x <=255, or just clamp? + sal_Int32 nIndex = 0; + OString token; + + token = lcl_getToken(aLine, nIndex); + if(token.isEmpty() || nIndex == -1) continue; + sal_Int32 r = token.toInt32(); + + token = lcl_getToken(aLine, nIndex); + if(token.isEmpty() || nIndex == -1) continue; + sal_Int32 g = token.toInt32(); + + token = lcl_getToken(aLine, nIndex); + if(token.isEmpty()) continue; + sal_Int32 b = token.toInt32(); + + std::string_view name; + if(nIndex != -1) + name = std::string_view(aLine).substr(nIndex); + + maColors.emplace_back( + Color(r, g, b), + OStringToOUString(name, RTL_TEXTENCODING_ASCII_US)); + } + } while (aFile.ReadLine(aLine)); +} + +Palette* PaletteGPL::Clone() const +{ + return new PaletteGPL(*this); +} + +// finds first token in rStr from index, separated by whitespace +// returns position of next token in index +static OString lcl_getToken(OStringBuffer& rStr, sal_Int32& index) +{ + sal_Int32 substart, toklen = 0; + OUString aWhitespaceChars( " \n\t" ); + + while(index < rStr.getLength() && + aWhitespaceChars.indexOf( rStr[index] ) != -1) + ++index; + if(index == rStr.getLength()) + { + index = -1; + return OString(); + } + substart = index; + + //counts length of token + while(index < rStr.getLength() && + aWhitespaceChars.indexOf( rStr[index] ) == -1 ) + { + ++index; + ++toklen; + } + + //counts to position of next token + while(index < rStr.getLength() && + aWhitespaceChars.indexOf( rStr[index] ) != -1 ) + ++index; + if(index == rStr.getLength()) + index = -1; + + return OString(std::string_view(rStr).substr(substart, toklen)); +} + +// PaletteSOC ------------------------------------------------------------------ + +PaletteSOC::PaletteSOC( OUString aFPath, OUString aFName ) : + mbLoadedPalette( false ), + maFPath(std::move( aFPath )), + maSOCPaletteName(std::move( aFName )) +{ +} + +PaletteSOC::~PaletteSOC() +{ +} + +const OUString& PaletteSOC::GetName() +{ + return maSOCPaletteName; +} + +const OUString& PaletteSOC::GetPath() +{ + return maFPath; +} + +void PaletteSOC::LoadColorSet(SvxColorValueSet& rColorSet) +{ + if( !mbLoadedPalette ) + { + mbLoadedPalette = true; + mpColorList = XPropertyList::AsColorList(XPropertyList::CreatePropertyListFromURL(XPropertyListType::Color, maFPath)); + (void)mpColorList->Load(); + } + rColorSet.Clear(); + if( mpColorList.is() ) + rColorSet.addEntriesForXColorList( *mpColorList ); +} + +bool PaletteSOC::IsValid() +{ + return true; +} + +Palette* PaletteSOC::Clone() const +{ + return new PaletteSOC(*this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/PaletteManager.cxx b/svx/source/tbxctrls/PaletteManager.cxx new file mode 100644 index 0000000000..a98149ff30 --- /dev/null +++ b/svx/source/tbxctrls/PaletteManager.cxx @@ -0,0 +1,472 @@ +/* -*- 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/PaletteManager.hxx> + +#include <basegfx/color/bcolortools.hxx> +#include <comphelper/propertyvalue.hxx> +#include <tools/urlobj.hxx> +#include <osl/file.hxx> +#include <unotools/pathoptions.hxx> +#include <sfx2/objsh.hxx> +#include <svx/drawitem.hxx> +#include <svx/strings.hrc> +#include <svx/svxids.hrc> +#include <svx/dialmgr.hxx> + +#include <tbxcolorupdate.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <comphelper/sequence.hxx> +#include <officecfg/Office/Common.hxx> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <docmodel/color/ComplexColor.hxx> +#include <docmodel/color/ComplexColorJSON.hxx> +#include <editeng/colritem.hxx> +#include <editeng/memberids.h> + +#include <palettes.hxx> + +#include <memory> +#include <array> +#include <stack> +#include <set> + +PaletteManager::PaletteManager() : + mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()), + mnNumOfPalettes(3), + mnCurrentPalette(0), + mnColorCount(0), + mpBtnUpdater(nullptr), + maColorSelectFunction(PaletteManager::DispatchColorCommand) + +{ + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if(pDocSh) + { + const SfxPoolItem* pItem = nullptr; + if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) ) + pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList(); + } + if(!pColorList.is()) + pColorList = XColorList::CreateStdColorList(); + LoadPalettes(); + mnNumOfPalettes += m_Palettes.size(); + +} + +PaletteManager::PaletteManager(const PaletteManager* pClone) + : mnMaxRecentColors(pClone->mnMaxRecentColors) + , mnNumOfPalettes(pClone->mnNumOfPalettes) + , mnCurrentPalette(pClone->mnCurrentPalette) + , mnColorCount(pClone->mnColorCount) + , mpBtnUpdater(nullptr) + , pColorList(pClone->pColorList) + , maRecentColors(pClone->maRecentColors) + , maColorSelectFunction(PaletteManager::DispatchColorCommand) +{ + for (const auto& a : pClone->m_Palettes) + m_Palettes.emplace_back(a->Clone()); +} + +PaletteManager* PaletteManager::Clone() const +{ + return new PaletteManager(this); +} + +PaletteManager::~PaletteManager() +{ +} + +void PaletteManager::LoadPalettes() +{ + m_Palettes.clear(); + OUString aPalPaths = SvtPathOptions().GetPalettePath(); + + std::stack<OUString> aDirs; + sal_Int32 nIndex = 0; + do + { + aDirs.push(aPalPaths.getToken(0, ';', nIndex)); + } + while (nIndex >= 0); + + std::set<OUString> aNames; + //try all entries palette path list user first, then + //system, ignoring duplicate file names + while (!aDirs.empty()) + { + OUString aPalPath = aDirs.top(); + aDirs.pop(); + + osl::Directory aDir(aPalPath); + osl::DirectoryItem aDirItem; + osl::FileStatus aFileStat( osl_FileStatus_Mask_FileName | + osl_FileStatus_Mask_FileURL | + osl_FileStatus_Mask_Type ); + if( aDir.open() == osl::FileBase::E_None ) + { + while( aDir.getNextItem(aDirItem) == osl::FileBase::E_None ) + { + aDirItem.getFileStatus(aFileStat); + if(aFileStat.isRegular() || aFileStat.isLink()) + { + OUString aFName = aFileStat.getFileName(); + INetURLObject aURLObj( aFileStat.getFileURL() ); + OUString aFNameWithoutExt = aURLObj.GetBase(); + if (aNames.find(aFName) == aNames.end()) + { + std::unique_ptr<Palette> pPalette; + if( aFName.endsWithIgnoreAsciiCase(".gpl") ) + pPalette.reset(new PaletteGPL(aFileStat.getFileURL(), aFNameWithoutExt)); + else if( aFName.endsWithIgnoreAsciiCase(".soc") ) + pPalette.reset(new PaletteSOC(aFileStat.getFileURL(), aFNameWithoutExt)); + else if ( aFName.endsWithIgnoreAsciiCase(".ase") ) + pPalette.reset(new PaletteASE(aFileStat.getFileURL(), aFNameWithoutExt)); + + if( pPalette && pPalette->IsValid() ) + m_Palettes.push_back( std::move(pPalette) ); + aNames.insert(aFNameWithoutExt); + } + } + } + } + } +} + +bool PaletteManager::IsThemePaletteSelected() const +{ + return mnCurrentPalette == mnNumOfPalettes - 2; +} + +bool PaletteManager::GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& rThemeIndex, sal_uInt16& rEffectIndex) +{ + // tdf#157034, nItemId begins with 1 but list of themes begin with 0 + // so decrement nItemId + --nItemId; + + // Each column is the same color with different effects. + rThemeIndex = nItemId % 12; + + rEffectIndex = nItemId / 12; + if (rEffectIndex > 5) + return false; + return true; +} + +bool PaletteManager::GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16& rLumMod, sal_Int16& rLumOff) +{ + if (!moThemePaletteCollection) + return false; + + auto const& aThemeColorData = moThemePaletteCollection->maColors[nThemeIndex]; + + rLumMod = aThemeColorData.getLumMod(nEffect); + rLumOff = aThemeColorData.getLumOff(nEffect); + + return true; +} + +void PaletteManager::ReloadColorSet(SvxColorValueSet &rColorSet) +{ + moThemePaletteCollection.reset(); + if( mnCurrentPalette == 0) + { + rColorSet.Clear(); + css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() ); + css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() ); + int nIx = 1; + for (int i = 0; i < CustomColorList.getLength(); ++i) + { + Color aColor(ColorTransparency, CustomColorList[i]); + rColorSet.InsertItem(nIx, aColor, CustomColorNameList[i]); + ++nIx; + } + } + else if (IsThemePaletteSelected()) + { + SfxObjectShell* pObjectShell = SfxObjectShell::Current(); + if (pObjectShell) + { + auto pColorSet = pObjectShell->GetThemeColors(); + mnColorCount = 12; + rColorSet.Clear(); + sal_uInt16 nItemId = 1; + + if (!pColorSet) + return; + + svx::ThemeColorPaletteManager aThemeColorManager(pColorSet); + moThemePaletteCollection = aThemeColorManager.generate(); + + // Each row is one effect type (no effect + each type). + for (size_t nEffect : {0, 1, 2, 3, 4, 5}) + { + // Each column is one color type. + for (auto const& rColorData : moThemePaletteCollection->maColors) + { + auto const& rEffect = rColorData.maEffects[nEffect]; + rColorSet.InsertItem(nItemId++, rEffect.maColor, rEffect.maColorName); + } + } + } + } + else if( mnCurrentPalette == mnNumOfPalettes - 1 ) + { + // Add doc colors to palette + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if (pDocSh) + { + std::set<Color> aColors = pDocSh->GetDocColors(); + mnColorCount = aColors.size(); + rColorSet.Clear(); + rColorSet.addEntriesForColorSet(aColors, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " ") ); + } + } + else + { + m_Palettes[mnCurrentPalette - 1]->LoadColorSet( rColorSet ); + mnColorCount = rColorSet.GetItemCount(); + } +} + +void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet) +{ + maRecentColors.clear(); + rColorSet.Clear(); + css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get()); + css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get()); + int nIx = 1; + const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength(); + for (int i = 0; i < Colorlist.getLength(); ++i) + { + Color aColor(ColorTransparency, Colorlist[i]); + OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase()); + maRecentColors.emplace_back(aColor, sColorName); + rColorSet.InsertItem(nIx, aColor, sColorName); + ++nIx; + } +} + +std::vector<OUString> PaletteManager::GetPaletteList() +{ + std::vector<OUString> aPaletteNames + { + SvxResId( RID_SVXSTR_CUSTOM_PAL ) + }; + for (auto const& it : m_Palettes) + { + aPaletteNames.push_back( (*it).GetName() ); + } + aPaletteNames.push_back(SvxResId(RID_SVXSTR_THEME_COLORS)); + aPaletteNames.push_back( SvxResId ( RID_SVXSTR_DOC_COLORS ) ); + + return aPaletteNames; +} + +void PaletteManager::SetPalette( sal_Int32 nPos ) +{ + mnCurrentPalette = nPos; + if( nPos != mnNumOfPalettes - 1 && nPos != 0) + { + pColorList = XPropertyList::AsColorList( + XPropertyList::CreatePropertyListFromURL( + XPropertyListType::Color, GetSelectedPalettePath())); + auto name = GetPaletteName(); // may change pColorList + pColorList->SetName(name); + if(pColorList->Load()) + { + SfxObjectShell* pShell = SfxObjectShell::Current(); + if (pShell != nullptr) + { + SvxColorListItem aColorItem(pColorList, SID_COLOR_TABLE); + pShell->PutItem( aColorItem ); + } + } + } + OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get()); + if (aPaletteName != GetPaletteName()) + { + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::UserColors::PaletteName::set(GetPaletteName(), batch); + batch->commit(); + } +} + +sal_Int32 PaletteManager::GetPalette() const +{ + return mnCurrentPalette; +} + +OUString PaletteManager::GetPaletteName() +{ + std::vector<OUString> aNames(GetPaletteList()); + if(mnCurrentPalette != mnNumOfPalettes - 1 && mnCurrentPalette != 0) + { + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if(pDocSh) + { + const SfxPoolItem* pItem = nullptr; + if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) ) + pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList(); + } + } + return aNames[mnCurrentPalette]; +} + +OUString PaletteManager::GetSelectedPalettePath() +{ + if (mnCurrentPalette < m_Palettes.size() && mnCurrentPalette != 0) + return m_Palettes[mnCurrentPalette - 1]->GetPath(); + else + return OUString(); +} + +tools::Long PaletteManager::GetColorCount() const +{ + return mnColorCount; +} + +tools::Long PaletteManager::GetRecentColorCount() const +{ + return maRecentColors.size(); +} + +void PaletteManager::AddRecentColor(const Color& rRecentColor, const OUString& rName, bool bFront) +{ + auto itColor = std::find_if(maRecentColors.begin(), + maRecentColors.end(), + [rRecentColor] (const NamedColor &aColor) { return aColor.m_aColor == rRecentColor; }); + // if recent color to be added is already in list, remove it + if( itColor != maRecentColors.end() ) + maRecentColors.erase( itColor ); + + if (maRecentColors.size() == mnMaxRecentColors) + maRecentColors.pop_back(); + if (bFront) + maRecentColors.emplace_front(rRecentColor, rName); + else + maRecentColors.emplace_back(rRecentColor, rName); + css::uno::Sequence< sal_Int32 > aColorList(maRecentColors.size()); + auto aColorListRange = asNonConstRange(aColorList); + css::uno::Sequence< OUString > aColorNameList(maRecentColors.size()); + auto aColorNameListRange = asNonConstRange(aColorNameList); + for (size_t i = 0; i < maRecentColors.size(); ++i) + { + aColorListRange[i] = static_cast<sal_Int32>(maRecentColors[i].m_aColor); + aColorNameListRange[i] = maRecentColors[i].m_aName; + } + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::UserColors::RecentColor::set(aColorList, batch); + officecfg::Office::Common::UserColors::RecentColorName::set(aColorNameList, batch); + batch->commit(); +} + +void PaletteManager::SetSplitButtonColor(const NamedColor& rColor) +{ + if (mpBtnUpdater) + mpBtnUpdater->SetRecentColor(rColor); +} + +void PaletteManager::SetBtnUpdater(svx::ToolboxButtonColorUpdaterBase* pBtnUpdater) +{ + mpBtnUpdater = pBtnUpdater; +} + +void PaletteManager::SetColorSelectFunction(const ColorSelectFunction& aColorSelectFunction) +{ + maColorSelectFunction = aColorSelectFunction; +} + +void PaletteManager::PopupColorPicker(weld::Window* pParent, const OUString& aCommand, const Color& rInitialColor) +{ + // The calling object goes away during aColorDlg.Execute(), so we must copy this + OUString aCommandCopy = aCommand; + m_pColorDlg = std::make_unique<SvColorDialog>(); + m_pColorDlg->SetColor(rInitialColor); + m_pColorDlg->SetMode(svtools::ColorPickerMode::Modify); + std::shared_ptr<PaletteManager> xSelf(shared_from_this()); + m_pColorDlg->ExecuteAsync(pParent, [xSelf, aCommandCopy] (sal_Int32 nResult) { + if (nResult == RET_OK) + { + Color aLastColor = xSelf->m_pColorDlg->GetColor(); + OUString sColorName = "#" + aLastColor.AsRGBHexString().toAsciiUpperCase(); + NamedColor aNamedColor(aLastColor, sColorName); + xSelf->SetSplitButtonColor(aNamedColor); + xSelf->AddRecentColor(aLastColor, sColorName); + xSelf->maColorSelectFunction(aCommandCopy, aNamedColor); + } + }); +} + +void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedColor& rColor) +{ + using namespace css; + using namespace css::uno; + using namespace css::frame; + using namespace css::beans; + using namespace css::util; + + Reference<XComponentContext> xContext(comphelper::getProcessComponentContext()); + Reference<XDesktop2> xDesktop = Desktop::create(xContext); + Reference<XFrame> xFrame(xDesktop->getCurrentFrame()); + Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY); + if (!xDispatchProvider.is()) + return; + + INetURLObject aObj( aCommand ); + + std::vector<PropertyValue> aArgs{ + comphelper::makePropertyValue(aObj.GetURLPath()+ ".Color", sal_Int32(rColor.m_aColor)), + }; + + if (rColor.m_nThemeIndex != -1) + { + model::ComplexColor aComplexColor; + aComplexColor.setThemeColor(model::convertToThemeColorType(rColor.m_nThemeIndex)); + if (rColor.m_nLumMod != 10000) + aComplexColor.addTransformation({model::TransformationType::LumMod, rColor.m_nLumMod}); + if (rColor.m_nLumMod != 0) + aComplexColor.addTransformation({model::TransformationType::LumOff, rColor.m_nLumOff}); + + uno::Any aAny; + aAny <<= OStringToOUString(model::color::convertToJSON(aComplexColor), RTL_TEXTENCODING_UTF8); + + aArgs.push_back(comphelper::makePropertyValue(aObj.GetURLPath() + ".ComplexColorJSON", aAny)); + } + + URL aTargetURL; + aTargetURL.Complete = aCommand; + Reference<XURLTransformer> xURLTransformer(URLTransformer::create(comphelper::getProcessComponentContext())); + xURLTransformer->parseStrict(aTargetURL); + + Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0); + if (xDispatch.is()) + { + xDispatch->dispatch(aTargetURL, comphelper::containerToSequence(aArgs)); + if (xFrame->getContainerWindow().is()) + xFrame->getContainerWindow()->setFocus(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx new file mode 100644 index 0000000000..d26063d544 --- /dev/null +++ b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <StylesPreviewToolBoxControl.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <vcl/svapp.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +StylesPreviewToolBoxControl::StylesPreviewToolBoxControl() {} + +StylesPreviewToolBoxControl::~StylesPreviewToolBoxControl() {} + +void SAL_CALL +StylesPreviewToolBoxControl::initialize(const css::uno::Sequence<css::uno::Any>& rArguments) +{ + svt::ToolboxController::initialize(rArguments); + + if (m_xFrame.is()) + InitializeStyles(m_xFrame->getController()->getModel()); +} + +void SAL_CALL StylesPreviewToolBoxControl::dispose() +{ + svt::ToolboxController::dispose(); + + SolarMutexGuard aSolarMutexGuard; + m_xVclBox.disposeAndClear(); + m_xWeldBox.reset(); +} + +void StylesPreviewToolBoxControl::InitializeStyles( + const css::uno::Reference<css::frame::XModel>& xModel) +{ + m_aDefaultStyles.clear(); + + //now convert the default style names to the localized names + try + { + css::uno::Reference<css::style::XStyleFamiliesSupplier> xStylesSupplier( + xModel, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::lang::XServiceInfo> xServices(xModel, css::uno::UNO_QUERY_THROW); + if (xServices->supportsService("com.sun.star.text.TextDocument")) + { + css::uno::Reference<css::container::XNameAccess> xParaStyles; + xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>= xParaStyles; + static const std::vector<OUString> aWriterStyles + = { "Standard", "Text body", "Heading 1", "Heading 2", "Heading 3", + "Heading 4", "Title", "Subtitle", "Quotations", "Preformatted Text" }; + for (const OUString& aStyle : aWriterStyles) + { + try + { + css::uno::Reference<css::beans::XPropertySet> xStyle; + xParaStyles->getByName(aStyle) >>= xStyle; + OUString sName; + xStyle->getPropertyValue("DisplayName") >>= sName; + if (!sName.isEmpty()) + m_aDefaultStyles.push_back(std::pair<OUString, OUString>(aStyle, sName)); + } + catch (const css::container::NoSuchElementException&) + { + } + catch (const css::uno::Exception&) + { + } + } + } + else if (xServices->supportsService("com.sun.star.sheet.SpreadsheetDocument")) + { + static const char* aCalcStyles[] = { "Default", "Accent 1", "Accent 2", "Accent 3", + "Heading 1", "Heading 2", "Result" }; + css::uno::Reference<css::container::XNameAccess> xCellStyles; + xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles; + for (const char* pCalcStyle : aCalcStyles) + { + try + { + const OUString sStyleName(OUString::createFromAscii(pCalcStyle)); + if (xCellStyles->hasByName(sStyleName)) + { + css::uno::Reference<css::beans::XPropertySet> xStyle( + xCellStyles->getByName(sStyleName), css::uno::UNO_QUERY_THROW); + OUString sName; + xStyle->getPropertyValue("DisplayName") >>= sName; + if (!sName.isEmpty()) + { + m_aDefaultStyles.push_back( + std::pair<OUString, OUString>(sStyleName, sName)); + } + } + } + catch (const css::uno::Exception&) + { + } + } + } + } + catch (const css::uno::Exception&) + { + OSL_FAIL("error while initializing style names"); + } +} + +void SAL_CALL StylesPreviewToolBoxControl::update() {} + +void StylesPreviewToolBoxControl::statusChanged(const css::frame::FeatureStateEvent& /*rEvent*/) {} + +css::uno::Reference<css::awt::XWindow> +StylesPreviewToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + css::uno::Reference<css::awt::XWindow> xItemWindow; + + /* TODO + if (m_pBuilder) + { + SolarMutexGuard aSolarMutexGuard; + + std::unique_ptr<weld::Container> xWidget(*m_pBuilder); + + xItemWindow + = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get())); + + m_xWeldBox.reset(new StylesPreviewWindow_Base(std::move(xWidget))); + m_pBox = m_xWeldBox.get(); + } + else + */ + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent); + if (pParent) + { + SolarMutexGuard aSolarMutexGuard; + + m_xVclBox = VclPtr<StylesPreviewWindow_Impl>::Create( + pParent, std::vector(m_aDefaultStyles), m_xFrame); + xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox); + } + } + + return xItemWindow; +} + +OUString StylesPreviewToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.StylesPreviewToolBoxControl"; +} + +sal_Bool StylesPreviewToolBoxControl::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> StylesPreviewToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_StylesPreviewToolBoxControl_get_implementation( + css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new StylesPreviewToolBoxControl()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx new file mode 100644 index 0000000000..da560feb0e --- /dev/null +++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx @@ -0,0 +1,681 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <StylesPreviewWindow.hxx> + +#include <comphelper/base64.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/propertyvalue.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <sfx2/objsh.hxx> +#include <svl/itemset.hxx> +#include <sfx2/tbxctrl.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/tplpitem.hxx> +#include <sfx2/viewsh.hxx> +#include <vcl/filter/PngImageWriter.hxx> +#include <vcl/glyphitemcache.hxx> +#include <vcl/virdev.hxx> +#include <vcl/settings.hxx> + +#include <editeng/editids.hrc> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/svxfont.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/brushitem.hxx> + +#include <i18nlangtag/mslangid.hxx> + +#include <svx/xfillit0.hxx> +#include <svx/xdef.hxx> +#include <svx/xflclit.hxx> + +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/uno/Sequence.hxx> + +#include <vcl/commandevent.hxx> +#include <tools/json_writer.hxx> + +namespace +{ +class StylePreviewCache +{ +private: + class JsonStylePreviewCacheClear final : public Timer + { + public: + JsonStylePreviewCacheClear() + : Timer("Json Style Preview Cache clear callback") + { + // a generous 30 secs + SetTimeout(30000); + SetStatic(); + } + virtual void Invoke() override { StylePreviewCache::gJsonStylePreviewCache.clear(); } + }; + + static std::map<OUString, VclPtr<VirtualDevice>> gStylePreviewCache; + static std::map<OUString, OString> gJsonStylePreviewCache; + static int gStylePreviewCacheClients; + static JsonStylePreviewCacheClear gJsonIdleClear; + +public: + static std::map<OUString, VclPtr<VirtualDevice>>& Get() { return gStylePreviewCache; } + static std::map<OUString, OString>& GetJson() { return gJsonStylePreviewCache; } + + static void ClearCache(bool bHard) + { + for (auto& aPreview : gStylePreviewCache) + aPreview.second.disposeAndClear(); + + gStylePreviewCache.clear(); + if (bHard) + { + StylePreviewCache::gJsonStylePreviewCache.clear(); + gJsonIdleClear.Stop(); + } + else + { + // tdf#155720 don't immediately clear the json representation + gJsonIdleClear.Start(); + } + } + + static void RegisterClient() + { + if (!gStylePreviewCacheClients) + gJsonIdleClear.Stop(); + gStylePreviewCacheClients++; + } + + static void UnregisterClient() + { + gStylePreviewCacheClients--; + if (!gStylePreviewCacheClients) + ClearCache(false); + } +}; + +std::map<OUString, VclPtr<VirtualDevice>> StylePreviewCache::gStylePreviewCache; +std::map<OUString, OString> StylePreviewCache::gJsonStylePreviewCache; +int StylePreviewCache::gStylePreviewCacheClients; +StylePreviewCache::JsonStylePreviewCacheClear StylePreviewCache::gJsonIdleClear; +} + +StyleStatusListener::StyleStatusListener( + StylesPreviewWindow_Base* pPreviewControl, + const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider) + : SfxStatusListener(xDispatchProvider, SID_STYLE_FAMILY2, ".uno:ParaStyle") + , m_pPreviewControl(pPreviewControl) +{ + ReBind(); +} + +void StyleStatusListener::StateChangedAtStatusListener(SfxItemState /*eState*/, + const SfxPoolItem* pState) +{ + const SfxTemplateItem* pStateItem = dynamic_cast<const SfxTemplateItem*>(pState); + if (pStateItem) + { + if (pStateItem->GetStyleIdentifier().isEmpty()) + m_pPreviewControl->Select(pStateItem->GetStyleName()); + else + m_pPreviewControl->Select(pStateItem->GetStyleIdentifier()); + } +} + +StylePoolChangeListener::StylePoolChangeListener(StylesPreviewWindow_Base* pPreviewControl) + : m_pPreviewControl(pPreviewControl) +{ + SfxObjectShell* pDocShell = SfxObjectShell::Current(); + + m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr; + + if (m_pStyleSheetPool) + { + StartListening(*m_pStyleSheetPool); + } +} + +StylePoolChangeListener::~StylePoolChangeListener() +{ + if (m_pStyleSheetPool) + EndListening(*m_pStyleSheetPool); +} + +void StylePoolChangeListener::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::StyleSheetModified) + StylePreviewCache::ClearCache(true); + m_pPreviewControl->RequestStylesListUpdate(); +} + +StyleItemController::StyleItemController(std::pair<OUString, OUString> aStyleName) + : m_eStyleFamily(SfxStyleFamily::Para) + , m_aStyleName(std::move(aStyleName)) +{ +} + +void StyleItemController::Paint(vcl::RenderContext& rRenderContext) +{ + rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT + | vcl::PushFlags::TEXTCOLOR); + + DrawEntry(rRenderContext); + + rRenderContext.Pop(); +} + +bool StylesPreviewWindow_Base::Command(const CommandEvent& rEvent) +{ + if (rEvent.GetCommand() != CommandEventId::ContextMenu) + return false; + + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(m_xStylesView.get(), "svx/ui/stylemenu.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + OUString rIdent = xMenu->popup_at_rect(m_xStylesView.get(), + tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1))); + if (rIdent == "update" || rIdent == "edit") + { + css::uno::Sequence<css::beans::PropertyValue> aArgs(0); + + const css::uno::Reference<css::frame::XDispatchProvider> xProvider(m_xFrame, + css::uno::UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, + rIdent == "update" ? OUString(".uno:StyleUpdateByExample") + : OUString(".uno:EditStyle"), + aArgs); + + return true; + } + + return false; +} + +static Color GetTextColorFromItemSet(std::optional<SfxItemSet> const& pItemSet) +{ + const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR); + if (pItem) + return static_cast<const SvxColorItem*>(pItem)->GetValue(); + + return COL_AUTO; +} + +static Color GetHighlightColorFromItemSet(std::optional<SfxItemSet> const& pItemSet) +{ + const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR); + if (pItem) + return static_cast<const SvxBrushItem*>(pItem)->GetColor(); + + return COL_AUTO; +} + +static Color GetBackgroundColorFromItemSet(std::optional<SfxItemSet> const& pItemSet) +{ + const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLCOLOR); + if (pItem) + return static_cast<const XFillColorItem*>(pItem)->GetColorValue(); + + return COL_AUTO; +} + +static css::drawing::FillStyle GetFillStyleFromItemSet(std::optional<SfxItemSet> const& pItemSet) +{ + const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLSTYLE); + if (pItem) + return static_cast<const XFillStyleItem*>(pItem)->GetValue(); + + return css::drawing::FillStyle_NONE; +} + +static SvxFont GetFontFromItems(const SvxFontItem* pFontItem, Size aPixelFontSize, + std::optional<SfxItemSet> const& pItemSet) +{ + SvxFont aFont; + + aFont.SetFamilyName(pFontItem->GetFamilyName()); + aFont.SetStyleName(pFontItem->GetStyleName()); + aFont.SetFontSize(aPixelFontSize); + + const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT); + if (pItem) + aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE); + if (pItem) + aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR); + if (pItem) + aFont.SetOutline(static_cast<const SvxContourItem*>(pItem)->GetValue()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED); + if (pItem) + aFont.SetShadow(static_cast<const SvxShadowedItem*>(pItem)->GetValue()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF); + if (pItem) + aFont.SetRelief(static_cast<const SvxCharReliefItem*>(pItem)->GetValue()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE); + if (pItem) + aFont.SetUnderline(static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE); + if (pItem) + aFont.SetOverline(static_cast<const SvxOverlineItem*>(pItem)->GetValue()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT); + if (pItem) + aFont.SetStrikeout(static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP); + if (pItem) + aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap()); + + pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK); + if (pItem) + aFont.SetEmphasisMark(static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark()); + + return aFont; +} + +void StyleItemController::DrawEntry(vcl::RenderContext& rRenderContext) +{ + SfxObjectShell* pShell = SfxObjectShell::Current(); + if (!pShell) + return; + + SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool(); + SfxStyleSheetBase* pStyle = nullptr; + + if (!pPool) + return; + + pStyle = pPool->First(m_eStyleFamily); + while (pStyle && pStyle->GetName() != m_aStyleName.first + && pStyle->GetName() != m_aStyleName.second) + pStyle = pPool->Next(); + + if (!pStyle) + return; + + Size aSize(rRenderContext.GetOutputSizePixel()); + tools::Rectangle aFullRect(Point(0, 0), aSize); + tools::Rectangle aContentRect(aFullRect); + + Color aOriginalColor = rRenderContext.GetFillColor(); + Color aOriginalLineColor = rRenderContext.GetLineColor(); + + DrawContentBackground(rRenderContext, aContentRect, aOriginalColor); + + std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview()); + if (!pItemSet) + return; + + Color aFontHighlight = COL_AUTO; + + sal_Int16 nScriptType + = MsLangId::getScriptType(Application::GetSettings().GetUILanguageTag().getLanguageType()); + + sal_uInt16 nFontSlot = SID_ATTR_CHAR_FONT; + if (nScriptType == css::i18n::ScriptType::ASIAN) + nFontSlot = SID_ATTR_CHAR_CJK_FONT; + else if (nScriptType == css::i18n::ScriptType::COMPLEX) + nFontSlot = SID_ATTR_CHAR_CTL_FONT; + + const SvxFontItem* const pFontItem = pItemSet->GetItem<SvxFontItem>(nFontSlot); + const SvxFontHeightItem* const pFontHeightItem + = pItemSet->GetItem<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT); + + if (pFontItem && pFontHeightItem) + { + Size aFontSize(0, pFontHeightItem->GetHeight()); + Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit()))); + + SvxFont aFont = GetFontFromItems(pFontItem, aPixelSize, pItemSet); + rRenderContext.SetFont(aFont); + + Color aFontCol = GetTextColorFromItemSet(pItemSet); + if (aFontCol != COL_AUTO) + rRenderContext.SetTextColor(aFontCol); + + aFontHighlight = GetHighlightColorFromItemSet(pItemSet); + + css::drawing::FillStyle style = GetFillStyleFromItemSet(pItemSet); + + switch (style) + { + case css::drawing::FillStyle_SOLID: + { + Color aBackCol = GetBackgroundColorFromItemSet(pItemSet); + if (aBackCol != COL_AUTO) + DrawContentBackground(rRenderContext, aContentRect, aBackCol); + } + break; + + default: + break; + //TODO Draw the other background styles: gradient, hatching and bitmap + } + } + + if (aFontHighlight != COL_AUTO) + DrawHighlight(rRenderContext, aFontHighlight); + + DrawText(rRenderContext); + + rRenderContext.SetFillColor(aOriginalColor); + rRenderContext.SetLineColor(aOriginalLineColor); +} + +void StyleItemController::DrawContentBackground(vcl::RenderContext& rRenderContext, + const tools::Rectangle& aContentRect, + const Color& aColor) +{ + rRenderContext.SetLineColor(aColor); + rRenderContext.SetFillColor(aColor); + rRenderContext.DrawRect(aContentRect); +} + +void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack) +{ + tools::Rectangle aTextRect; + rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second); + + Size aSize = aTextRect.GetSize(); + aSize.AdjustHeight(aSize.getHeight()); + aTextRect.SetSize(aSize); + + Point aPos(0, 0); + aPos.AdjustX(LEFT_MARGIN); + aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2); + aTextRect.SetPos(aPos); + + rRenderContext.SetLineColor(aFontBack); + rRenderContext.SetFillColor(aFontBack); + + rRenderContext.DrawRect(aTextRect); +} + +void StyleItemController::DrawText(vcl::RenderContext& rRenderContext) +{ + const SalLayoutGlyphs* layoutGlyphs + = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rRenderContext, m_aStyleName.second); + tools::Rectangle aTextRect; + rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, {}, + layoutGlyphs); + + Point aPos(0, 0); + aPos.AdjustX(LEFT_MARGIN); + aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2); + + rRenderContext.DrawText(aPos, m_aStyleName.second, 0, -1, nullptr, nullptr, layoutGlyphs); +} + +StylesPreviewWindow_Base::StylesPreviewWindow_Base( + weld::Builder& xBuilder, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles, + const css::uno::Reference<css::frame::XFrame>& xFrame) + : m_xFrame(xFrame) + , m_xStylesView(xBuilder.weld_icon_view("stylesview")) + , m_aUpdateTask(*this) + , m_aDefaultStyles(std::move(aDefaultStyles)) +{ + StylePreviewCache::RegisterClient(); + + m_xStylesView->connect_selection_changed(LINK(this, StylesPreviewWindow_Base, Selected)); + m_xStylesView->connect_item_activated(LINK(this, StylesPreviewWindow_Base, DoubleClick)); + m_xStylesView->connect_command(LINK(this, StylesPreviewWindow_Base, DoCommand)); + m_xStylesView->connect_get_property_tree_elem( + LINK(this, StylesPreviewWindow_Base, DoJsonProperty)); + + const css::uno::Reference<css::frame::XDispatchProvider> xProvider(m_xFrame, + css::uno::UNO_QUERY); + m_xStatusListener = new StyleStatusListener(this, xProvider); + + m_pStylePoolChangeListener.reset(new StylePoolChangeListener(this)); + + RequestStylesListUpdate(); +} + +IMPL_LINK(StylesPreviewWindow_Base, Selected, weld::IconView&, rIconView, void) +{ + OUString sStyleName = rIconView.get_selected_text(); + + css::uno::Sequence<css::beans::PropertyValue> aArgs{ + comphelper::makePropertyValue("Template", sStyleName), + comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para)) + }; + const css::uno::Reference<css::frame::XDispatchProvider> xProvider(m_xFrame, + css::uno::UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleApply", aArgs); +} + +IMPL_LINK(StylesPreviewWindow_Base, DoubleClick, weld::IconView&, rIconView, bool) +{ + OUString sStyleName = rIconView.get_selected_text(); + + css::uno::Sequence<css::beans::PropertyValue> aArgs{ + comphelper::makePropertyValue("Param", sStyleName), + comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para)) + }; + const css::uno::Reference<css::frame::XDispatchProvider> xProvider(m_xFrame, + css::uno::UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, ".uno:EditStyle", aArgs); + + return true; +} + +IMPL_LINK(StylesPreviewWindow_Base, DoCommand, const CommandEvent&, rPos, bool) +{ + return Command(rPos); +} + +StylesPreviewWindow_Base::~StylesPreviewWindow_Base() +{ + m_xStatusListener->UnBind(); + + m_aUpdateTask.Stop(); + + StylePreviewCache::UnregisterClient(); + + try + { + m_xStatusListener->dispose(); + } + catch (css::uno::Exception&) + { + } + + m_xStatusListener = nullptr; +} + +void StylesPreviewWindow_Base::Select(const OUString& rStyleName) +{ + m_sSelectedStyle = rStyleName; + + UpdateSelection(); +} + +void StylesPreviewWindow_Base::UpdateSelection() +{ + for (std::vector<std::pair<OUString, OUString>>::size_type i = 0; i < m_aAllStyles.size(); ++i) + { + if (m_aAllStyles[i].first == m_sSelectedStyle || m_aAllStyles[i].second == m_sSelectedStyle) + { + m_xStylesView->select(i); + break; + } + } +} + +void StylesPreviewWindow_Base::RequestStylesListUpdate() { m_aUpdateTask.Start(); } + +void StylesListUpdateTask::Invoke() +{ + m_rStylesList.UpdateStylesList(); + m_rStylesList.UpdateSelection(); +} + +static OString extractPngString(const BitmapEx& rBitmap) +{ + SvMemoryStream aOStm(65535, 65535); + // Use fastest compression "1" + css::uno::Sequence<css::beans::PropertyValue> aFilterData{ + comphelper::makePropertyValue("Compression", sal_Int32(1)), + }; + vcl::PngImageWriter aPNGWriter(aOStm); + aPNGWriter.setParameters(aFilterData); + if (aPNGWriter.write(rBitmap)) + { + css::uno::Sequence<sal_Int8> aSeq(static_cast<sal_Int8 const*>(aOStm.GetData()), + aOStm.Tell()); + OStringBuffer aBuffer("data:image/png;base64,"); + ::comphelper::Base64::encode(aBuffer, aSeq); + return aBuffer.makeStringAndClear(); + } + + return ""_ostr; +} + +// 0: json writer, 1: TreeIter, 2: property. returns true if supported +IMPL_LINK(StylesPreviewWindow_Base, DoJsonProperty, const weld::json_prop_query&, rQuery, bool) +{ + if (std::get<2>(rQuery) != "image") + return false; + + const weld::TreeIter& rIter = std::get<1>(rQuery); + OUString sStyleId(m_xStylesView->get_id(rIter)); + OUString sStyleName(m_xStylesView->get_text(rIter)); + OString sBase64Png(GetCachedPreviewJson(std::pair<OUString, OUString>(sStyleId, sStyleName))); + if (sBase64Png.isEmpty()) + return false; + + tools::JsonWriter& rJsonWriter = std::get<0>(rQuery); + rJsonWriter.put("image", sBase64Png); + + return true; +} + +VclPtr<VirtualDevice> +StylesPreviewWindow_Base::GetCachedPreview(const std::pair<OUString, OUString>& rStyle) +{ + auto aFound = StylePreviewCache::Get().find(rStyle.second); + if (aFound != StylePreviewCache::Get().end()) + return StylePreviewCache::Get()[rStyle.second]; + else + { + VclPtr<VirtualDevice> pImg = VclPtr<VirtualDevice>::Create(); + const Size aSize(100, 30); + pImg->SetOutputSizePixel(aSize); + + StyleItemController aStyleController(rStyle); + aStyleController.Paint(*pImg); + StylePreviewCache::Get()[rStyle.second] = pImg; + + return pImg; + } +} + +OString StylesPreviewWindow_Base::GetCachedPreviewJson(const std::pair<OUString, OUString>& rStyle) +{ + auto aJsonFound = StylePreviewCache::GetJson().find(rStyle.second); + if (aJsonFound != StylePreviewCache::GetJson().end()) + return StylePreviewCache::GetJson()[rStyle.second]; + + VclPtr<VirtualDevice> xDev = GetCachedPreview(rStyle); + BitmapEx aBitmap(xDev->GetBitmapEx(Point(0, 0), xDev->GetOutputSize())); + OString sResult = extractPngString(aBitmap); + StylePreviewCache::GetJson()[rStyle.second] = sResult; + return sResult; +} + +void StylesPreviewWindow_Base::UpdateStylesList() +{ + m_aAllStyles = m_aDefaultStyles; + + SfxObjectShell* pDocShell = SfxObjectShell::Current(); + SfxStyleSheetBasePool* pStyleSheetPool = nullptr; + + if (pDocShell) + pStyleSheetPool = pDocShell->GetStyleSheetPool(); + + if (pStyleSheetPool) + { + auto xIter = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para, + SfxStyleSearchBits::UserDefined); + + SfxStyleSheetBase* pStyle = xIter->First(); + + while (pStyle) + { + OUString sName(pStyle->GetName()); + m_aAllStyles.push_back(std::pair<OUString, OUString>(sName, sName)); + pStyle = xIter->Next(); + } + } + + m_xStylesView->freeze(); + m_xStylesView->clear(); + // for online we can skip inserting the preview into the IconView and rely + // on DoJsonProperty to provide the image to clients + const bool bNeedInsertPreview = !comphelper::LibreOfficeKit::isActive(); + for (const auto& rStyle : m_aAllStyles) + { + VclPtr<VirtualDevice> pImg = bNeedInsertPreview ? GetCachedPreview(rStyle) : nullptr; + m_xStylesView->append(rStyle.first, rStyle.second, pImg); + } + m_xStylesView->thaw(); +} + +StylesPreviewWindow_Impl::StylesPreviewWindow_Impl( + vcl::Window* pParent, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles, + const css::uno::Reference<css::frame::XFrame>& xFrame) + : InterimItemWindow(pParent, "svx/ui/stylespreview.ui", "ApplyStyleBox", true, + reinterpret_cast<sal_uInt64>(SfxViewShell::Current())) + , StylesPreviewWindow_Base(*m_xBuilder, std::move(aDefaultStyles), xFrame) +{ + SetOptimalSize(); +} + +StylesPreviewWindow_Impl::~StylesPreviewWindow_Impl() { disposeOnce(); } + +void StylesPreviewWindow_Impl::dispose() +{ + m_xStylesView.reset(); + + InterimItemWindow::dispose(); +} + +void StylesPreviewWindow_Impl::SetOptimalSize() { SetSizePixel(get_preferred_size()); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/svx/source/tbxctrls/SvxColorChildWindow.cxx b/svx/source/tbxctrls/SvxColorChildWindow.cxx new file mode 100644 index 0000000000..c7fb9a683b --- /dev/null +++ b/svx/source/tbxctrls/SvxColorChildWindow.cxx @@ -0,0 +1,43 @@ +/* -*- 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/SvxColorChildWindow.hxx> +#include <svx/svxids.hrc> +#include <colrctrl.hxx> + +SFX_IMPL_DOCKINGWINDOW_WITHID( SvxColorChildWindow, SID_COLOR_CONTROL ) + +// Derivation from SfxChildWindow as "container" for animator +SvxColorChildWindow::SvxColorChildWindow( vcl::Window* _pParent, + sal_uInt16 nId, + SfxBindings* pBindings, + SfxChildWinInfo* pInfo ) : + SfxChildWindow( _pParent, nId ) +{ + VclPtr<SvxColorDockingWindow> pWin = VclPtr<SvxColorDockingWindow>::Create( pBindings, this, + _pParent ); + + SetWindow(pWin); + + SetAlignment(SfxChildAlignment::RIGHT); + + pWin->Initialize( pInfo ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/SvxColorValueSet.cxx b/svx/source/tbxctrls/SvxColorValueSet.cxx new file mode 100644 index 0000000000..4a181730ed --- /dev/null +++ b/svx/source/tbxctrls/SvxColorValueSet.cxx @@ -0,0 +1,166 @@ +/* -*- 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/SvxColorValueSet.hxx> +#include <svx/xtable.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <osl/diagnose.h> + +#include <svx/uiobject.hxx> + +SvxColorValueSet::SvxColorValueSet(std::unique_ptr<weld::ScrolledWindow> pWindow) + : ValueSet(std::move(pWindow)) +{ + SetEdgeBlending(true); +} + +FactoryFunction SvxColorValueSet::GetUITestFactory() const +{ + return SvxColorValueSetUIObject::create; +} + +sal_uInt32 SvxColorValueSet::getEntryEdgeLength() +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + return rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1; +} + +sal_uInt32 SvxColorValueSet::getColumnCount() +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + return rStyleSettings.GetColorValueSetColumnCount(); +} + +void SvxColorValueSet::addEntriesForXColorList(const XColorList& rXColorList, sal_uInt32 nStartIndex) +{ + const sal_uInt32 nColorCount(rXColorList.Count()); + + for(sal_uInt32 nIndex(0); nIndex < nColorCount; nIndex++, nStartIndex++) + { + const XColorEntry* pEntry = rXColorList.GetColor(nIndex); + + if(pEntry) + { + InsertItem(nStartIndex, pEntry->GetColor(), pEntry->GetName()); + } + else + { + OSL_ENSURE(false, "OOps, XColorList with empty entries (!)"); + } + } +} + +void SvxColorValueSet::addEntriesForColorSet(const std::set<Color>& rColorSet, std::u16string_view rNamePrefix) +{ + sal_uInt32 nStartIndex = 1; + if(rNamePrefix.size() != 0) + { + for(const auto& rColor : rColorSet) + { + InsertItem(nStartIndex, rColor, rNamePrefix + OUString::number(nStartIndex)); + nStartIndex++; + } + } + else + { + for(const auto& rColor : rColorSet) + { + InsertItem(nStartIndex, rColor, ""); + nStartIndex++; + } + } +} + +Size SvxColorValueSet::layoutAllVisible(sal_uInt32 nEntryCount) +{ + if(!nEntryCount) + { + nEntryCount++; + } + + const sal_uInt32 nRowCount(ceil(double(nEntryCount)/SvxColorValueSet::getColumnCount())); + const Size aItemSize(SvxColorValueSet::getEntryEdgeLength() - 2, SvxColorValueSet::getEntryEdgeLength() - 2); + const WinBits aWinBits(GetStyle() & ~WB_VSCROLL); + + if (nRowCount > SvxColorValueSet::getMaxRowCount()) + { + SetStyle(aWinBits|WB_VSCROLL); + } + else + { + SetStyle(aWinBits); + } + + SetColCount(SvxColorValueSet::getColumnCount()); + SetLineCount(std::min(nRowCount, SvxColorValueSet::getMaxRowCount())); + SetItemWidth(aItemSize.Width()); + SetItemHeight(aItemSize.Height()); + + return CalcWindowSizePixel(aItemSize); +} + +void SvxColorValueSet::Resize() +{ + layoutToGivenHeight(GetOutputSizePixel().Height(), GetItemCount()); + ValueSet::Resize(); +} + +void SvxColorValueSet::layoutToGivenHeight(sal_uInt32 nHeight, sal_uInt32 nEntryCount) +{ + if(!nEntryCount) + { + nEntryCount++; + } + + const Size aItemSize(SvxColorValueSet::getEntryEdgeLength() - 2, SvxColorValueSet::getEntryEdgeLength() - 2); + const WinBits aWinBits(GetStyle() & ~WB_VSCROLL); + + // get size with all fields disabled + const WinBits aWinBitsNoScrollNoFields(GetStyle() & ~(WB_VSCROLL|WB_NAMEFIELD|WB_NONEFIELD)); + SetStyle(aWinBitsNoScrollNoFields); + const Size aSizeNoScrollNoFields(CalcWindowSizePixel(aItemSize, SvxColorValueSet::getColumnCount())); + + // get size with all needed fields + SetStyle(aWinBits); + Size aNewSize(CalcWindowSizePixel(aItemSize, SvxColorValueSet::getColumnCount())); + + const Size aItemSizePixel(CalcItemSizePixel(aItemSize)); + // calculate field height and available height for requested height + const sal_uInt32 nFieldHeight(aNewSize.Height() - aSizeNoScrollNoFields.Height()); + const sal_uInt32 nAvailableHeight(nHeight >= nFieldHeight ? nHeight - nFieldHeight + aItemSizePixel.Height() - 1 : 0); + + // calculate how many lines can be shown there + const sal_uInt32 nLineCount(nAvailableHeight / aItemSizePixel.Height()); + const sal_uInt32 nLineMax(ceil(double(nEntryCount)/SvxColorValueSet::getColumnCount())); + + if(nLineMax > nLineCount) + { + SetStyle(aWinBits|WB_VSCROLL); + } + + SetItemWidth(aItemSize.Width()); + SetItemHeight(aItemSize.Height()); + SetColCount(SvxColorValueSet::getColumnCount()); + SetLineCount(nLineCount); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/SvxPresetListBox.cxx b/svx/source/tbxctrls/SvxPresetListBox.cxx new file mode 100644 index 0000000000..bbbfa73634 --- /dev/null +++ b/svx/source/tbxctrls/SvxPresetListBox.cxx @@ -0,0 +1,112 @@ +/* -*- 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/SvxPresetListBox.hxx> +#include <svx/xtable.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/image.hxx> +#include <vcl/svapp.hxx> + +SvxPresetListBox::SvxPresetListBox(std::unique_ptr<weld::ScrolledWindow> pWindow) + : ValueSet(std::move(pWindow)) + , aIconSize(60, 64) +{ + SetEdgeBlending(true); +} + +void SvxPresetListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + ValueSet::SetDrawingArea(pDrawingArea); + SetStyle(GetStyle() | WB_ITEMBORDER); +} + +void SvxPresetListBox::Resize() +{ + DrawLayout(); + WinBits aWinBits(GetStyle()); + aWinBits |= WB_VSCROLL; + SetStyle(aWinBits); + ValueSet::Resize(); +} + +bool SvxPresetListBox::Command(const CommandEvent& rEvent) +{ + if (rEvent.GetCommand() != CommandEventId::ContextMenu) + return CustomWidgetController::Command(rEvent); + const sal_uInt16 nIndex = GetSelectedItemId(); + if (nIndex > 0) + { + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(GetDrawingArea(), "svx/ui/presetmenu.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + OnMenuItemSelected(xMenu->popup_at_rect( + GetDrawingArea(), tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1)))); + return true; + } + return false; +} + +void SvxPresetListBox::DrawLayout() +{ + SetColCount(nColCount); + SetLineCount(5); +} + +template <typename ListType, typename EntryType> +void SvxPresetListBox::FillPresetListBoxImpl(ListType& pList, sal_uInt32 nStartIndex) +{ + const Size aSize(GetIconSize()); + BitmapEx aBitmap; + for (tools::Long nIndex = 0; nIndex < pList.Count(); nIndex++, nStartIndex++) + { + aBitmap = pList.GetBitmapForPreview(nIndex, aSize); + EntryType* pItem = static_cast<EntryType*>(pList.Get(nIndex)); + InsertItem(nStartIndex, Image(aBitmap), pItem->GetName()); + } +} + +void SvxPresetListBox::FillPresetListBox(XGradientList& pList, sal_uInt32 nStartIndex) +{ + FillPresetListBoxImpl<XGradientList, XGradientEntry>(pList, nStartIndex); +} + +void SvxPresetListBox::FillPresetListBox(XHatchList& pList, sal_uInt32 nStartIndex) +{ + FillPresetListBoxImpl<XHatchList, XHatchEntry>(pList, nStartIndex); +} + +void SvxPresetListBox::FillPresetListBox(XBitmapList& pList, sal_uInt32 nStartIndex) +{ + FillPresetListBoxImpl<XBitmapList, XBitmapEntry>(pList, nStartIndex); +} + +void SvxPresetListBox::FillPresetListBox(XPatternList& pList, sal_uInt32 nStartIndex) +{ + FillPresetListBoxImpl<XPatternList, XBitmapEntry>(pList, nStartIndex); +} + +void SvxPresetListBox::OnMenuItemSelected(std::u16string_view rIdent) +{ + if (rIdent == u"rename") + maRenameHdl.Call(this); + else if (rIdent == u"delete") + maDeleteHdl.Call(this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/bulletsnumbering.cxx b/svx/source/tbxctrls/bulletsnumbering.cxx new file mode 100644 index 0000000000..e1a55a1123 --- /dev/null +++ b/svx/source/tbxctrls/bulletsnumbering.cxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <com/sun/star/text/DefaultNumberingProvider.hpp> +#include <com/sun/star/text/XNumberingFormatter.hpp> + +#include <comphelper/propertysequence.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <svtools/popupwindowcontroller.hxx> +#include <svtools/toolbarmenu.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> +#include <svx/numvset.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +namespace { + +class NumberingToolBoxControl; + +class NumberingPopup : public WeldToolbarPopup +{ + NumberingPageType mePageType; + NumberingToolBoxControl& mrController; + std::unique_ptr<SvxNumValueSet> mxValueSet; + std::unique_ptr<weld::CustomWeld> mxValueSetWin; + std::unique_ptr<weld::Button> mxMoreButton; + DECL_LINK(VSSelectValueSetHdl, ValueSet*, void); + DECL_LINK(VSButtonClickSetHdl, weld::Button&, void); + + virtual void GrabFocus() override; + +public: + NumberingPopup(NumberingToolBoxControl& rController, weld::Widget* pParent, NumberingPageType ePageType); + + virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; +}; + +class NumberingToolBoxControl : public svt::PopupWindowController +{ + NumberingPageType mePageType; + +public: + explicit NumberingToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +NumberingPopup::NumberingPopup(NumberingToolBoxControl& rController, + weld::Widget* pParent, NumberingPageType ePageType) + : WeldToolbarPopup(rController.getFrameInterface(), pParent, "svx/ui/numberingwindow.ui", "NumberingWindow") + , mePageType(ePageType) + , mrController(rController) + , mxValueSet(new SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true))) + , mxValueSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxValueSet)) + , mxMoreButton(m_xBuilder->weld_button("more")) +{ + mxValueSet->SetStyle(WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NO_DIRECTSELECT); + mxValueSet->init(mePageType); + + if ( mePageType != NumberingPageType::BULLET ) + { + css::uno::Reference< css::text::XDefaultNumberingProvider > xDefNum = css::text::DefaultNumberingProvider::create( mrController.getContext() ); + if ( xDefNum.is() ) + { + css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale(); + css::uno::Reference< css::text::XNumberingFormatter > xFormat( xDefNum, css::uno::UNO_QUERY ); + + if ( mePageType == NumberingPageType::SINGLENUM ) + { + css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aNumberings( + xDefNum->getDefaultContinuousNumberingLevels( aLocale ) ); + mxValueSet->SetNumberingSettings( aNumberings, xFormat, aLocale ); + } + else if ( mePageType == NumberingPageType::OUTLINE ) + { + css::uno::Sequence< css::uno::Reference< css::container::XIndexAccess > > aOutline( + xDefNum->getDefaultOutlineNumberings( aLocale ) ); + mxValueSet->SetOutlineNumberingSettings( aOutline, xFormat, aLocale ); + } + } + } + + weld::DrawingArea* pDrawingArea = mxValueSet->GetDrawingArea(); + OutputDevice& rRefDevice = pDrawingArea->get_ref_device(); + Size aItemSize(rRefDevice.LogicToPixel(Size(30, 42), MapMode(MapUnit::MapAppFont))); + mxValueSet->SetExtraSpacing( 2 ); + Size aSize(mxValueSet->CalcWindowSizePixel(aItemSize)); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + mxValueSet->SetOutputSizePixel(aSize); + mxValueSet->SetColor(Application::GetSettings().GetStyleSettings().GetFieldColor()); + + OUString aMoreItemText = SvxResId( RID_SVXSTR_CUSTOMIZE ); + if ( mePageType == NumberingPageType::BULLET ) + AddStatusListener( ".uno:CurrentBulletListType" ); + else if ( mePageType == NumberingPageType::SINGLENUM ) + AddStatusListener( ".uno:CurrentNumListType" ); + else + AddStatusListener( ".uno:CurrentOutlineType" ); + + auto xImage = vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:OutlineBullet", mrController.getFrameInterface()); + mxMoreButton->set_image(xImage); + mxMoreButton->set_label(aMoreItemText); + mxMoreButton->connect_clicked(LINK(this, NumberingPopup, VSButtonClickSetHdl)); + + mxValueSet->SetSelectHdl(LINK(this, NumberingPopup, VSSelectValueSetHdl)); +} + +void NumberingPopup::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + mxValueSet->SetNoSelection(); + + sal_Int32 nSelItem; + if ( rEvent.State >>= nSelItem ) + mxValueSet->SelectItem( nSelItem ); +} + +IMPL_LINK_NOARG(NumberingPopup, VSSelectValueSetHdl, ValueSet*, void) +{ + sal_uInt16 nSelItem = mxValueSet->GetSelectedItemId(); + if ( mePageType == NumberingPageType::BULLET ) + { + auto aArgs( comphelper::InitPropertySequence( { { "SetBullet", css::uno::Any( nSelItem ) } } ) ); + mrController.dispatchCommand( ".uno:SetBullet", aArgs ); + } + else if ( mePageType == NumberingPageType::SINGLENUM ) + { + auto aArgs( comphelper::InitPropertySequence( { { "SetNumber", css::uno::Any( nSelItem ) } } ) ); + mrController.dispatchCommand( ".uno:SetNumber", aArgs ); + } + else + { + auto aArgs( comphelper::InitPropertySequence( { { "SetOutline", css::uno::Any( nSelItem ) } } ) ); + mrController.dispatchCommand( ".uno:SetOutline", aArgs ); + } + mrController.EndPopupMode(); +} + +void NumberingPopup::GrabFocus() +{ + mxValueSet->GrabFocus(); +} + +IMPL_LINK_NOARG(NumberingPopup, VSButtonClickSetHdl, weld::Button&, void) +{ + auto aArgs( comphelper::InitPropertySequence( { { "Page", css::uno::Any( OUString("customize") ) } } ) ); + mrController.dispatchCommand( ".uno:OutlineBullet", aArgs ); + + mrController.EndPopupMode(); +} + +NumberingToolBoxControl::NumberingToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ): + svt::PopupWindowController( rxContext, css::uno::Reference< css::frame::XFrame >(), OUString() ), + mePageType( NumberingPageType::SINGLENUM ) +{ +} + +std::unique_ptr<WeldToolbarPopup> NumberingToolBoxControl::weldPopupWindow() +{ + return std::make_unique<NumberingPopup>(*this, m_pToolbar, mePageType); +} + +VclPtr<vcl::Window> NumberingToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<NumberingPopup>(*this, pParent->GetFrameWeld(), mePageType)); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +void SAL_CALL NumberingToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + if ( m_aCommandURL == ".uno:DefaultBullet" ) + mePageType = NumberingPageType::BULLET; + else if ( m_aCommandURL == ".uno:SetOutline" ) + mePageType = NumberingPageType::OUTLINE; + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + return; + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + { + ToolBoxItemBits nBits = mePageType == NumberingPageType::OUTLINE + ? ToolBoxItemBits::DROPDOWNONLY + : ToolBoxItemBits::DROPDOWN; + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | nBits ); + } +} + +OUString SAL_CALL NumberingToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.NumberingToolBoxControl"; +} + +css::uno::Sequence< OUString > SAL_CALL NumberingToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_NumberingToolBoxControl_get_implementation( + css::uno::XComponentContext *rxContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new NumberingToolBoxControl( rxContext ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/colrctrl.cxx b/svx/source/tbxctrls/colrctrl.cxx new file mode 100644 index 0000000000..da829d127e --- /dev/null +++ b/svx/source/tbxctrls/colrctrl.cxx @@ -0,0 +1,423 @@ +/* -*- 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 <sot/exchange.hxx> +#include <svx/strings.hrc> +#include <svx/svxids.hrc> + +#include <sfx2/viewsh.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/image.hxx> +#include <vcl/transfer.hxx> + +#include <colrctrl.hxx> + +#include <svx/svdview.hxx> +#include <svx/drawitem.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> +#include <editeng/colritem.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlnclit.hxx> +#include <svx/xtable.hxx> +#include <svx/dialmgr.hxx> +#include <helpids.h> +#include <vcl/virdev.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> + +using namespace com::sun::star; + +class SvxColorValueSetData final : public TransferDataContainer +{ +private: + uno::Sequence<beans::NamedValue> m_Data; + + virtual void AddSupportedFormats() override; + virtual bool GetData(const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc) override; + +public: + SvxColorValueSetData() + { + } + + void SetData(const uno::Sequence<beans::NamedValue>& rData) + { + m_Data = rData; + ClearFormats(); // invalidate m_aAny so new data will take effect + } +}; + +void SvxColorValueSetData::AddSupportedFormats() +{ + AddFormat( SotClipboardFormatId::XFA ); +} + +bool SvxColorValueSetData::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) +{ + bool bRet = false; + + if( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::XFA ) + { + SetAny(uno::Any(m_Data)); + bRet = true; + } + + return bRet; +} + +void SvxColorValueSet_docking::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + SvxColorValueSet::SetDrawingArea(pDrawingArea); + SetAccessibleName(SvxResId(STR_COLORTABLE)); + SetStyle(GetStyle() | WB_ITEMBORDER); + + m_xHelper.set(new SvxColorValueSetData); + rtl::Reference<TransferDataContainer> xHelper(m_xHelper); + SetDragDataTransferable(xHelper, DND_ACTION_COPY); +} + +SvxColorValueSet_docking::SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> xWindow) + : SvxColorValueSet(std::move(xWindow)) + , mbLeftButton(true) +{ +} + +bool SvxColorValueSet_docking::MouseButtonDown( const MouseEvent& rMEvt ) +{ + bool bRet; + + // For Mac still handle differently! + if( rMEvt.IsLeft() ) + { + mbLeftButton = true; + bRet = SvxColorValueSet::MouseButtonDown( rMEvt ); + } + else + { + mbLeftButton = false; + MouseEvent aMEvt( rMEvt.GetPosPixel(), + rMEvt.GetClicks(), + rMEvt.GetMode(), + MOUSE_LEFT, + rMEvt.GetModifier() ); + bRet = SvxColorValueSet::MouseButtonDown( aMEvt ); + } + + return bRet; +} + +bool SvxColorValueSet_docking::MouseButtonUp( const MouseEvent& rMEvt ) +{ + bool bRet; + + // For Mac still handle differently! + if( rMEvt.IsLeft() ) + { + mbLeftButton = true; + bRet = SvxColorValueSet::MouseButtonUp( rMEvt ); + } + else + { + mbLeftButton = false; + MouseEvent aMEvt( rMEvt.GetPosPixel(), + rMEvt.GetClicks(), + rMEvt.GetMode(), + MOUSE_LEFT, + rMEvt.GetModifier() ); + bRet = SvxColorValueSet::MouseButtonUp( aMEvt ); + } + SetNoSelection(); + + return bRet; +} + +bool SvxColorValueSet_docking::StartDrag() +{ + sal_uInt16 nPos = GetSelectedItemId(); + Color aItemColor( GetItemColor( nPos ) ); + OUString sItemText( GetItemText( nPos ) ); + + drawing::FillStyle eStyle = ((1 == nPos) + ? drawing::FillStyle_NONE + : drawing::FillStyle_SOLID); + + XFillColorItem const color(sItemText, aItemColor); + XFillStyleItem const style(eStyle); + uno::Any c, s; + color.QueryValue(c, 0); + style.QueryValue(s, 0); + + uno::Sequence<beans::NamedValue> props{ { "FillColor", std::move(c) }, + { "FillStyle", std::move(s) } }; + m_xHelper->SetData(props); + + return false; +} + +constexpr sal_uInt16 gnLeftSlot = SID_ATTR_FILL_COLOR; +constexpr sal_uInt16 gnRightSlot = SID_ATTR_LINE_COLOR; + +SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings* _pBindings, SfxChildWindow* pCW, vcl::Window* _pParent) + : SfxDockingWindow(_pBindings, pCW, _pParent, + "DockingColorWindow", "svx/ui/dockingcolorwindow.ui") + , xColorSet(new SvxColorValueSet_docking(m_xBuilder->weld_scrolled_window("valuesetwin", true))) + , xColorSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *xColorSet)) +{ + SetText(SvxResId(STR_COLORTABLE)); + SetQuickHelpText(SvxResId(RID_SVXSTR_COLORBAR)); + SetSizePixel(LogicToPixel(Size(150, 22), MapMode(MapUnit::MapAppFont))); + SetHelpId(HID_CTRL_COLOR); + + xColorSet->SetSelectHdl( LINK( this, SvxColorDockingWindow, SelectHdl ) ); + xColorSet->SetHelpId(HID_COLOR_CTL_COLORS); + + // Get the model from the view shell. Using SfxObjectShell::Current() + // is unreliable when called at the wrong times. + SfxObjectShell* pDocSh = nullptr; + if (_pBindings != nullptr) + { + SfxDispatcher* pDispatcher = _pBindings->GetDispatcher(); + if (pDispatcher != nullptr) + { + SfxViewFrame* pFrame = pDispatcher->GetFrame(); + if (pFrame != nullptr) + { + SfxViewShell* pViewShell = pFrame->GetViewShell(); + if (pViewShell != nullptr) + pDocSh = pViewShell->GetObjectShell(); + } + } + } + + if ( pDocSh ) + { + const SfxPoolItem* pItem = pDocSh->GetItem( SID_COLOR_TABLE ); + if( pItem ) + { + pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList(); + FillValueSet(); + } + } + + Size aItemSize = xColorSet->CalcItemSizePixel(Size(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength())); + aItemSize.setWidth( aItemSize.Width() + SvxColorValueSet::getEntryEdgeLength() ); + aItemSize.setWidth( aItemSize.Width() / 2 ); + aItemSize.setHeight( aItemSize.Height() + SvxColorValueSet::getEntryEdgeLength() ); + aItemSize.setHeight( aItemSize.Height() / 2 ); + + if (_pBindings != nullptr) + StartListening(*_pBindings, DuplicateHandling::Prevent); +} + +SvxColorDockingWindow::~SvxColorDockingWindow() +{ + disposeOnce(); +} + +void SvxColorDockingWindow::dispose() +{ + EndListening( GetBindings() ); + xColorSetWin.reset(); + xColorSet.reset(); + SfxDockingWindow::dispose(); +} + +void SvxColorDockingWindow::Notify( SfxBroadcaster& , const SfxHint& rHint ) +{ + const SfxPoolItemHint* pPoolItemHint = dynamic_cast<const SfxPoolItemHint*>(&rHint); + if ( pPoolItemHint ) + if (auto pColorListItem = dynamic_cast<const SvxColorListItem*>(pPoolItemHint->GetObject())) + { + // The list of colors has changed + pColorList = pColorListItem->GetColorList(); + FillValueSet(); + } +} + +void SvxColorDockingWindow::FillValueSet() +{ + if( !pColorList.is() ) + return; + + xColorSet->Clear(); + + xColorSet->addEntriesForXColorList(*pColorList, 2); + + // create the last entry for 'invisible/none' + const Size aColorSize(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength()); + tools::Long nPtX = aColorSize.Width() - 1; + tools::Long nPtY = aColorSize.Height() - 1; + ScopedVclPtrInstance< VirtualDevice > pVD; + + pVD->SetOutputSizePixel( aColorSize ); + pVD->SetLineColor( COL_BLACK ); + pVD->SetBackground( Wallpaper( COL_WHITE ) ); + pVD->DrawLine( Point(), Point( nPtX, nPtY ) ); + pVD->DrawLine( Point( 0, nPtY ), Point( nPtX, 0 ) ); + + BitmapEx aBmp( pVD->GetBitmapEx( Point(), aColorSize ) ); + + xColorSet->InsertItem( sal_uInt16(1), Image(aBmp), SvxResId( RID_SVXSTR_INVISIBLE ) ); +} + +bool SvxColorDockingWindow::Close() +{ + SfxBoolItem aItem( SID_COLOR_CONTROL, false ); + GetBindings().GetDispatcher()->ExecuteList(SID_COLOR_CONTROL, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem }); + SfxDockingWindow::Close(); + return true; +} + +IMPL_LINK_NOARG(SvxColorDockingWindow, SelectHdl, ValueSet*, void) +{ + SfxDispatcher* pDispatcher = GetBindings().GetDispatcher(); + sal_uInt16 nPos = xColorSet->GetSelectedItemId(); + Color aColor( xColorSet->GetItemColor( nPos ) ); + OUString aStr( xColorSet->GetItemText( nPos ) ); + + if (xColorSet->IsLeftButton()) + { + if ( gnLeftSlot == SID_ATTR_FILL_COLOR ) + { + if ( nPos == 1 ) // invisible + { + XFillStyleItem aXFillStyleItem( drawing::FillStyle_NONE ); + pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD, + { &aXFillStyleItem }); + } + else + { + bool bDone = false; + + // If we have a DrawView and we are in TextEdit mode, then + // not the area color but the text color is assigned + SfxViewShell* pViewSh = SfxViewShell::Current(); + if ( pViewSh ) + { + SdrView* pView = pViewSh->GetDrawView(); + if ( pView && pView->IsTextEdit() ) + { + SvxColorItem aTextColorItem( aColor, SID_ATTR_CHAR_COLOR ); + pDispatcher->ExecuteList(SID_ATTR_CHAR_COLOR, + SfxCallMode::RECORD, { &aTextColorItem }); + bDone = true; + } + } + if ( !bDone ) + { + XFillStyleItem aXFillStyleItem( drawing::FillStyle_SOLID ); + XFillColorItem aXFillColorItem( aStr, aColor ); + pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD, + { &aXFillColorItem, &aXFillStyleItem }); + } + } + } + else if ( nPos != 1 ) // invisible + { + SvxColorItem aLeftColorItem( aColor, gnLeftSlot ); + pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD, + { &aLeftColorItem }); + } + } + else + { + if ( gnRightSlot == SID_ATTR_LINE_COLOR ) + { + if( nPos == 1 ) // invisible + { + XLineStyleItem aXLineStyleItem( drawing::LineStyle_NONE ); + pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD, + { &aXLineStyleItem }); + } + else + { + // If the LineStyle is invisible, it is set to SOLID + SfxViewShell* pViewSh = SfxViewShell::Current(); + if ( pViewSh ) + { + SdrView* pView = pViewSh->GetDrawView(); + if ( pView ) + { + SfxItemSet aAttrSet(pView->GetModel().GetItemPool()); + pView->GetAttributes( aAttrSet ); + if ( aAttrSet.GetItemState( XATTR_LINESTYLE ) != SfxItemState::DONTCARE ) + { + drawing::LineStyle eXLS = + aAttrSet.Get( XATTR_LINESTYLE ).GetValue(); + if ( eXLS == drawing::LineStyle_NONE ) + { + XLineStyleItem aXLineStyleItem( drawing::LineStyle_SOLID ); + pDispatcher->ExecuteList(gnRightSlot, + SfxCallMode::RECORD, { &aXLineStyleItem }); + } + } + } + } + + XLineColorItem aXLineColorItem( aStr, aColor ); + pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD, + { &aXLineColorItem }); + } + } + else if ( nPos != 1 ) // invisible + { + SvxColorItem aRightColorItem( aColor, gnRightSlot ); + pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD, + { &aRightColorItem }); + } + } +} + +void SvxColorDockingWindow::GetFocus() +{ + SfxDockingWindow::GetFocus(); + if (xColorSet) + { + // Grab the focus to the color value set so that it can be controlled + // with the keyboard. + xColorSet->GrabFocus(); + } +} + +bool SvxColorDockingWindow::EventNotify( NotifyEvent& rNEvt ) +{ + bool bRet = false; + if( rNEvt.GetType() == NotifyEventType::KEYINPUT ) + { + KeyEvent aKeyEvt = *rNEvt.GetKeyEvent(); + sal_uInt16 nKeyCode = aKeyEvt.GetKeyCode().GetCode(); + switch( nKeyCode ) + { + case KEY_ESCAPE: + GrabFocusToDocument(); + bRet = true; + break; + } + } + + return bRet || SfxDockingWindow::EventNotify(rNEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/extrusioncontrols.cxx b/svx/source/tbxctrls/extrusioncontrols.cxx new file mode 100644 index 0000000000..12a10a234c --- /dev/null +++ b/svx/source/tbxctrls/extrusioncontrols.cxx @@ -0,0 +1,968 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <comphelper/propertyvalue.hxx> +#include <svtools/toolbarmenu.hxx> +#include <vcl/toolbox.hxx> + +#include <svx/strings.hrc> +#include <svx/svdtrans.hxx> +#include <svx/dialmgr.hxx> + +#include <helpids.h> +#include "extrusioncontrols.hxx" +#include <extrusiondepthdialog.hxx> + +#include <bitmaps.hlst> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::graphic; + +namespace svx +{ + +const sal_Int32 gSkewList[] = { 135, 90, 45, 180, 0, -360, -135, -90, -45 }; +constexpr OUString g_sExtrusionDirection = u".uno:ExtrusionDirection"_ustr; +constexpr OUString g_sExtrusionProjection = u".uno:ExtrusionProjection"_ustr; +constexpr OUString EMPTY = u""_ustr; + +constexpr OUString aLightOffBmps[] = +{ + RID_SVXBMP_LIGHT_OFF_FROM_TOP_LEFT, + RID_SVXBMP_LIGHT_OFF_FROM_TOP, + RID_SVXBMP_LIGHT_OFF_FROM_TOP_RIGHT, + RID_SVXBMP_LIGHT_OFF_FROM_LEFT, + EMPTY, + RID_SVXBMP_LIGHT_OFF_FROM_RIGHT, + RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_LEFT, + RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM, + RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_RIGHT +}; + +constexpr OUString aLightOnBmps[] = +{ + RID_SVXBMP_LIGHT_ON_FROM_TOP_LEFT, + RID_SVXBMP_LIGHT_ON_FROM_TOP, + RID_SVXBMP_LIGHT_ON_FROM_TOP_RIGHT, + RID_SVXBMP_LIGHT_ON_FROM_LEFT, + EMPTY, + RID_SVXBMP_LIGHT_ON_FROM_RIGHT, + RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_LEFT, + RID_SVXBMP_LIGHT_ON_FROM_BOTTOM, + RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_RIGHT +}; + +constexpr OUString aLightPreviewBmps[] = +{ + RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_LEFT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP, + RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_RIGHT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_LEFT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_FRONT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_RIGHT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_LEFT, + RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM, + RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_RIGHT +}; + +constexpr OUString aDirectionBmps[] = +{ + RID_SVXBMP_DIRECTION_DIRECTION_NW, + RID_SVXBMP_DIRECTION_DIRECTION_N, + RID_SVXBMP_DIRECTION_DIRECTION_NE, + RID_SVXBMP_DIRECTION_DIRECTION_W, + RID_SVXBMP_DIRECTION_DIRECTION_NONE, + RID_SVXBMP_DIRECTION_DIRECTION_E, + RID_SVXBMP_DIRECTION_DIRECTION_SW, + RID_SVXBMP_DIRECTION_DIRECTION_S, + RID_SVXBMP_DIRECTION_DIRECTION_SE +}; + +static TranslateId aDirectionStrs[] = +{ + RID_SVXSTR_DIRECTION_NW, + RID_SVXSTR_DIRECTION_N, + RID_SVXSTR_DIRECTION_NE, + RID_SVXSTR_DIRECTION_W, + RID_SVXSTR_DIRECTION_NONE, + RID_SVXSTR_DIRECTION_E, + RID_SVXSTR_DIRECTION_SW, + RID_SVXSTR_DIRECTION_S, + RID_SVXSTR_DIRECTION_SE +}; + +ExtrusionDirectionWindow::ExtrusionDirectionWindow( + svt::PopupWindowController* pControl, + weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/directionwindow.ui", "DirectionWindow") + , mxControl(pControl) + , mxDirectionSet(new ValueSet(nullptr)) + , mxDirectionSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxDirectionSet)) + , mxPerspective(m_xBuilder->weld_radio_button("perspective")) + , mxParallel(m_xBuilder->weld_radio_button("parallel")) +{ + mxDirectionSet->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT); + + for (sal_uInt16 i = DIRECTION_NW; i <= DIRECTION_SE; ++i) + { + maImgDirection[i] = Image(StockImage::Yes, aDirectionBmps[i]); + } + + mxDirectionSet->SetSelectHdl( LINK( this, ExtrusionDirectionWindow, SelectValueSetHdl ) ); + mxDirectionSet->SetColCount( 3 ); + mxDirectionSet->EnableFullItemMode( false ); + + for (sal_uInt16 i = DIRECTION_NW; i <= DIRECTION_SE; ++i) + { + mxDirectionSet->InsertItem(i + 1, maImgDirection[i], SvxResId(aDirectionStrs[i])); + } + + Size aSize(72, 72); + mxDirectionSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); + mxDirectionSet->SetOutputSizePixel(aSize); + + mxPerspective->connect_toggled(LINK(this, ExtrusionDirectionWindow, SelectToolbarMenuHdl)); + + AddStatusListener( g_sExtrusionDirection ); + AddStatusListener( g_sExtrusionProjection ); +} + +void ExtrusionDirectionWindow::GrabFocus() +{ + mxDirectionSet->GrabFocus(); +} + +ExtrusionDirectionWindow::~ExtrusionDirectionWindow() +{ +} + +void ExtrusionDirectionWindow::implSetDirection( sal_Int32 nSkew, bool bEnabled ) +{ + sal_uInt16 nItemId; + for( nItemId = DIRECTION_NW; nItemId <= DIRECTION_SE; nItemId++ ) + { + if( gSkewList[nItemId] == nSkew ) + break; + } + + if( nItemId <= DIRECTION_SE ) + { + mxDirectionSet->SelectItem( nItemId+1 ); + } + else + { + mxDirectionSet->SetNoSelection(); + } + + if (bEnabled) + mxDirectionSet->Enable(); + else + mxDirectionSet->Disable(); +} + +void ExtrusionDirectionWindow::implSetProjection( sal_Int32 nProjection, bool bEnabled ) +{ + mxPerspective->set_active(nProjection == 0 && bEnabled); + mxParallel->set_active(nProjection == 1 && bEnabled); + mxPerspective->set_sensitive(bEnabled); + mxParallel->set_sensitive(bEnabled); +} + +void ExtrusionDirectionWindow::statusChanged( + const css::frame::FeatureStateEvent& Event +) +{ + if( Event.FeatureURL.Main == g_sExtrusionDirection ) + { + if( !Event.IsEnabled ) + { + implSetDirection( -1, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetDirection( nValue, true ); + } + } + else if( Event.FeatureURL.Main == g_sExtrusionProjection ) + { + if( !Event.IsEnabled ) + { + implSetProjection( -1, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetProjection( nValue, true ); + } + } +} + +IMPL_LINK_NOARG(ExtrusionDirectionWindow, SelectValueSetHdl, ValueSet*, void) +{ + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + g_sExtrusionDirection.copy(5), + gSkewList[mxDirectionSet->GetSelectedItemId()-1]) }; + + mxControl->dispatchCommand( g_sExtrusionDirection, aArgs ); + + mxControl->EndPopupMode(); +} + +IMPL_LINK_NOARG(ExtrusionDirectionWindow, SelectToolbarMenuHdl, weld::Toggleable&, void) +{ + int nProjection = mxPerspective->get_active() ? 0 : 1; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + g_sExtrusionProjection.copy(5), static_cast<sal_Int32>(nProjection)) }; + + mxControl->dispatchCommand( g_sExtrusionProjection, aArgs ); + implSetProjection( nProjection, true ); + + mxControl->EndPopupMode(); +} + +ExtrusionDirectionControl::ExtrusionDirectionControl( + const Reference< XComponentContext >& rxContext +) : svt::PopupWindowController( + rxContext, + Reference< css::frame::XFrame >(), + ".uno:ExtrusionDirectionFloater" + ) +{ +} + +std::unique_ptr<WeldToolbarPopup> ExtrusionDirectionControl::weldPopupWindow() +{ + return std::make_unique<ExtrusionDirectionWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> ExtrusionDirectionControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<ExtrusionDirectionWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL ExtrusionDirectionControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString ExtrusionDirectionControl::getImplementationName() +{ + return "com.sun.star.comp.svx.ExtrusionDirectionController"; +} + + +Sequence< OUString > ExtrusionDirectionControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_ExtrusionDirectionControl_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ExtrusionDirectionControl(xContext)); +} + + +ExtrusionDepthDialog::ExtrusionDepthDialog(weld::Window* pParent, double fDepth, FieldUnit eDefaultUnit) + : GenericDialogController(pParent, "svx/ui/extrustiondepthdialog.ui", "ExtrustionDepthDialog") + , m_xMtrDepth(m_xBuilder->weld_metric_spin_button("depth", eDefaultUnit)) +{ + m_xMtrDepth->set_value(static_cast<int>(fDepth) * 100, FieldUnit::MM_100TH); +} + +ExtrusionDepthDialog::~ExtrusionDepthDialog() +{ +} + +double ExtrusionDepthDialog::getDepth() const +{ + return static_cast<double>(m_xMtrDepth->get_value(FieldUnit::MM_100TH)) / 100.0; +} + +double const aDepthListInch[] = { 0, 1270,2540,5080,10160 }; +double const aDepthListMM[] = { 0, 1000, 2500, 5000, 10000 }; + +constexpr OUString gsExtrusionDepth( u".uno:ExtrusionDepth"_ustr ); +constexpr OUString gsMetricUnit( u".uno:MetricUnit"_ustr ); + +ExtrusionDepthWindow::ExtrusionDepthWindow(svt::PopupWindowController* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/depthwindow.ui", "DepthWindow") + , mxControl(pControl) + , mxDepth0(m_xBuilder->weld_radio_button("depth0")) + , mxDepth1(m_xBuilder->weld_radio_button("depth1")) + , mxDepth2(m_xBuilder->weld_radio_button("depth2")) + , mxDepth3(m_xBuilder->weld_radio_button("depth3")) + , mxDepth4(m_xBuilder->weld_radio_button("depth4")) + , mxInfinity(m_xBuilder->weld_radio_button("infinity")) + , mxCustom(m_xBuilder->weld_radio_button("custom")) + , meUnit(FieldUnit::NONE) + , mfDepth( -1.0 ) + , mbSettingValue(false) + , mbCommandDispatched(false) +{ + mxDepth0->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxDepth1->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxDepth2->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxDepth3->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxDepth4->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxInfinity->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxCustom->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl)); + mxCustom->connect_mouse_release(LINK(this, ExtrusionDepthWindow, MouseReleaseHdl)); + + AddStatusListener( gsExtrusionDepth ); + AddStatusListener( gsMetricUnit ); +} + +void ExtrusionDepthWindow::GrabFocus() +{ + mxDepth0->grab_focus(); +} + +void ExtrusionDepthWindow::implSetDepth( double fDepth ) +{ + mfDepth = fDepth; + + bool bSettingValue = mbSettingValue; + mbSettingValue = true; + + mxCustom->set_active(true); + bool bIsMetric = IsMetric(meUnit); + mxDepth0->set_active(fDepth == (bIsMetric ? aDepthListMM[0] : aDepthListInch[0])); + mxDepth1->set_active(fDepth == (bIsMetric ? aDepthListMM[1] : aDepthListInch[1])); + mxDepth2->set_active(fDepth == (bIsMetric ? aDepthListMM[2] : aDepthListInch[2])); + mxDepth3->set_active(fDepth == (bIsMetric ? aDepthListMM[3] : aDepthListInch[3])); + mxDepth4->set_active(fDepth == (bIsMetric ? aDepthListMM[4] : aDepthListInch[4])); + mxInfinity->set_active(fDepth >= 338666); + + mbSettingValue = bSettingValue; +} + +void ExtrusionDepthWindow::implFillStrings( FieldUnit eUnit ) +{ + meUnit = eUnit; + + const TranslateId aDepths[] = + { + RID_SVXSTR_DEPTH_0, + RID_SVXSTR_DEPTH_1, + RID_SVXSTR_DEPTH_2, + RID_SVXSTR_DEPTH_3, + RID_SVXSTR_DEPTH_4 + }; + + const TranslateId aDepthsInch[] = + { + RID_SVXSTR_DEPTH_0_INCH, + RID_SVXSTR_DEPTH_1_INCH, + RID_SVXSTR_DEPTH_2_INCH, + RID_SVXSTR_DEPTH_3_INCH, + RID_SVXSTR_DEPTH_4_INCH + }; + + static_assert(SAL_N_ELEMENTS(aDepths) == SAL_N_ELEMENTS(aDepthsInch)); + + const TranslateId* pResource = IsMetric(eUnit) ? aDepths : aDepthsInch; + + mxDepth0->set_label(SvxResId(pResource[0])); + mxDepth1->set_label(SvxResId(pResource[1])); + mxDepth2->set_label(SvxResId(pResource[2])); + mxDepth3->set_label(SvxResId(pResource[3])); + mxDepth4->set_label(SvxResId(pResource[4])); +} + +void ExtrusionDepthWindow::statusChanged( + const css::frame::FeatureStateEvent& Event +) +{ + if( Event.FeatureURL.Main == gsExtrusionDepth ) + { + if( !Event.IsEnabled ) + { + implSetDepth( 0 ); + } + else + { + double fValue = 0.0; + if( Event.State >>= fValue ) + implSetDepth( fValue ); + } + } + else if( Event.FeatureURL.Main == gsMetricUnit ) + { + if( Event.IsEnabled ) + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + { + implFillStrings( static_cast<FieldUnit>(nValue) ); + if( mfDepth >= 0.0 ) + implSetDepth( mfDepth ); + } + } + } +} + +void ExtrusionDepthWindow::DispatchDepthDialog() +{ + Sequence< PropertyValue > aArgs{ + comphelper::makePropertyValue("Depth", mfDepth), + comphelper::makePropertyValue("Metric", static_cast<sal_Int32>( meUnit )) + }; + + rtl::Reference<svt::PopupWindowController> xControl(mxControl); + xControl->EndPopupMode(); + xControl->dispatchCommand(".uno:ExtrusionDepthDialog", aArgs); + mbCommandDispatched = true; +} + +IMPL_LINK(ExtrusionDepthWindow, SelectHdl, weld::Toggleable&, rButton, void) +{ + if (mbSettingValue || !rButton.get_active()) + return; + + // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee + // this toggle will happen before that mouse release though it does in + // practice for vcl and gtk + if (mbCommandDispatched) + return; + + if (mxCustom->get_active()) + DispatchDepthDialog(); + else + { + double fDepth; + + if (mxInfinity->get_active()) + { + fDepth = 338666.6; + } + else + { + int nSelected; + if (mxDepth0->get_active()) + nSelected = 0; + else if (mxDepth1->get_active()) + nSelected = 1; + else if (mxDepth2->get_active()) + nSelected = 2; + else if (mxDepth3->get_active()) + nSelected = 3; + else + nSelected = 4; + + fDepth = IsMetric( meUnit ) ? aDepthListMM[nSelected] : aDepthListInch[nSelected]; + } + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + gsExtrusionDepth.copy(5), fDepth) }; + + mxControl->dispatchCommand( gsExtrusionDepth, aArgs ); + mbCommandDispatched = true; + implSetDepth( fDepth ); + + mxControl->EndPopupMode(); + } +} + +IMPL_LINK_NOARG(ExtrusionDepthWindow, MouseReleaseHdl, const MouseEvent&, bool) +{ + /* + tdf#145296 if the "custom" radiobutton was presented preselected as + toggled on and the user clicked on it then there's no toggled signal sent + because the item was already toggled on and didn't change state. + + So if that happens launch the custom spacing dialog explicitly here on + mouse release. + */ + if (mxCustom->get_active() && !mbCommandDispatched) + { + DispatchDepthDialog(); + return true; + } + return false; +} + +// ExtrusionDirectionControl +ExtrusionDepthController::ExtrusionDepthController( + const Reference< XComponentContext >& rxContext +) : svt::PopupWindowController( + rxContext, + Reference< css::frame::XFrame >(), + ".uno:ExtrusionDepthFloater" + ) +{ +} + +std::unique_ptr<WeldToolbarPopup> ExtrusionDepthController::weldPopupWindow() +{ + return std::make_unique<ExtrusionDepthWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> ExtrusionDepthController::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<ExtrusionDepthWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL ExtrusionDepthController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString ExtrusionDepthController::getImplementationName() +{ + return "com.sun.star.comp.svx.ExtrusionDepthController"; +} + + +Sequence< OUString > ExtrusionDepthController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_ExtrusionDepthController_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ExtrusionDepthController(xContext)); +} + + +constexpr OUString g_sExtrusionLightingDirection = u".uno:ExtrusionLightingDirection"_ustr; +constexpr OUString g_sExtrusionLightingIntensity = u".uno:ExtrusionLightingIntensity"_ustr; + +ExtrusionLightingWindow::ExtrusionLightingWindow(svt::PopupWindowController* pControl, + weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/lightingwindow.ui", "LightingWindow") + , mxControl(pControl) + , mxLightingSet(new ValueSet(nullptr)) + , mxLightingSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLightingSet)) + , mxBright(m_xBuilder->weld_radio_button("bright")) + , mxNormal(m_xBuilder->weld_radio_button("normal")) + , mxDim(m_xBuilder->weld_radio_button("dim")) +{ + mxLightingSet->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT); + + for (sal_uInt16 i = FROM_TOP_LEFT; i <= FROM_BOTTOM_RIGHT; ++i) + { + if( i != FROM_FRONT ) + { + maImgLightingOff[i] = Image(StockImage::Yes, aLightOffBmps[i]); + maImgLightingOn[i] = Image(StockImage::Yes, aLightOnBmps[i]); + } + maImgLightingPreview[i] = Image(StockImage::Yes, aLightPreviewBmps[i]); + } + + mxLightingSet->SetHelpId( HID_VALUESET_EXTRUSION_LIGHTING ); + + mxLightingSet->SetSelectHdl( LINK( this, ExtrusionLightingWindow, SelectValueSetHdl ) ); + mxLightingSet->SetColCount( 3 ); + mxLightingSet->EnableFullItemMode( false ); + + for (sal_uInt16 i = FROM_TOP_LEFT; i <= FROM_BOTTOM_RIGHT; ++i) + { + if( i != FROM_FRONT ) + { + mxLightingSet->InsertItem( i+1, maImgLightingOff[i] ); + } + else + { + mxLightingSet->InsertItem( 5, maImgLightingPreview[FROM_FRONT] ); + } + } + Size aSize(72, 72); + mxLightingSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); + mxLightingSet->SetOutputSizePixel(aSize); + + mxBright->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl)); + mxNormal->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl)); + mxDim->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl)); + + AddStatusListener( g_sExtrusionLightingDirection ); + AddStatusListener( g_sExtrusionLightingIntensity ); +} + +void ExtrusionLightingWindow::GrabFocus() +{ + mxLightingSet->GrabFocus(); +} + +ExtrusionLightingWindow::~ExtrusionLightingWindow() +{ +} + +void ExtrusionLightingWindow::implSetIntensity( int nLevel, bool bEnabled ) +{ + mxBright->set_sensitive(bEnabled); + mxBright->set_active(nLevel == 0 && bEnabled); + mxNormal->set_sensitive(bEnabled); + mxNormal->set_active(nLevel == 1 && bEnabled); + mxDim->set_sensitive(bEnabled); + mxDim->set_active(nLevel == 2 && bEnabled); +} + +void ExtrusionLightingWindow::implSetDirection( int nDirection, bool bEnabled ) +{ + if( !bEnabled ) + nDirection = FROM_FRONT; + + sal_uInt16 nItemId; + for( nItemId = FROM_TOP_LEFT; nItemId <= FROM_BOTTOM_RIGHT; nItemId++ ) + { + if( nItemId == FROM_FRONT ) + { + mxLightingSet->SetItemImage( nItemId + 1, maImgLightingPreview[ nDirection ] ); + } + else + { + mxLightingSet->SetItemImage( + nItemId + 1, + static_cast<sal_uInt16>(nDirection) == nItemId ? maImgLightingOn[nItemId] : maImgLightingOff[nItemId] + ); + } + } + + if (bEnabled) + mxLightingSet->Enable(); + else + mxLightingSet->Disable(); +} + +void ExtrusionLightingWindow::statusChanged( + const css::frame::FeatureStateEvent& Event +) +{ + if( Event.FeatureURL.Main == g_sExtrusionLightingIntensity ) + { + if( !Event.IsEnabled ) + { + implSetIntensity( 0, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetIntensity( nValue, true ); + } + } + else if( Event.FeatureURL.Main == g_sExtrusionLightingDirection ) + { + if( !Event.IsEnabled ) + { + implSetDirection( 0, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetDirection( nValue, true ); + } + } +} + +IMPL_LINK_NOARG(ExtrusionLightingWindow, SelectValueSetHdl, ValueSet*, void) +{ + sal_Int32 nDirection = mxLightingSet->GetSelectedItemId(); + + if( (nDirection > 0) && (nDirection < 10) ) + { + nDirection--; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + g_sExtrusionLightingDirection.copy(5), nDirection) }; + + mxControl->dispatchCommand( g_sExtrusionLightingDirection, aArgs ); + + implSetDirection( nDirection, true ); + } + + mxControl->EndPopupMode(); +} + +IMPL_LINK(ExtrusionLightingWindow, SelectToolbarMenuHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + int nLevel; + if (mxBright->get_active()) + nLevel = 0; + else if (mxNormal->get_active()) + nLevel = 1; + else + nLevel = 2; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + g_sExtrusionLightingIntensity.copy(5), static_cast<sal_Int32>(nLevel)) }; + + mxControl->dispatchCommand( g_sExtrusionLightingIntensity, aArgs ); + + implSetIntensity( nLevel, true ); + + mxControl->EndPopupMode(); +} + +ExtrusionLightingControl::ExtrusionLightingControl( + const Reference< XComponentContext >& rxContext +) : svt::PopupWindowController( rxContext, + Reference< css::frame::XFrame >(), + ".uno:ExtrusionDirectionFloater" + ) +{ +} + +std::unique_ptr<WeldToolbarPopup> ExtrusionLightingControl::weldPopupWindow() +{ + return std::make_unique<ExtrusionLightingWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> ExtrusionLightingControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<ExtrusionLightingWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL ExtrusionLightingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString ExtrusionLightingControl::getImplementationName() +{ + return "com.sun.star.comp.svx.ExtrusionLightingController"; +} + + +Sequence< OUString > ExtrusionLightingControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_ExtrusionLightingControl_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ExtrusionLightingControl(xContext)); +} + + +constexpr OUString g_sExtrusionSurface = u".uno:ExtrusionSurface"_ustr; + +ExtrusionSurfaceWindow::ExtrusionSurfaceWindow(svt::PopupWindowController* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/surfacewindow.ui", "SurfaceWindow") + , mxControl(pControl) + , mxWireFrame(m_xBuilder->weld_radio_button("wireframe")) + , mxMatt(m_xBuilder->weld_radio_button("matt")) + , mxPlastic(m_xBuilder->weld_radio_button("plastic")) + , mxMetal(m_xBuilder->weld_radio_button("metal")) + , mxMetalMSO(m_xBuilder->weld_radio_button("metalMSO")) +{ + mxWireFrame->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl)); + mxMatt->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl)); + mxPlastic->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl)); + mxMetal->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl)); + mxMetalMSO->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl)); + + AddStatusListener( g_sExtrusionSurface ); +} + +void ExtrusionSurfaceWindow::GrabFocus() +{ + mxWireFrame->grab_focus(); +} + +void ExtrusionSurfaceWindow::implSetSurface( int nSurface, bool bEnabled ) +{ + mxWireFrame->set_active(nSurface == 0 && bEnabled); + mxWireFrame->set_sensitive(bEnabled); + mxMatt->set_active(nSurface == 1 && bEnabled); + mxMatt->set_sensitive(bEnabled); + mxPlastic->set_active(nSurface == 2 && bEnabled); + mxPlastic->set_sensitive(bEnabled); + mxMetal->set_active(nSurface == 3 && bEnabled); + mxMetal->set_sensitive(bEnabled); + mxMetalMSO->set_active(nSurface == 4 && bEnabled); + mxMetalMSO->set_sensitive(bEnabled); +} + +void ExtrusionSurfaceWindow::statusChanged( + const css::frame::FeatureStateEvent& Event +) +{ + if( Event.FeatureURL.Main != g_sExtrusionSurface ) + return; + + if( !Event.IsEnabled ) + { + implSetSurface( 0, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetSurface( nValue, true ); + } +} + +IMPL_LINK(ExtrusionSurfaceWindow, SelectHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + sal_Int32 nSurface; + if (mxWireFrame->get_active()) + nSurface = 0; + else if (mxMatt->get_active()) + nSurface = 1; + else if (mxPlastic->get_active()) + nSurface = 2; + else if (mxMetal->get_active()) + nSurface = 3; + else + nSurface = 4; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + g_sExtrusionSurface.copy(5), nSurface) }; + + mxControl->dispatchCommand( g_sExtrusionSurface, aArgs ); + + implSetSurface( nSurface, true ); + + mxControl->EndPopupMode(); +} + +ExtrusionSurfaceControl::ExtrusionSurfaceControl( + const Reference< XComponentContext >& rxContext +) +: svt::PopupWindowController( + rxContext, + Reference< css::frame::XFrame >(), + ".uno:ExtrusionSurfaceFloater" + ) +{ +} + +std::unique_ptr<WeldToolbarPopup> ExtrusionSurfaceControl::weldPopupWindow() +{ + return std::make_unique<ExtrusionSurfaceWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> ExtrusionSurfaceControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<ExtrusionSurfaceWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL ExtrusionSurfaceControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString ExtrusionSurfaceControl::getImplementationName() +{ + return "com.sun.star.comp.svx.ExtrusionSurfaceController"; +} + + +Sequence< OUString > ExtrusionSurfaceControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_ExtrusionSurfaceControl_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ExtrusionSurfaceControl(xContext)); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/extrusioncontrols.hxx b/svx/source/tbxctrls/extrusioncontrols.hxx new file mode 100644 index 0000000000..8b7c2e8afc --- /dev/null +++ b/svx/source/tbxctrls/extrusioncontrols.hxx @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_SVX_SOURCE_TBXCTRLS_EXTRUSIONCONTROLS_HXX +#define INCLUDED_SVX_SOURCE_TBXCTRLS_EXTRUSIONCONTROLS_HXX + +#include <svtools/toolbarmenu.hxx> +#include <svtools/popupwindowcontroller.hxx> +#include <svtools/valueset.hxx> +#include <vcl/customweld.hxx> + +// enum to index light images +#define FROM_TOP_LEFT 0 +#define FROM_TOP 1 +#define FROM_TOP_RIGHT 2 +#define FROM_LEFT 3 +#define FROM_FRONT 4 +#define FROM_RIGHT 5 +#define FROM_BOTTOM_LEFT 6 +#define FROM_BOTTOM 7 +#define FROM_BOTTOM_RIGHT 8 + +#define DIRECTION_NW 0 +#define DIRECTION_N 1 +#define DIRECTION_NE 2 +#define DIRECTION_W 3 +#define DIRECTION_NONE 4 +#define DIRECTION_E 5 +#define DIRECTION_SW 6 +#define DIRECTION_S 7 +#define DIRECTION_SE 8 + +namespace svx +{ +class ExtrusionDirectionWindow final : public WeldToolbarPopup +{ +public: + ExtrusionDirectionWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override; + virtual ~ExtrusionDirectionWindow() override; + + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; + +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<ValueSet> mxDirectionSet; + std::unique_ptr<weld::CustomWeld> mxDirectionSetWin; + std::unique_ptr<weld::RadioButton> mxPerspective; + std::unique_ptr<weld::RadioButton> mxParallel; + + Image maImgDirection[9]; + + DECL_LINK( SelectToolbarMenuHdl, weld::Toggleable&, void ); + DECL_LINK( SelectValueSetHdl, ValueSet*, void ); + + void implSetDirection( sal_Int32 nSkew, bool bEnabled ); + void implSetProjection( sal_Int32 nProjection, bool bEnabled ); + +}; + +class ExtrusionDirectionControl : public svt::PopupWindowController +{ +public: + explicit ExtrusionDirectionControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class ExtrusionDepthWindow final : public WeldToolbarPopup +{ +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<weld::RadioButton> mxDepth0; + std::unique_ptr<weld::RadioButton> mxDepth1; + std::unique_ptr<weld::RadioButton> mxDepth2; + std::unique_ptr<weld::RadioButton> mxDepth3; + std::unique_ptr<weld::RadioButton> mxDepth4; + std::unique_ptr<weld::RadioButton> mxInfinity; + std::unique_ptr<weld::RadioButton> mxCustom; + + FieldUnit meUnit; + double mfDepth; + bool mbSettingValue; + bool mbCommandDispatched; + + DECL_LINK( SelectHdl, weld::Toggleable&, void ); + DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool ); + + void implFillStrings( FieldUnit eUnit ); + void implSetDepth( double fDepth ); + + void DispatchDepthDialog(); + +public: + ExtrusionDepthWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override; + + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; +}; + +class ExtrusionDepthController : public svt::PopupWindowController +{ +public: + explicit ExtrusionDepthController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class ExtrusionLightingWindow final : public WeldToolbarPopup +{ +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<ValueSet> mxLightingSet; + std::unique_ptr<weld::CustomWeld> mxLightingSetWin; + std::unique_ptr<weld::RadioButton> mxBright; + std::unique_ptr<weld::RadioButton> mxNormal; + std::unique_ptr<weld::RadioButton> mxDim; + + Image maImgLightingOff[9]; + Image maImgLightingOn[9]; + Image maImgLightingPreview[9]; + + void implSetIntensity( int nLevel, bool bEnabled ); + void implSetDirection( int nDirection, bool bEnabled ); + + DECL_LINK( SelectToolbarMenuHdl, weld::Toggleable&, void ); + DECL_LINK( SelectValueSetHdl, ValueSet*, void ); +public: + ExtrusionLightingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override; + virtual ~ExtrusionLightingWindow() override; + + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; +}; + +class ExtrusionLightingControl : public svt::PopupWindowController +{ +public: + explicit ExtrusionLightingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class ExtrusionSurfaceWindow final : public WeldToolbarPopup +{ +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<weld::RadioButton> mxWireFrame; + std::unique_ptr<weld::RadioButton> mxMatt; + std::unique_ptr<weld::RadioButton> mxPlastic; + std::unique_ptr<weld::RadioButton> mxMetal; + std::unique_ptr<weld::RadioButton> mxMetalMSO; + + DECL_LINK( SelectHdl, weld::Toggleable&, void ); + + void implSetSurface( int nSurface, bool bEnabled ); + +public: + ExtrusionSurfaceWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override; + + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; +}; + + +class ExtrusionSurfaceControl : public svt::PopupWindowController +{ +public: + explicit ExtrusionSurfaceControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/fillctrl.cxx b/svx/source/tbxctrls/fillctrl.cxx new file mode 100644 index 0000000000..5e860b3de8 --- /dev/null +++ b/svx/source/tbxctrls/fillctrl.cxx @@ -0,0 +1,1097 @@ +/* -*- 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 <sfx2/dispatch.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewsh.hxx> +#include <rtl/ustring.hxx> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> +#include <svl/itemset.hxx> +#include <svx/svxids.hrc> +#include <tools/json_writer.hxx> + +constexpr OUString TMP_STR_BEGIN = u"["_ustr; +constexpr OUString TMP_STR_END = u"]"_ustr; + +#include <svx/drawitem.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xtable.hxx> +#include <svx/fillctrl.hxx> +#include <svx/itemwin.hxx> +#include <svx/xflclit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace { + +enum eFillStyle +{ + NONE, + SOLID, + GRADIENT, + HATCH, + BITMAP, + PATTERN +}; + +drawing::FillStyle toCssFillStyle( eFillStyle eXFS ) +{ + if (eXFS == PATTERN) + { + return drawing::FillStyle_BITMAP; + } + + return static_cast<drawing::FillStyle>(eXFS); +} + +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxFillToolBoxControl, XFillStyleItem ); + +SvxFillToolBoxControl::SvxFillToolBoxControl( + sal_uInt16 nSlotId, + ToolBoxItemId nId, + ToolBox& rTbx ) + : SfxToolBoxControl( nSlotId, nId, rTbx ) + , mxFillControl(nullptr) + , mpLbFillType(nullptr) + , mpToolBoxColor(nullptr) + , mpLbFillAttr(nullptr) + , mnLastXFS(-1) + , mnLastPosGradient(0) + , mnLastPosHatch(0) + , mnLastPosBitmap(0) + , mnLastPosPattern(0) +{ + addStatusListener( ".uno:FillColor"); + addStatusListener( ".uno:FillGradient"); + addStatusListener( ".uno:FillHatch"); + addStatusListener( ".uno:FillBitmap"); + addStatusListener( ".uno:ColorTableState"); + addStatusListener( ".uno:GradientListState"); + addStatusListener( ".uno:HatchListState"); + addStatusListener( ".uno:BitmapListState"); +} + +SvxFillToolBoxControl::~SvxFillToolBoxControl() +{ +} + +void SvxFillToolBoxControl::StateChangedAtToolBoxControl( + sal_uInt16 nSID, + SfxItemState eState, + const SfxPoolItem* pState) +{ + const bool bDisabled(SfxItemState::DISABLED == eState); + + switch(nSID) + { + case SID_ATTR_FILL_STYLE: + { + if(bDisabled) + { + mpLbFillType->set_sensitive(false); + mpLbFillType->set_active(-1); + mpLbFillAttr->show(); + mpLbFillAttr->set_sensitive(false); + mpLbFillAttr->set_active(-1); + mpToolBoxColor->hide(); + mnLastXFS = -1; + mpStyleItem.reset(); + } + + if(eState >= SfxItemState::DEFAULT) + { + const XFillStyleItem* pItem = dynamic_cast< const XFillStyleItem* >(pState); + + if(pItem) + { + mpStyleItem.reset(pItem->Clone()); + mpLbFillType->set_sensitive(true); + drawing::FillStyle eXFS = mpStyleItem->GetValue(); + mnLastXFS = sal::static_int_cast< sal_Int32 >(eXFS); + mpLbFillType->set_active(mnLastXFS); + + if(drawing::FillStyle_NONE == eXFS) + { + mpLbFillAttr->set_active(-1); + mpLbFillAttr->set_sensitive(false); + } + + Update(); + break; + } + } + + mpLbFillType->set_active(-1); + mpLbFillAttr->show(); + mpLbFillAttr->set_sensitive(false); + mpLbFillAttr->set_active(-1); + mpToolBoxColor->hide(); + mnLastXFS = -1; + mpStyleItem.reset(); + mxFillControl->Resize(); + break; + } + case SID_ATTR_FILL_COLOR: + { + if(SfxItemState::DEFAULT == eState) + { + mpColorItem.reset(pState ? static_cast<XFillColorItem*>(pState->Clone()) : nullptr); + } + + if(mpStyleItem && drawing::FillStyle_SOLID == mpStyleItem->GetValue()) + { + mpLbFillAttr->hide(); + mpToolBoxColor->show(); + mxFillControl->Resize(); + + Update(); + } + break; + } + case SID_ATTR_FILL_GRADIENT: + { + if(SfxItemState::DEFAULT == eState) + { + mpFillGradientItem.reset(pState ? static_cast<XFillGradientItem*>(pState->Clone()) : nullptr); + } + + if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue()) + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(SfxItemState::DEFAULT == eState) + { + mpLbFillAttr->set_sensitive(true); + Update(); + } + else if(SfxItemState::DISABLED == eState ) + { + mpLbFillAttr->set_sensitive(false); + mpLbFillAttr->set_active(-1); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + break; + } + case SID_ATTR_FILL_HATCH: + { + if(SfxItemState::DEFAULT == eState) + { + mpHatchItem.reset(pState ? static_cast<XFillHatchItem*>(pState->Clone()) : nullptr); + } + + if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue()) + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(SfxItemState::DEFAULT == eState) + { + mpLbFillAttr->set_sensitive(true); + Update(); + } + else if(SfxItemState::DISABLED == eState ) + { + mpLbFillAttr->set_sensitive(false); + mpLbFillAttr->set_active(-1); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + break; + } + case SID_ATTR_FILL_BITMAP: + { + if(SfxItemState::DEFAULT == eState) + { + mpBitmapItem.reset(pState ? static_cast<XFillBitmapItem*>(pState->Clone()) : nullptr); + } + + if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue()) + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(SfxItemState::DEFAULT == eState) + { + mpLbFillAttr->set_sensitive(true); + Update(); + } + else if(SfxItemState::DISABLED == eState ) + { + mpLbFillAttr->set_sensitive(false); + mpLbFillAttr->set_active(-1); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + break; + } + case SID_GRADIENT_LIST: + { + if(SfxItemState::DEFAULT == eState) + { + if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue()) + { + if(mpFillGradientItem) + { + const OUString aString( mpFillGradientItem->GetName() ); + mpLbFillAttr->clear(); + if (const SfxObjectShell* pSh = SfxObjectShell::Current()) + { + mpLbFillAttr->set_sensitive(true); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList()); + } + mpLbFillAttr->set_active_text(aString); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + } + break; + } + case SID_HATCH_LIST: + { + if(SfxItemState::DEFAULT == eState) + { + if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue()) + { + if(mpHatchItem) + { + const OUString aString( mpHatchItem->GetName() ); + mpLbFillAttr->clear(); + if (const SfxObjectShell* pSh = SfxObjectShell::Current()) + { + mpLbFillAttr->set_sensitive(true); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList()); + } + mpLbFillAttr->set_active_text(aString); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + } + break; + } + case SID_BITMAP_LIST: + { + if(SfxItemState::DEFAULT == eState) + { + if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue()) + { + if(mpBitmapItem) + { + const OUString aString( mpBitmapItem->GetName() ); + mpLbFillAttr->clear(); + if (const SfxObjectShell* pSh = SfxObjectShell::Current()) + { + mpLbFillAttr->set_sensitive(true); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList()); + } + mpLbFillAttr->set_active_text(aString); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + } + break; + } + } +} + +void SvxFillToolBoxControl::Update() +{ + if(!mpStyleItem) + return; + + const drawing::FillStyle eXFS = mpStyleItem->GetValue(); + SfxObjectShell* pSh = SfxObjectShell::Current(); + + switch( eXFS ) + { + case drawing::FillStyle_NONE: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + break; + } + case drawing::FillStyle_SOLID: + { + if(mpColorItem) + { + mpLbFillAttr->hide(); + mpToolBoxColor->show(); + mxFillControl->Resize(); + } + break; + } + case drawing::FillStyle_GRADIENT: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(pSh && pSh->GetItem(SID_GRADIENT_LIST)) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList()); + + if(mpFillGradientItem) + { + const OUString aString(mpFillGradientItem->GetName()); + + mpLbFillAttr->set_active_text(aString); + + // Check if the entry is not in the list + if (mpLbFillAttr->get_active_text() != aString) + { + sal_Int32 nCount = mpLbFillAttr->get_count(); + OUString aTmpStr; + if( nCount > 0 ) + { + // Last entry gets tested against temporary entry + aTmpStr = mpLbFillAttr->get_text( nCount - 1 ); + if( aTmpStr.startsWith(TMP_STR_BEGIN) && + aTmpStr.endsWith(TMP_STR_END) ) + { + mpLbFillAttr->remove(nCount - 1); + } + } + aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END; + + rtl::Reference<XGradientList> xGradientList = new XGradientList( "", ""/*TODO?*/ ); + xGradientList->Insert(std::make_unique<XGradientEntry>(mpFillGradientItem->GetGradientValue(), aTmpStr)); + xGradientList->SetDirty( false ); + const BitmapEx aBmp = xGradientList->GetUiBitmap( 0 ); + + if (!aBmp.IsEmpty()) + { + ScopedVclPtrInstance< VirtualDevice > pVD; + const Size aBmpSize(aBmp.GetSizePixel()); + pVD->SetOutputSizePixel(aBmpSize, false); + pVD->DrawBitmapEx(Point(), aBmp); + mpLbFillAttr->append("", xGradientList->Get(0)->GetName(), *pVD); + mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1); + } + } + + } + else + { + mpLbFillAttr->set_active(-1); + } + } + else + { + mpLbFillAttr->set_active(-1); + } + break; + } + case drawing::FillStyle_HATCH: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(pSh && pSh->GetItem(SID_HATCH_LIST)) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList()); + + if(mpHatchItem) + { + const OUString aString(mpHatchItem->GetName()); + + mpLbFillAttr->set_active_text( aString ); + + // Check if the entry is not in the list + if( mpLbFillAttr->get_active_text() != aString ) + { + const sal_Int32 nCount = mpLbFillAttr->get_count(); + OUString aTmpStr; + if( nCount > 0 ) + { + // Last entry gets tested against temporary entry + aTmpStr = mpLbFillAttr->get_text( nCount - 1 ); + if( aTmpStr.startsWith(TMP_STR_BEGIN) && + aTmpStr.endsWith(TMP_STR_END) ) + { + mpLbFillAttr->remove( nCount - 1 ); + } + } + aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END; + + rtl::Reference<XHatchList> xHatchList = new XHatchList( "", ""/*TODO?*/ ); + xHatchList->Insert(std::make_unique<XHatchEntry>(mpHatchItem->GetHatchValue(), aTmpStr)); + xHatchList->SetDirty( false ); + const BitmapEx & aBmp = xHatchList->GetUiBitmap( 0 ); + + if( !aBmp.IsEmpty() ) + { + ScopedVclPtrInstance< VirtualDevice > pVD; + const Size aBmpSize(aBmp.GetSizePixel()); + pVD->SetOutputSizePixel(aBmpSize, false); + pVD->DrawBitmapEx(Point(), aBmp); + mpLbFillAttr->append("", xHatchList->GetHatch(0)->GetName(), *pVD); + mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1); + } + } + } + else + { + mpLbFillAttr->set_active(-1); + } + } + else + { + mpLbFillAttr->set_active(-1); + } + break; + } + case drawing::FillStyle_BITMAP: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mxFillControl->Resize(); + + if(pSh) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + + if(mpBitmapItem && !mpBitmapItem->isPattern() && pSh->GetItem(SID_BITMAP_LIST)) + { + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList()); + + const OUString aString(mpBitmapItem->GetName()); + + mpLbFillAttr->set_active_text(aString); + + // Check if the entry is not in the list + if (mpLbFillAttr->get_active_text() != aString) + { + sal_Int32 nCount = mpLbFillAttr->get_count(); + OUString aTmpStr; + if( nCount > 0 ) + { + // Last entry gets tested against temporary entry + aTmpStr = mpLbFillAttr->get_text(nCount - 1); + if( aTmpStr.startsWith(TMP_STR_BEGIN) && + aTmpStr.endsWith(TMP_STR_END) ) + { + mpLbFillAttr->remove(nCount - 1); + } + } + aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END; + + XBitmapListRef xBitmapList = + XPropertyList::AsBitmapList( + XPropertyList::CreatePropertyList( + XPropertyListType::Bitmap, "TmpList", ""/*TODO?*/)); + xBitmapList->Insert(std::make_unique<XBitmapEntry>(mpBitmapItem->GetGraphicObject(), aTmpStr)); + xBitmapList->SetDirty( false ); + SvxFillAttrBox::Fill(*mpLbFillAttr, xBitmapList); + mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1); + } + + } + else if (mpBitmapItem && mpBitmapItem->isPattern() && pSh->GetItem(SID_PATTERN_LIST)) + { + mnLastXFS = sal::static_int_cast<sal_Int32>(PATTERN); + mpLbFillType->set_active(mnLastXFS); + + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList()); + const OUString aString(mpBitmapItem->GetName()); + + mpLbFillAttr->set_active_text(aString); + } + else + { + mpLbFillAttr->set_active(-1); + } + } + else + { + mpLbFillAttr->set_active(-1); + } + break; + } + default: + OSL_ENSURE(false, "Non supported FillType (!)"); + break; + } + +} + +VclPtr<InterimItemWindow> SvxFillToolBoxControl::CreateItemWindow(vcl::Window *pParent) +{ + if(GetSlotId() == SID_ATTR_FILL_STYLE) + { + mxFillControl.reset(VclPtr<FillControl>::Create(pParent, m_xFrame)); + + mpLbFillType = mxFillControl->mxLbFillType.get(); + mpLbFillAttr = mxFillControl->mxLbFillAttr.get(); + mpToolBoxColor = mxFillControl->mxToolBoxColor.get(); + + mpLbFillType->connect_changed(LINK(this,SvxFillToolBoxControl,SelectFillTypeHdl)); + mpLbFillAttr->connect_changed(LINK(this,SvxFillToolBoxControl,SelectFillAttrHdl)); + + + return mxFillControl; + } + return VclPtr<InterimItemWindow>(); +} + +FillControl::FillControl(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame) + : InterimItemWindow(pParent, "svx/ui/fillctrlbox.ui", "FillCtrlBox") + , mxLbFillType(m_xBuilder->weld_combo_box("type")) + , mxToolBoxColor(m_xBuilder->weld_toolbar("color")) + , mxColorDispatch(new ToolbarUnoDispatcher(*mxToolBoxColor, *m_xBuilder, rFrame)) + , mxLbFillAttr(m_xBuilder->weld_combo_box("attr")) + , mnTypeCurPos(0) + , mnAttrCurPos(0) +{ + InitControlBase(mxLbFillType.get()); + + mxLbFillAttr->connect_key_press(LINK(this, FillControl, AttrKeyInputHdl)); + mxLbFillType->connect_key_press(LINK(this, FillControl, TypeKeyInputHdl)); + mxToolBoxColor->connect_key_press(LINK(this, FillControl, ColorKeyInputHdl)); + + mxLbFillType->connect_get_property_tree(LINK(this, FillControl, DumpAsPropertyTreeHdl)); + + mxLbFillType->connect_focus_in(LINK(this, FillControl, TypeFocusHdl)); + mxLbFillAttr->connect_focus_in(LINK(this, FillControl, AttrFocusHdl)); + + SvxFillTypeBox::Fill(*mxLbFillType); + + SetOptimalSize(); +} + +IMPL_STATIC_LINK(FillControl, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void) +{ + rJsonWriter.put("command", ".uno:FillStyle"); +} + +void FillControl::ReleaseFocus_Impl() +{ + SfxViewShell* pCurSh = SfxViewShell::Current(); + if (pCurSh) + { + vcl::Window* pShellWnd = pCurSh->GetWindow(); + if (pShellWnd) + pShellWnd->GrabFocus(); + } +} + +IMPL_LINK(FillControl, TypeKeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); + sal_uInt16 nCode = rKeyCode.GetCode(); + + if (nCode == KEY_ESCAPE) + { + mxLbFillType->set_active(mnTypeCurPos); + ReleaseFocus_Impl(); + return true; + } + + if (nCode != KEY_TAB) + return false; + if (rKeyCode.IsShift()) + return ChildKeyInput(rKEvt); + if (mxLbFillAttr->get_visible() && !mxLbFillAttr->get_sensitive()) + return ChildKeyInput(rKEvt); + return false; +} + +IMPL_LINK_NOARG(FillControl, TypeFocusHdl, weld::Widget&, void) +{ + mnTypeCurPos = mxLbFillType->get_active(); +} + +IMPL_LINK_NOARG(FillControl, AttrFocusHdl, weld::Widget&, void) +{ + mnAttrCurPos = mxLbFillAttr->get_active(); +} + +IMPL_LINK(FillControl, AttrKeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); + sal_uInt16 nCode = rKeyCode.GetCode(); + + if (nCode == KEY_ESCAPE) + { + mxLbFillAttr->set_active(mnAttrCurPos); + ReleaseFocus_Impl(); + return true; + } + + return ChildKeyInput(rKEvt); +} + +IMPL_LINK(FillControl, ColorKeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return ChildKeyInput(rKEvt); +} + +FillControl::~FillControl() +{ + disposeOnce(); +} + +void FillControl::dispose() +{ + mxLbFillAttr.reset(); + mxColorDispatch.reset(); + mxToolBoxColor.reset(); + mxLbFillType.reset(); + InterimItemWindow::dispose(); +} + +IMPL_LINK_NOARG(SvxFillToolBoxControl, SelectFillTypeHdl, weld::ComboBox&, void) +{ + sal_Int32 nXFS = mpLbFillType->get_active(); + + if(mnLastXFS == nXFS) + return; + + eFillStyle eXFS = static_cast<eFillStyle>(nXFS); + mpLbFillAttr->clear(); + SfxObjectShell* pSh = SfxObjectShell::Current(); + const XFillStyleItem aXFillStyleItem(toCssFillStyle(eXFS)); + + // #i122676# Do no longer trigger two Execute calls, one for SID_ATTR_FILL_STYLE + // and one for setting the fill attribute itself, but add two SfxPoolItems to the + // call to get just one action at the SdrObject and to create only one Undo action, too. + // Checked that this works in all apps. + switch( eXFS ) + { + default: + case NONE: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + mpLbFillAttr->set_sensitive(false); + if (pSh) + { + // #i122676# need to call a single SID_ATTR_FILL_STYLE change + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_STYLE, SfxCallMode::RECORD, + { &aXFillStyleItem }); + } + break; + } + case SOLID: + { + mpLbFillAttr->hide(); + mpToolBoxColor->show(); + if (pSh) + { + const ::Color aColor = mpColorItem ? mpColorItem->GetColorValue() : COL_AUTO; + const XFillColorItem aXFillColorItem( "", aColor ); + + // #i122676# change FillStyle and Color in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_COLOR, SfxCallMode::RECORD, + { &aXFillColorItem, &aXFillStyleItem }); + } + break; + } + case GRADIENT: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + + if(pSh && pSh->GetItem(SID_GRADIENT_LIST)) + { + if(!mpLbFillAttr->get_count()) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList()); + } + + if (mnLastPosGradient != -1) + { + const SvxGradientListItem * pItem = pSh->GetItem(SID_GRADIENT_LIST); + + if(mnLastPosGradient < pItem->GetGradientList()->Count()) + { + const basegfx::BGradient aGradient = pItem->GetGradientList()->GetGradient(mnLastPosGradient)->GetGradient(); + const XFillGradientItem aXFillGradientItem(mpLbFillAttr->get_text(mnLastPosGradient), aGradient); + + // #i122676# change FillStyle and Gradient in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_GRADIENT, SfxCallMode::RECORD, + { &aXFillGradientItem, &aXFillStyleItem }); + mpLbFillAttr->set_active(mnLastPosGradient); + } + } + } + else + { + mpLbFillAttr->set_sensitive(false); + } + break; + } + case HATCH: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + + if(pSh && pSh->GetItem(SID_HATCH_LIST)) + { + if(!mpLbFillAttr->get_count()) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList()); + } + + if (mnLastPosHatch != -1) + { + const SvxHatchListItem * pItem = pSh->GetItem(SID_HATCH_LIST); + + if(mnLastPosHatch < pItem->GetHatchList()->Count()) + { + const XHatch aHatch = pItem->GetHatchList()->GetHatch(mnLastPosHatch)->GetHatch(); + const XFillHatchItem aXFillHatchItem(mpLbFillAttr->get_active_text(), aHatch); + + // #i122676# change FillStyle and Hatch in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_HATCH, SfxCallMode::RECORD, + { &aXFillHatchItem, &aXFillStyleItem }); + mpLbFillAttr->set_active(mnLastPosHatch); + } + } + } + else + { + mpLbFillAttr->set_sensitive(false); + } + break; + } + case BITMAP: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + + if(pSh && pSh->GetItem(SID_BITMAP_LIST)) + { + if(!mpLbFillAttr->get_count()) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList()); + } + + if (mnLastPosBitmap != -1) + { + const SvxBitmapListItem * pItem = pSh->GetItem(SID_BITMAP_LIST); + + if(mnLastPosBitmap < pItem->GetBitmapList()->Count()) + { + const XBitmapEntry* pXBitmapEntry = pItem->GetBitmapList()->GetBitmap(mnLastPosBitmap); + const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject()); + + // #i122676# change FillStyle and Bitmap in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD, + { &aXFillBitmapItem, &aXFillStyleItem }); + mpLbFillAttr->set_active(mnLastPosBitmap); + } + } + } + else + { + mpLbFillAttr->set_sensitive(false); + } + break; + } + case PATTERN: + { + mpLbFillAttr->show(); + mpToolBoxColor->hide(); + + if(pSh && pSh->GetItem(SID_PATTERN_LIST)) + { + if(!mpLbFillAttr->get_count()) + { + mpLbFillAttr->set_sensitive(true); + mpLbFillAttr->clear(); + SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList()); + } + + if (mnLastPosPattern != -1) + { + const SvxPatternListItem * pItem = pSh->GetItem(SID_PATTERN_LIST); + + if(mnLastPosPattern < pItem->GetPatternList()->Count()) + { + const XBitmapEntry* pXBitmapEntry = pItem->GetPatternList()->GetBitmap(mnLastPosPattern); + const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject()); + + // #i122676# change FillStyle and Bitmap in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD, + { &aXFillBitmapItem, &aXFillStyleItem }); + mpLbFillAttr->set_active(mnLastPosPattern); + } + } + } + else + { + mpLbFillAttr->set_sensitive(false); + } + break; + } + + } + + mnLastXFS = nXFS; + + mxFillControl->Resize(); +} + +IMPL_LINK_NOARG(SvxFillToolBoxControl, SelectFillAttrHdl, weld::ComboBox&, void) +{ + sal_Int32 nXFS = mpLbFillType->get_active(); + eFillStyle eXFS = static_cast<eFillStyle>(nXFS); + + const XFillStyleItem aXFillStyleItem(toCssFillStyle(eXFS)); + SfxObjectShell* pSh = SfxObjectShell::Current(); + + // #i122676# dependent from bFillStyleChange, do execute a single or two + // changes in one Execute call + const bool bFillStyleChange(mnLastXFS != nXFS); + + switch (eXFS) + { + case SOLID: + { + if (bFillStyleChange && pSh) + { + // #i122676# Single FillStyle change call needed here + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_STYLE, SfxCallMode::RECORD, + { &aXFillStyleItem }); + } + break; + } + case GRADIENT: + { + sal_Int32 nPos = mpLbFillAttr->get_active(); + + if (nPos == -1) + { + nPos = mnLastPosGradient; + } + + if (nPos != -1 && pSh && pSh->GetItem(SID_GRADIENT_LIST)) + { + const SvxGradientListItem * pItem = pSh->GetItem(SID_GRADIENT_LIST); + + if(nPos < pItem->GetGradientList()->Count()) + { + const basegfx::BGradient aGradient = pItem->GetGradientList()->GetGradient(nPos)->GetGradient(); + const XFillGradientItem aXFillGradientItem(mpLbFillAttr->get_active_text(), aGradient); + + // #i122676# Change FillStyle and Gradient in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_GRADIENT, SfxCallMode::RECORD, + bFillStyleChange + ? std::initializer_list<SfxPoolItem const*>{ &aXFillGradientItem, &aXFillStyleItem } + : std::initializer_list<SfxPoolItem const*>{ &aXFillGradientItem }); + } + } + + if (nPos != -1) + { + mnLastPosGradient = nPos; + } + break; + } + case HATCH: + { + sal_Int32 nPos = mpLbFillAttr->get_active(); + + if (nPos == -1) + { + nPos = mnLastPosHatch; + } + + if (nPos != -1 && pSh && pSh->GetItem(SID_HATCH_LIST)) + { + const SvxHatchListItem * pItem = pSh->GetItem(SID_HATCH_LIST); + + if(nPos < pItem->GetHatchList()->Count()) + { + const XHatch aHatch = pItem->GetHatchList()->GetHatch(nPos)->GetHatch(); + const XFillHatchItem aXFillHatchItem( mpLbFillAttr->get_active_text(), aHatch); + + // #i122676# Change FillStyle and Hatch in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_HATCH, SfxCallMode::RECORD, + bFillStyleChange + ? std::initializer_list<SfxPoolItem const*>{ &aXFillHatchItem, &aXFillStyleItem } + : std::initializer_list<SfxPoolItem const*>{ &aXFillHatchItem }); + } + } + + if (nPos != -1) + { + mnLastPosHatch = nPos; + } + break; + } + case BITMAP: + { + sal_Int32 nPos = mpLbFillAttr->get_active(); + + if (nPos == -1) + { + nPos = mnLastPosBitmap; + } + + if (nPos != -1 && pSh && pSh->GetItem(SID_BITMAP_LIST)) + { + const SvxBitmapListItem * pItem = pSh->GetItem(SID_BITMAP_LIST); + + if(nPos < pItem->GetBitmapList()->Count()) + { + const XBitmapEntry* pXBitmapEntry = pItem->GetBitmapList()->GetBitmap(nPos); + const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject()); + + // #i122676# Change FillStyle and Bitmap in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD, + bFillStyleChange + ? std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem, &aXFillStyleItem } + : std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem }); + } + } + + if (nPos != -1) + { + mnLastPosBitmap = nPos; + } + break; + } + case PATTERN: + { + sal_Int32 nPos = mpLbFillAttr->get_active(); + + if (nPos == -1) + { + nPos = mnLastPosPattern; + } + + if (nPos != -1 && pSh && pSh->GetItem(SID_PATTERN_LIST)) + { + const SvxPatternListItem * pItem = pSh->GetItem(SID_PATTERN_LIST); + + if(nPos < pItem->GetPatternList()->Count()) + { + const XBitmapEntry* pXBitmapEntry = pItem->GetPatternList()->GetBitmap(nPos); + const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject()); + + // #i122676# Change FillStyle and Bitmap in one call + pSh->GetDispatcher()->ExecuteList( + SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD, + bFillStyleChange + ? std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem, &aXFillStyleItem } + : std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem }); + } + } + + if (nPos != -1) + { + mnLastPosPattern = nPos; + } + break; + } + + default: break; + } +} + +void FillControl::SetOptimalSize() +{ + Size aSize(mxLbFillType->get_preferred_size()); + Size aFirstSize(mxToolBoxColor->get_preferred_size()); + auto nWidth = std::max(aFirstSize.Width(), LogicToPixel(Size(55, 0), MapMode(MapUnit::MapAppFont)).Width()); + auto nHeight = std::max(aSize.Height(), aFirstSize.Height()); + mxToolBoxColor->set_size_request(nWidth, -1); + mxLbFillAttr->set_size_request(42, -1); //something narrow so the toolbar sets the overall size of this column + SetSizePixel(Size(m_xContainer->get_preferred_size().Width(), nHeight)); +} + +void FillControl::DataChanged(const DataChangedEvent& rDCEvt) +{ + if((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) + { + SetOptimalSize(); + } + InterimItemWindow::DataChanged(rDCEvt); +} + +void FillControl::GetFocus() +{ + // tdf#148047 if the dropdown is active then leave the focus + // there and don't grab back to a different widget + if (mxToolBoxColor->get_menu_item_active(".uno:FillColor")) + return; + InterimItemWindow::GetFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/fontworkgallery.cxx b/svx/source/tbxctrls/fontworkgallery.cxx new file mode 100644 index 0000000000..8b995ce9d4 --- /dev/null +++ b/svx/source/tbxctrls/fontworkgallery.cxx @@ -0,0 +1,807 @@ +/* -*- 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/text/WritingMode.hpp> + +#include <comphelper/lok.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> + +#include <sfx2/viewsh.hxx> + +#include <svl/itempool.hxx> + +#include <svtools/toolbarmenu.hxx> +#include <svtools/popupwindowcontroller.hxx> + +#include <svx/fmmodel.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdview.hxx> + +#include <svx/gallery.hxx> +#include <svx/fontworkgallery.hxx> + +#include <tools/UnitConversion.hxx> + +#include <algorithm> +#include <memory> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +namespace svx +{ + +FontWorkGalleryDialog::FontWorkGalleryDialog(weld::Window* pParent, SdrView& rSdrView) + : GenericDialogController(pParent, "svx/ui/fontworkgallerydialog.ui", "FontworkGalleryDialog") + , mnThemeId(0xffff) + , mrSdrView(rSdrView) + , mbInsertIntoPage(true) + , mpDestModel(nullptr) + , maCtlFavorites(m_xBuilder->weld_icon_view("ctlFavoriteswin")) + , mxOKButton(m_xBuilder->weld_button("ok")) +{ + Size aSize(530, 400); + maCtlFavorites->set_size_request(aSize.Width(), aSize.Height()); + + maCtlFavorites->connect_item_activated( LINK( this, FontWorkGalleryDialog, DoubleClickFavoriteHdl ) ); + maCtlFavorites->connect_query_tooltip(LINK(this, FontWorkGalleryDialog, QueryTooltipHandler)); + mxOKButton->connect_clicked(LINK(this, FontWorkGalleryDialog, ClickOKHdl)); + + initFavorites( GALLERY_THEME_FONTWORK ); + fillFavorites( GALLERY_THEME_FONTWORK ); +} + +FontWorkGalleryDialog::~FontWorkGalleryDialog() +{ +} + +void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId) +{ + // the favorites are read via the gallery + sal_uInt32 nFavCount = GalleryExplorer::GetSdrObjCount( nThemeId ); + + // lock gallery theme + GalleryExplorer::BeginLocking(nThemeId); + + sal_uInt32 nModelPos; + FmFormModel *pModel = nullptr; + + for( nModelPos = 0; nModelPos < nFavCount; nModelPos++ ) + { + BitmapEx aThumb; + + if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty()) + { + VclPtr< VirtualDevice > pVDev = VclPtr<VirtualDevice>::Create(); + const Point aNull(0, 0); + + if (pVDev->GetDPIScaleFactor() > 1) + aThumb.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); + + const Size aSize(aThumb.GetSizePixel()); + + pVDev->SetOutputSizePixel(aSize); + + static const sal_uInt32 nLen(8); + static const Color aW(COL_WHITE); + static const Color aG(0xef, 0xef, 0xef); + + pVDev->DrawCheckered(aNull, aSize, nLen, aW, aG); + + pVDev->DrawBitmapEx(aNull, aThumb); + maFavoritesHorizontal.emplace_back(pVDev); + } + } + + // release gallery theme + GalleryExplorer::EndLocking(nThemeId); +} + +void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId) +{ + mnThemeId = nThemeId; + + auto nFavCount = maFavoritesHorizontal.size(); + + maCtlFavorites->clear(); + maIdToTitleMap.clear(); + + std::vector<OUString> aTitles; + (void)GalleryExplorer::FillObjListTitle(nThemeId, aTitles); + assert(aTitles.size() == nFavCount); + + for( size_t nFavorite = 1; nFavorite <= nFavCount; nFavorite++ ) + { + OUString sId = OUString::number(static_cast<sal_uInt16>(nFavorite)); + maIdToTitleMap.emplace(sId, aTitles.at(nFavorite - 1)); + maCtlFavorites->insert(-1, nullptr, &sId, maFavoritesHorizontal[nFavorite - 1], nullptr); + } + + if (maCtlFavorites->n_children()) + maCtlFavorites->select(0); +} + +void FontWorkGalleryDialog::SetSdrObjectRef( SdrModel* pModel) +{ + mbInsertIntoPage = false; + mpDestModel = pModel; +} + +void FontWorkGalleryDialog::insertSelectedFontwork() +{ + OUString sItemId = maCtlFavorites->get_selected_id(); + if (sItemId.isEmpty()) + return; + + sal_Int32 nItemId = sItemId.toInt32(); + + if (nItemId == 0) + return; + + FmFormModel aModel; + aModel.GetItemPool().FreezeIdRanges(); + + if( !GalleryExplorer::GetSdrObj( mnThemeId, nItemId-1, &aModel ) ) + return; + + SdrPage* pPage = aModel.GetPage(0); + if( !(pPage && pPage->GetObjCount()) ) + return; + + // tdf#116993 Calc uses a 'special' mode for this dialog in being the + // only caller of ::SetSdrObjectRef. Only in that case mpDestModel seems + // to be the correct target SdrModel. + // If this is not used, the correct SdrModel seems to be the one from + // the mrSdrView that is used to insert (InsertObjectAtView below) the + // cloned SdrObject. + const bool bUseSpecialCalcMode(!mbInsertIntoPage && nullptr != mpDestModel); + + // center shape on current view + OutputDevice* pOutDev(mrSdrView.GetFirstOutputDevice()); + + if (!pOutDev) + return; + + // Clone directly to target SdrModel (may be different due to user/caller (!)) + rtl::Reference<SdrObject> pNewObject( + pPage->GetObj(0)->CloneSdrObject( + bUseSpecialCalcMode ? *mpDestModel : mrSdrView.getSdrModelFromSdrView())); + + pNewObject->MakeNameUnique(); + + // tdf#117629 + // Since the 'old' ::CloneSdrObject also copies the SdrPage* the + // SdrObject::getUnoShape() *will* create the wrong UNO API object + // early. This IS one of the reasons I do change these things - this + // error does not happen with my next change I am working on already + // ARGH! For now, reset the SdrPage* to nullptr. + // What sense does it have to copy the SdrPage* of the original SdrObject ?!? + // TTTT: This also *might* be the hidden reason for the strange code at the + // end of SdrObject::SetPage that tries to delete the SvxShape under some + // circumstances... + // pNewObject->SetPage(nullptr); + + tools::Rectangle aObjRect( pNewObject->GetLogicRect() ); + Point aPagePos; + Size aFontworkSize = aObjRect.GetSize(); + + if (comphelper::LibreOfficeKit::isActive()) + { + SfxViewShell* pViewShell = SfxViewShell::Current(); + + aPagePos = pViewShell->getLOKVisibleArea().Center(); + + aPagePos.setX(convertTwipToMm100(aPagePos.X())); + aPagePos.setY(convertTwipToMm100(aPagePos.Y())); + + sal_Int32 nLOKViewWidth = 0.8 * convertTwipToMm100(pViewShell->getLOKVisibleArea().getOpenWidth()); + if (aFontworkSize.getWidth() > nLOKViewWidth) + { + double fScale = static_cast<double>(aFontworkSize.getWidth()) / nLOKViewWidth; + aFontworkSize.setWidth(aFontworkSize.getWidth() / fScale); + aFontworkSize.setHeight(aFontworkSize.getHeight() / fScale); + } + } + else + { + Size aSize = pOutDev->GetOutputSizePixel(); + tools::Rectangle aPixelVisRect(Point(0,0), aSize); + tools::Rectangle aVisArea = pOutDev->PixelToLogic(aPixelVisRect); + + aPagePos = aVisArea.Center(); + } + + if (aPagePos.getX() > aFontworkSize.getWidth() / 2) + aPagePos.AdjustX( -(aFontworkSize.getWidth() / 2) ); + if (aPagePos.getY() > aFontworkSize.getHeight() / 2) + aPagePos.AdjustY( -(aFontworkSize.getHeight() / 2) ); + + tools::Rectangle aNewObjectRectangle(aPagePos, aFontworkSize); + pNewObject->SetLogicRect(aNewObjectRectangle); + + if (bUseSpecialCalcMode) + { + mxSdrObject = pNewObject; + } + else + { + SdrPageView* pPV(mrSdrView.GetSdrPageView()); + + if (nullptr != pPV) + { + mrSdrView.InsertObjectAtView( pNewObject.get(), *pPV ); + } + } +} + +IMPL_LINK_NOARG(FontWorkGalleryDialog, ClickOKHdl, weld::Button&, void) +{ + insertSelectedFontwork(); + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(FontWorkGalleryDialog, DoubleClickFavoriteHdl, weld::IconView&, bool) +{ + insertSelectedFontwork(); + m_xDialog->response(RET_OK); + return true; +} + +IMPL_LINK(FontWorkGalleryDialog, QueryTooltipHandler, const weld::TreeIter&, iter, OUString) +{ + const OUString id = maCtlFavorites->get_id(iter); + auto it = maIdToTitleMap.find(id); + return it != maIdToTitleMap.end() ? it->second : OUString(); +} + +namespace { + +class FontworkAlignmentWindow final : public WeldToolbarPopup +{ +public: + FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override + { + mxLeft->grab_focus(); + } + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; + +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<weld::RadioButton> mxLeft; + std::unique_ptr<weld::RadioButton> mxCenter; + std::unique_ptr<weld::RadioButton> mxRight; + std::unique_ptr<weld::RadioButton> mxStretch; + bool mbSettingValue; + + DECL_LINK( SelectHdl, weld::Toggleable&, void ); + + void implSetAlignment( int nAlignmentMode, bool bEnabled ); +}; + +} + +constexpr OUString gsFontworkAlignment(u".uno:FontworkAlignment"_ustr); + +FontworkAlignmentWindow::FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/fontworkalignmentcontrol.ui", "FontworkAlignmentControl") + , mxControl(pControl) + , mxLeft(m_xBuilder->weld_radio_button("left")) + , mxCenter(m_xBuilder->weld_radio_button("center")) + , mxRight(m_xBuilder->weld_radio_button("right")) + , mxStretch(m_xBuilder->weld_radio_button("stretch")) + , mbSettingValue(false) +{ + mxLeft->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl)); + mxCenter->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl)); + mxRight->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl)); + mxStretch->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl)); + + AddStatusListener( gsFontworkAlignment ); +} + +void FontworkAlignmentWindow::implSetAlignment( int nSurface, bool bEnabled ) +{ + bool bSettingValue = mbSettingValue; + mbSettingValue = true; + mxLeft->set_active(nSurface == 0 && bEnabled); + mxLeft->set_sensitive(bEnabled); + mxCenter->set_active(nSurface == 1 && bEnabled); + mxCenter->set_sensitive(bEnabled); + mxRight->set_active(nSurface == 2 && bEnabled); + mxRight->set_sensitive(bEnabled); + //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented + //mxWord->set_active(nSurface == 3 && bEnabled); + //mxWord->set_sensitive(bEnabled); + mxStretch->set_active(nSurface == 4 && bEnabled); + mxStretch->set_sensitive(bEnabled); + mbSettingValue = bSettingValue; +} + +void FontworkAlignmentWindow::statusChanged( const css::frame::FeatureStateEvent& Event ) +{ + if( Event.FeatureURL.Main != gsFontworkAlignment ) + return; + + if( !Event.IsEnabled ) + { + implSetAlignment( 0, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetAlignment( nValue, true ); + } +} + +IMPL_LINK(FontworkAlignmentWindow, SelectHdl, weld::Toggleable&, rButton, void) +{ + if (mbSettingValue || !rButton.get_active()) + return; + + sal_Int32 nAlignment; + if (mxLeft->get_active()) + nAlignment = 0; + else if (mxCenter->get_active()) + nAlignment = 1; + else if (mxRight->get_active()) + nAlignment = 2; + //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented + //else if (mxWord->get_active()) + // nAlignment = 3; + else + nAlignment = 4; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + gsFontworkAlignment.copy(5), nAlignment) }; + + mxControl->dispatchCommand( gsFontworkAlignment, aArgs ); + + implSetAlignment( nAlignment, true ); + + mxControl->EndPopupMode(); +} + +namespace { + +class FontworkAlignmentControl : public svt::PopupWindowController +{ +public: + explicit FontworkAlignmentControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +FontworkAlignmentControl::FontworkAlignmentControl( const Reference< XComponentContext >& rxContext ) +: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), ".uno:FontworkAlignment" ) +{ +} + +std::unique_ptr<WeldToolbarPopup> FontworkAlignmentControl::weldPopupWindow() +{ + return std::make_unique<FontworkAlignmentWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> FontworkAlignmentControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<FontworkAlignmentWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL FontworkAlignmentControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString FontworkAlignmentControl::getImplementationName() +{ + return "com.sun.star.comp.svx.FontworkAlignmentController"; +} + + +Sequence< OUString > FontworkAlignmentControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_FontworkAlignmentControl_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FontworkAlignmentControl(xContext)); +} + +namespace { + +class FontworkCharacterSpacingWindow final : public WeldToolbarPopup +{ +public: + FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow); + virtual void GrabFocus() override; + + virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override; +private: + rtl::Reference<svt::PopupWindowController> mxControl; + std::unique_ptr<weld::RadioButton> mxVeryTight; + std::unique_ptr<weld::RadioButton> mxTight; + std::unique_ptr<weld::RadioButton> mxNormal; + std::unique_ptr<weld::RadioButton> mxLoose; + std::unique_ptr<weld::RadioButton> mxVeryLoose; + std::unique_ptr<weld::RadioButton> mxCustom; + std::unique_ptr<weld::CheckButton> mxKernPairs; + sal_Int32 mnCharacterSpacing; + bool mbSettingValue; + bool mbCommandDispatched; + + DECL_LINK( KernSelectHdl, weld::Toggleable&, void ); + DECL_LINK( SelectHdl, weld::Toggleable&, void ); + DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool ); + + void implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled ); + void implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled); + void DispatchSpacingDialog(); +}; + +} + +constexpr OUString gsFontworkCharacterSpacing(u".uno:FontworkCharacterSpacing"_ustr); +constexpr OUString gsFontworkKernCharacterPairs(u".uno:FontworkKernCharacterPairs"_ustr); + +FontworkCharacterSpacingWindow::FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/fontworkcharacterspacingcontrol.ui", "FontworkCharacterSpacingControl") + , mxControl(pControl) + , mxVeryTight(m_xBuilder->weld_radio_button("verytight")) + , mxTight(m_xBuilder->weld_radio_button("tight")) + , mxNormal(m_xBuilder->weld_radio_button("normal")) + , mxLoose(m_xBuilder->weld_radio_button("loose")) + , mxVeryLoose(m_xBuilder->weld_radio_button("veryloose")) + , mxCustom(m_xBuilder->weld_radio_button("custom")) + , mxKernPairs(m_xBuilder->weld_check_button("kernpairs")) + , mnCharacterSpacing(0) + , mbSettingValue(false) + , mbCommandDispatched(false) +{ + mxVeryTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxNormal->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxVeryLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxCustom->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl)); + mxCustom->connect_mouse_release(LINK(this, FontworkCharacterSpacingWindow, MouseReleaseHdl)); + + mxKernPairs->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, KernSelectHdl)); + + AddStatusListener( gsFontworkCharacterSpacing ); + AddStatusListener( gsFontworkKernCharacterPairs ); + + // See TODO in svx/source/toolbars/fontworkbar.cxx for SID_FONTWORK_KERN_CHARACTER_PAIRS, + // the kernpairs setting is ignored, so hide the widget entirely + mxKernPairs->hide(); +} + +void FontworkCharacterSpacingWindow::GrabFocus() +{ + mxVeryTight->grab_focus(); +} + +void FontworkCharacterSpacingWindow::implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled ) +{ + bool bSettingValue = mbSettingValue; + mbSettingValue = true; + + mxVeryTight->set_sensitive(bEnabled); + mxTight->set_sensitive(bEnabled); + mxNormal->set_sensitive(bEnabled); + mxLoose->set_sensitive(bEnabled); + mxVeryLoose->set_sensitive(bEnabled); + mxCustom->set_sensitive(bEnabled); + + mxVeryTight->set_active(false); + mxTight->set_active(false); + mxNormal->set_active(false); + mxLoose->set_active(false); + mxVeryLoose->set_active(false); + mxCustom->set_active(true); + + switch(nCharacterSpacing) + { + case 80: + mxVeryTight->set_active(true); + break; + case 90: + mxTight->set_active(true); + break; + case 100: + mxNormal->set_active(true); + break; + case 120: + mxLoose->set_active(true); + break; + case 150: + mxVeryLoose->set_active(true); + break; + } + + mnCharacterSpacing = nCharacterSpacing; + + mbSettingValue = bSettingValue; +} + +void FontworkCharacterSpacingWindow::implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled) +{ + mxKernPairs->set_sensitive(bEnabled); + mxKernPairs->set_active(bKernOnOff); +} + +void FontworkCharacterSpacingWindow::statusChanged( const css::frame::FeatureStateEvent& Event ) +{ + if( Event.FeatureURL.Main == gsFontworkCharacterSpacing ) + { + if( !Event.IsEnabled ) + { + implSetCharacterSpacing( 0, false ); + } + else + { + sal_Int32 nValue = 0; + if( Event.State >>= nValue ) + implSetCharacterSpacing( nValue, true ); + } + } + else if( Event.FeatureURL.Main == gsFontworkKernCharacterPairs ) + { + if( !Event.IsEnabled ) + { + implSetKernCharacterPairs(false, false); + } + else + { + bool bValue = false; + if( Event.State >>= bValue ) + implSetKernCharacterPairs(bValue, true); + } + } +} + +IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, KernSelectHdl, weld::Toggleable&, void) +{ + if (mbSettingValue) + return; + + bool bKernOnOff = mxKernPairs->get_active(); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + gsFontworkKernCharacterPairs.copy(5), bKernOnOff) }; + + mxControl->dispatchCommand( gsFontworkKernCharacterPairs, aArgs ); + mbCommandDispatched = true; + + implSetKernCharacterPairs(bKernOnOff, true); + + mxControl->EndPopupMode(); +} + +void FontworkCharacterSpacingWindow::DispatchSpacingDialog() +{ + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + gsFontworkCharacterSpacing.copy(5), mnCharacterSpacing) }; + + rtl::Reference<svt::PopupWindowController> xControl(mxControl); + xControl->EndPopupMode(); + xControl->dispatchCommand(".uno:FontworkCharacterSpacingDialog", aArgs); + mbCommandDispatched = true; +} + +IMPL_LINK(FontworkCharacterSpacingWindow, SelectHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + if (mbSettingValue) + return; + + // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee + // this toggle will happen before that mouse release though it does in + // practice for vcl and gtk + if (mbCommandDispatched) + return; + + if (mxCustom->get_active()) + DispatchSpacingDialog(); + else + { + sal_Int32 nCharacterSpacing; + if (mxVeryTight->get_active()) + nCharacterSpacing = 80; + else if (mxTight->get_active()) + nCharacterSpacing = 90; + else if (mxLoose->get_active()) + nCharacterSpacing = 120; + else if (mxVeryLoose->get_active()) + nCharacterSpacing = 150; + else + nCharacterSpacing = 100; + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue( + gsFontworkCharacterSpacing.copy(5), nCharacterSpacing) }; + + mxControl->dispatchCommand( gsFontworkCharacterSpacing, aArgs ); + mbCommandDispatched = true; + + implSetCharacterSpacing( nCharacterSpacing, true ); + } + + mxControl->EndPopupMode(); +} + +IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, MouseReleaseHdl, const MouseEvent&, bool) +{ + /* + tdf#145296 if the "custom" radiobutton was presented preselected as + toggled on and the user clicked on it then there's no toggled signal sent + because the item was already toggled on and didn't change state. + + So if that happens launch the custom spacing dialog explicitly here on + mouse release. + */ + if (mxCustom->get_active() && !mbCommandDispatched) + { + DispatchSpacingDialog(); + return true; + } + return false; +} + +namespace { + +class FontworkCharacterSpacingControl : public svt::PopupWindowController +{ +public: + explicit FontworkCharacterSpacingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +FontworkCharacterSpacingControl::FontworkCharacterSpacingControl( const Reference< XComponentContext >& rxContext ) +: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), ".uno:FontworkCharacterSpacingFloater" ) +{ +} + +std::unique_ptr<WeldToolbarPopup> FontworkCharacterSpacingControl::weldPopupWindow() +{ + return std::make_unique<FontworkCharacterSpacingWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> FontworkCharacterSpacingControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<FontworkCharacterSpacingWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +// XInitialization +void SAL_CALL FontworkCharacterSpacingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::PopupWindowController::initialize( aArguments ); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +// XServiceInfo + + +OUString FontworkCharacterSpacingControl::getImplementationName() +{ + return "com.sun.star.comp.svx.FontworkCharacterSpacingController"; +} + + +Sequence< OUString > FontworkCharacterSpacingControl::getSupportedServiceNames() +{ + Sequence<OUString> aSNS { "com.sun.star.frame.ToolbarController" }; + return aSNS; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_FontworkCharacterSpacingControl_get_implementation( + css::uno::XComponentContext* xContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FontworkCharacterSpacingControl(xContext)); +} + +FontworkCharacterSpacingDialog::FontworkCharacterSpacingDialog(weld::Window* pParent, sal_Int32 nScale) + : GenericDialogController(pParent, "svx/ui/fontworkspacingdialog.ui", "FontworkSpacingDialog") + , m_xMtrScale(m_xBuilder->weld_metric_spin_button("entry", FieldUnit::PERCENT)) +{ + m_xMtrScale->set_value(nScale, FieldUnit::PERCENT); +} + +FontworkCharacterSpacingDialog::~FontworkCharacterSpacingDialog() +{ +} + +sal_Int32 FontworkCharacterSpacingDialog::getScale() const +{ + return static_cast<sal_Int32>(m_xMtrScale->get_value(FieldUnit::PERCENT)); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/formatpaintbrushctrl.cxx b/svx/source/tbxctrls/formatpaintbrushctrl.cxx new file mode 100644 index 0000000000..f67efd12c7 --- /dev/null +++ b/svx/source/tbxctrls/formatpaintbrushctrl.cxx @@ -0,0 +1,105 @@ +/* -*- 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/formatpaintbrushctrl.hxx> + +#include <comphelper/propertyvalue.hxx> +#include <svl/eitem.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/settings.hxx> + + +namespace svx +{ + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +SFX_IMPL_TOOLBOX_CONTROL( FormatPaintBrushToolBoxControl, SfxBoolItem ); + +FormatPaintBrushToolBoxControl::FormatPaintBrushToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) + : SfxToolBoxControl( nSlotId, nId, rTbx ) + , m_bPersistentCopy(false) + , m_aDoubleClickTimer("FormatPaintBrushToolBoxControl m_aDoubleClickTimer") +{ + sal_uInt64 nDblClkTime = rTbx.GetSettings().GetMouseSettings().GetDoubleClickTime(); + + m_aDoubleClickTimer.SetInvokeHandler( LINK(this, FormatPaintBrushToolBoxControl, WaitDoubleClickHdl) ); + m_aDoubleClickTimer.SetTimeout(nDblClkTime); +} + + +FormatPaintBrushToolBoxControl::~FormatPaintBrushToolBoxControl() +{ + m_aDoubleClickTimer.Stop(); +} + + +void FormatPaintBrushToolBoxControl::impl_executePaintBrush() +{ + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("PersistentCopy", + m_bPersistentCopy) }; + Dispatch( ".uno:FormatPaintbrush" + , aArgs ); +} + + +void FormatPaintBrushToolBoxControl::DoubleClick() +{ + m_aDoubleClickTimer.Stop(); + + m_bPersistentCopy = true; + impl_executePaintBrush(); +} + + +void FormatPaintBrushToolBoxControl::Click() +{ + m_bPersistentCopy = false; + m_aDoubleClickTimer.Start(); +} + + +IMPL_LINK_NOARG(FormatPaintBrushToolBoxControl, WaitDoubleClickHdl, Timer *, void) +{ + //there was no second click during waiting + impl_executePaintBrush(); +} + + +void FormatPaintBrushToolBoxControl::Select(sal_uInt16 /*nSelectModifier*/) +{ +} + + +void FormatPaintBrushToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, + const SfxPoolItem* pState ) +{ + if( eState != SfxItemState::DEFAULT && eState != SfxItemState::SET ) + m_bPersistentCopy = false; + SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState, pState ); +} + + +} //namespace svx + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/grafctrl.cxx b/svx/source/tbxctrls/grafctrl.cxx new file mode 100644 index 0000000000..9595bbe89c --- /dev/null +++ b/svx/source/tbxctrls/grafctrl.cxx @@ -0,0 +1,961 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <comphelper/propertyvalue.hxx> +#include <o3tl/string_view.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/idle.hxx> +#include <svl/intitem.hxx> +#include <svl/itempool.hxx> +#include <svl/eitem.hxx> +#include <svl/whiter.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/request.hxx> +#include <sfx2/basedlgs.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <sfx2/sfxdlg.hxx> +#include <tools/urlobj.hxx> + +#include <svx/dialogs.hrc> +#include <svx/svxids.hrc> +#include <svx/strings.hrc> +#include <editeng/brushitem.hxx> +#include <editeng/sizeitem.hxx> +#include <svx/sdgcpitm.hxx> + +#include <svx/dialmgr.hxx> +#include <svx/svdview.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdtrans.hxx> +#include <svx/grafctrl.hxx> +#include <svx/tbxcolor.hxx> +#include <sdgcoitm.hxx> +#include <svx/sdggaitm.hxx> +#include <svx/sdgluitm.hxx> +#include <svx/sdgmoitm.hxx> +#include <sdgtritm.hxx> +#include <bitmaps.hlst> + +#include <com/sun/star/frame/XDispatchProvider.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +constexpr OUString TOOLBOX_NAME = u"colorbar"_ustr; +#define RID_SVXSTR_UNDO_GRAFCROP RID_SVXSTR_GRAFCROP + +namespace { + +class ImplGrafControl final : public InterimItemWindow +{ +private: + OUString maCommand; + Reference<XFrame> mxFrame; + std::unique_ptr<weld::Image> mxImage; + std::unique_ptr<weld::MetricSpinButton> mxField; + + DECL_LINK(ValueChangedHdl, weld::MetricSpinButton&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + void ImplModify(); + +public: + ImplGrafControl( vcl::Window* pParent, const OUString& rCmd, const Reference< XFrame >& rFrame ); + virtual ~ImplGrafControl() override; + virtual void dispose() override; + + void Update( const SfxPoolItem* pItem ); + void set_field_text(const OUString& rStr) { mxField->set_text(rStr); } + void set_sensitive(bool bSensitive) + { + Enable(bSensitive); + mxImage->set_sensitive(bSensitive); + mxField->set_sensitive(bSensitive); + } +}; + +} + +IMPL_LINK_NOARG(ImplGrafControl, ValueChangedHdl, weld::MetricSpinButton&, void) +{ + ImplModify(); +} + +void ImplGrafControl::ImplModify() +{ + const sal_Int64 nVal = mxField->get_value(FieldUnit::NONE); + + // Convert value to an any to be usable with dispatch API + Any a; + if ( maCommand == ".uno:GrafRed" || + maCommand == ".uno:GrafGreen" || + maCommand == ".uno:GrafBlue" || + maCommand == ".uno:GrafLuminance" || + maCommand == ".uno:GrafContrast" ) + a <<= sal_Int16( nVal ); + else if ( maCommand == ".uno:GrafGamma" || + maCommand == ".uno:GrafTransparence" ) + a <<= sal_Int32( nVal ); + + if ( !a.hasValue() ) + return; + + INetURLObject aObj( maCommand ); + + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(aObj.GetURLPath(), a) }; + + SfxToolBoxControl::Dispatch( + Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ), + maCommand, + aArgs ); +} + +void ImplGrafControl::Update( const SfxPoolItem* pItem ) +{ + if( pItem ) + { + tools::Long nValue; + + if ( maCommand == ".uno:GrafTransparence" ) + nValue = static_cast<const SfxUInt16Item*>( pItem )->GetValue(); + else if ( maCommand == ".uno:GrafGamma" ) + nValue = static_cast<const SfxUInt32Item*>( pItem )->GetValue(); + else + nValue = static_cast<const SfxInt16Item*>( pItem )->GetValue(); + + mxField->set_value(nValue, FieldUnit::NONE); + } + else + mxField->set_text(OUString()); +} + +namespace { + +struct CommandToRID +{ + const char* pCommand; + OUString sResId; +}; + +} + +static OUString ImplGetRID( std::u16string_view aCommand ) +{ + static constexpr OUString EMPTY = u""_ustr; + static constexpr CommandToRID aImplCommandToResMap[] = + { + { ".uno:GrafRed", RID_SVXBMP_GRAF_RED }, + { ".uno:GrafGreen", RID_SVXBMP_GRAF_GREEN }, + { ".uno:GrafBlue", RID_SVXBMP_GRAF_BLUE }, + { ".uno:GrafLuminance", RID_SVXBMP_GRAF_LUMINANCE }, + { ".uno:GrafContrast", RID_SVXBMP_GRAF_CONTRAST }, + { ".uno:GrafGamma", RID_SVXBMP_GRAF_GAMMA }, + { ".uno:GrafTransparence", RID_SVXBMP_GRAF_TRANSPARENCE }, + { nullptr, EMPTY } + }; + + OUString sRID; + + sal_Int32 i( 0 ); + while ( aImplCommandToResMap[ i ].pCommand ) + { + if ( o3tl::equalsAscii( aCommand, aImplCommandToResMap[ i ].pCommand )) + { + sRID = aImplCommandToResMap[i].sResId; + break; + } + ++i; + } + + return sRID; +} + +ImplGrafControl::ImplGrafControl( + vcl::Window* pParent, + const OUString& rCmd, + const Reference< XFrame >& rFrame) + : InterimItemWindow(pParent, "svx/ui/grafctrlbox.ui", "GrafCtrlBox") + , maCommand(rCmd) + , mxFrame(rFrame) + , mxImage(m_xBuilder->weld_image("image")) + , mxField(m_xBuilder->weld_metric_spin_button("spinfield", FieldUnit::NONE)) +{ + InitControlBase(&mxField->get_widget()); + + OUString sResId(ImplGetRID(rCmd)); + mxImage->set_from_icon_name(sResId); + mxImage->set_toolbar_background(); + + SetBackground( Wallpaper() ); // transparent background + + mxField->set_help_id(rCmd); + mxField->get_widget().connect_key_press(LINK(this, ImplGrafControl, KeyInputHdl)); + mxField->connect_value_changed(LINK(this, ImplGrafControl, ValueChangedHdl)); + + if (maCommand == ".uno:GrafGamma") + { + mxField->set_digits(2); + + mxField->set_range(10, 1000, FieldUnit::NONE); + mxField->set_increments(10, 100, FieldUnit::NONE); + } + else + { + const tools::Long nMinVal = maCommand == ".uno:GrafTransparence" ? 0 : -100; + + mxField->set_unit(FieldUnit::PERCENT); + mxField->set_digits(0); + + mxField->set_range(nMinVal, 100, FieldUnit::PERCENT); + mxField->set_increments(1, 10, FieldUnit::PERCENT); + } + + SetSizePixel(m_xContainer->get_preferred_size()); +} + +IMPL_LINK(ImplGrafControl, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return ChildKeyInput(rKEvt); +} + +ImplGrafControl::~ImplGrafControl() +{ + disposeOnce(); +} + +void ImplGrafControl::dispose() +{ + mxImage.reset(); + mxField.reset(); + InterimItemWindow::dispose(); +} + +namespace { + +class ImplGrafModeControl final : public InterimItemWindow +{ +private: + sal_uInt16 mnCurPos; + Reference< XFrame > mxFrame; + std::unique_ptr<weld::ComboBox> m_xWidget; + + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(FocusInHdl, weld::Widget&, void); + + static void ImplReleaseFocus(); + +public: + ImplGrafModeControl( vcl::Window* pParent, const Reference< XFrame >& rFrame ); + virtual void dispose() override; + virtual ~ImplGrafModeControl() override; + + void set_sensitive(bool bSensitive) + { + Enable(bSensitive); + m_xWidget->set_sensitive(true); + } + + void set_active(int nActive) + { + m_xWidget->set_active(nActive); + } + + void Update( const SfxPoolItem* pItem ); +}; + +} + +ImplGrafModeControl::ImplGrafModeControl(vcl::Window* pParent, const Reference<XFrame>& rFrame) + : InterimItemWindow(pParent, "svx/ui/grafmodebox.ui", "GrafModeBox") + , mnCurPos(0) + , mxFrame(rFrame) + , m_xWidget(m_xBuilder->weld_combo_box("grafmode")) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_STANDARD ) ); + m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_GREYS ) ); + m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_MONO ) ); + m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_WATERMARK ) ); + + m_xWidget->connect_changed(LINK(this, ImplGrafModeControl, SelectHdl)); + m_xWidget->connect_key_press(LINK(this, ImplGrafModeControl, KeyInputHdl)); + m_xWidget->connect_focus_in(LINK(this, ImplGrafModeControl, FocusInHdl)); + + SetSizePixel(m_xWidget->get_preferred_size()); +} + +void ImplGrafModeControl::dispose() +{ + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +ImplGrafModeControl::~ImplGrafModeControl() +{ + disposeOnce(); +} + +IMPL_LINK(ImplGrafModeControl, SelectHdl, weld::ComboBox&, rBox, void) +{ + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("GrafMode", + sal_Int16(rBox.get_active())) }; + + /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + ImplReleaseFocus(); + + SfxToolBoxControl::Dispatch( + Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ), + ".uno:GrafMode", + aArgs ); +} + +IMPL_LINK(ImplGrafModeControl, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled(false); + + if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE) + { + m_xWidget->set_active(mnCurPos); + ImplReleaseFocus(); + bHandled = true; + } + + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(ImplGrafModeControl, FocusInHdl, weld::Widget&, void) +{ + mnCurPos = m_xWidget->get_active(); +} + +void ImplGrafModeControl::ImplReleaseFocus() +{ + if( SfxViewShell::Current() ) + { + vcl::Window* pShellWnd = SfxViewShell::Current()->GetWindow(); + + if( pShellWnd ) + pShellWnd->GrabFocus(); + } +} + +void ImplGrafModeControl::Update( const SfxPoolItem* pItem ) +{ + if( pItem ) + m_xWidget->set_active(static_cast<const SfxUInt16Item*>(pItem)->GetValue()); + else + m_xWidget->set_active(-1); +} + +SvxGrafToolBoxControl::SvxGrafToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx) : + SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + rTbx.SetItemBits( nId, ToolBoxItemBits::DROPDOWN | rTbx.GetItemBits( nId ) ); + rTbx.Invalidate(); +} + +SvxGrafToolBoxControl::~SvxGrafToolBoxControl() +{ +} + +void SvxGrafToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState ) +{ + ImplGrafControl* pCtrl = static_cast<ImplGrafControl*>( GetToolBox().GetItemWindow( GetId() ) ); + DBG_ASSERT( pCtrl, "Control not found" ); + + if( eState == SfxItemState::DISABLED ) + { + pCtrl->set_sensitive(false); + pCtrl->set_field_text( OUString() ); + } + else + { + pCtrl->set_sensitive(true); + + if( eState == SfxItemState::DEFAULT ) + pCtrl->Update( pState ); + else + pCtrl->Update( nullptr ); + } +} + +VclPtr<InterimItemWindow> SvxGrafToolBoxControl::CreateItemWindow( vcl::Window *pParent ) +{ + return VclPtr<ImplGrafControl>::Create( pParent, m_aCommandURL, m_xFrame ).get(); +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafRedToolBoxControl, SfxInt16Item ); + +SvxGrafRedToolBoxControl::SvxGrafRedToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafGreenToolBoxControl, SfxInt16Item ); + +SvxGrafGreenToolBoxControl::SvxGrafGreenToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafBlueToolBoxControl, SfxInt16Item ); + +SvxGrafBlueToolBoxControl::SvxGrafBlueToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafLuminanceToolBoxControl, SfxInt16Item ); + +SvxGrafLuminanceToolBoxControl::SvxGrafLuminanceToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafContrastToolBoxControl, SfxInt16Item ); + +SvxGrafContrastToolBoxControl::SvxGrafContrastToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafGammaToolBoxControl, SfxUInt32Item ); + +SvxGrafGammaToolBoxControl::SvxGrafGammaToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafTransparenceToolBoxControl, SfxUInt16Item ); + +SvxGrafTransparenceToolBoxControl::SvxGrafTransparenceToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SvxGrafToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SFX_IMPL_TOOLBOX_CONTROL( SvxGrafModeToolBoxControl, SfxUInt16Item ); + +SvxGrafModeToolBoxControl::SvxGrafModeToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SfxToolBoxControl( nSlotId, nId, rTbx ) +{ +} + +SvxGrafModeToolBoxControl::~SvxGrafModeToolBoxControl() +{ +} + +void SvxGrafModeToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState ) + +{ + ImplGrafModeControl* pCtrl = static_cast<ImplGrafModeControl*>( GetToolBox().GetItemWindow( GetId() ) ); + DBG_ASSERT( pCtrl, "Control not found" ); + + if( eState == SfxItemState::DISABLED ) + { + pCtrl->set_sensitive(false); + pCtrl->set_active(-1); + } + else + { + pCtrl->set_sensitive(true); + + if( eState == SfxItemState::DEFAULT ) + pCtrl->Update( pState ); + else + pCtrl->Update( nullptr ); + } +} + +VclPtr<InterimItemWindow> SvxGrafModeToolBoxControl::CreateItemWindow( vcl::Window *pParent ) +{ + return VclPtr<ImplGrafModeControl>::Create( pParent, m_xFrame ).get(); +} + +void SvxGrafAttrHelper::ExecuteGrafAttr( SfxRequest& rReq, SdrView& rView ) +{ + SfxItemPool& rPool = rView.GetModel().GetItemPool(); + SfxItemSetFixed<SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST> aSet( rPool ); + OUString aUndoStr; + const bool bUndo = rView.IsUndoEnabled(); + + if( bUndo ) + { + aUndoStr = rView.GetDescriptionOfMarkedObjects() + " "; + } + + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem; + sal_uInt16 nSlot = rReq.GetSlot(); + + if( !pArgs || SfxItemState::SET != pArgs->GetItemState( nSlot, false, &pItem )) + pItem = nullptr; + + switch( nSlot ) + { + case SID_ATTR_GRAF_RED: + { + if( pItem ) + { + aSet.Put( SdrGrafRedItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFRED ); + } + } + break; + + case SID_ATTR_GRAF_GREEN: + { + if( pItem ) + { + aSet.Put( SdrGrafGreenItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFGREEN ); + } + } + break; + + case SID_ATTR_GRAF_BLUE: + { + if( pItem ) + { + aSet.Put( SdrGrafBlueItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFBLUE ); + } + } + break; + + case SID_ATTR_GRAF_LUMINANCE: + { + if( pItem ) + { + aSet.Put( SdrGrafLuminanceItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFLUMINANCE ); + } + } + break; + + case SID_ATTR_GRAF_CONTRAST: + { + if( pItem ) + { + aSet.Put( SdrGrafContrastItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFCONTRAST ); + } + } + break; + + case SID_ATTR_GRAF_GAMMA: + { + if( pItem ) + { + aSet.Put( SdrGrafGamma100Item( static_cast<const SfxUInt32Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFGAMMA ); + } + } + break; + + case SID_ATTR_GRAF_TRANSPARENCE: + { + if( pItem ) + { + aSet.Put( SdrGrafTransparenceItem( static_cast<const SfxUInt16Item*>(pItem)->GetValue() )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFTRANSPARENCY ); + } + } + break; + + case SID_ATTR_GRAF_MODE: + { + if( pItem ) + { + aSet.Put( SdrGrafModeItem( static_cast<GraphicDrawMode>(static_cast<const SfxUInt16Item*>(pItem)->GetValue()) )); + if( bUndo ) + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFMODE ); + } + } + break; + + case SID_ATTR_GRAF_CROP: + { + const SdrMarkList& rMarkList = rView.GetMarkedObjectList(); + + if( 0 < rMarkList.GetMarkCount() ) + { + SdrGrafObj* pObj = static_cast<SdrGrafObj*>( rMarkList.GetMark( 0 )->GetMarkedSdrObj() ); + + if( ( pObj->GetGraphicType() != GraphicType::NONE ) && + ( pObj->GetGraphicType() != GraphicType::Default ) ) + { + SfxItemSetFixed<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP> aGrfAttr( rPool ); + const MapUnit eOldMetric = rPool.GetMetric( 0 ); + + aGrfAttr.Put(pObj->GetMergedItemSet()); + rPool.SetDefaultMetric( MapUnit::MapTwip ); + + SfxItemSetFixed< + SDRATTR_GRAFCROP, SDRATTR_GRAFCROP, + SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE, + SID_ATTR_GRAF_CROP, SID_ATTR_GRAF_FRMSIZE, + SID_ATTR_GRAF_GRAPHIC, SID_ATTR_GRAF_GRAPHIC> + aCropDlgAttr(rPool); + + aCropDlgAttr.Put( SvxBrushItem( pObj->GetGraphic(), GPOS_MM, SID_ATTR_GRAF_GRAPHIC ) ); + aCropDlgAttr.Put( SvxSizeItem( SID_ATTR_PAGE_SIZE, + o3tl::convert(Size(200000, 200000), o3tl::Length::mm100, o3tl::Length::twip))); + aCropDlgAttr.Put( SvxSizeItem( SID_ATTR_GRAF_FRMSIZE, + o3tl::convert(pObj->GetLogicRect().GetSize(), o3tl::Length::mm100, o3tl::Length::twip))); + + const SdrGrafCropItem& rCrop = aGrfAttr.Get( SDRATTR_GRAFCROP ); + Size aLTSize = o3tl::convert(Size(rCrop.GetLeft(), rCrop.GetTop()), o3tl::Length::mm100, o3tl::Length::twip); + Size aRBSize = o3tl::convert(Size(rCrop.GetRight(), rCrop.GetBottom()), o3tl::Length::mm100, o3tl::Length::twip); + + aCropDlgAttr.Put( SdrGrafCropItem( aLTSize.Width(), aLTSize.Height(), + aRBSize.Width(), aRBSize.Height() ) ); + + vcl::Window* pParent(SfxViewShell::Current() ? SfxViewShell::Current()->GetWindow() : nullptr); + SfxSingleTabDialogController aCropDialog(pParent ? pParent->GetFrameWeld() : nullptr, + &aCropDlgAttr); + const OUString aCropStr(SvxResId(RID_SVXSTR_GRAFCROP)); + + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_GRFCROP ); + std::unique_ptr<SfxTabPage> xTabPage = (*fnCreatePage)(aCropDialog.get_content_area(), &aCropDialog, &aCropDlgAttr); + sal_Int32 nPreferredDPI = rView.getSdrModelFromSdrView().getImagePreferredDPI(); + xTabPage->getAdditionalProperties().emplace("PreferredDPI", css::uno::Any(nPreferredDPI)); + xTabPage->SetPageTitle(aCropStr); + aCropDialog.SetTabPage(std::move(xTabPage)); + + if (aCropDialog.run() == RET_OK) + { + const SfxItemSet* pOutAttr = aCropDialog.GetOutputItemSet(); + + if( pOutAttr ) + { + aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFCROP ); + + // set crop attributes + if( SfxItemState::SET <= pOutAttr->GetItemState( SDRATTR_GRAFCROP ) ) + { + const SdrGrafCropItem& rNewCrop = pOutAttr->Get( SDRATTR_GRAFCROP ); + + aLTSize = o3tl::convert(Size(rNewCrop.GetLeft(), rNewCrop.GetTop()), o3tl::Length::twip, o3tl::Length::mm100); + aRBSize = o3tl::convert(Size(rNewCrop.GetRight(), rNewCrop.GetBottom()), o3tl::Length::twip, o3tl::Length::mm100); + aSet.Put( SdrGrafCropItem( aLTSize.Width(), aLTSize.Height(), aRBSize.Width(), aRBSize.Height() ) ); + } + + // set new logic rect + if( SfxItemState::SET <= pOutAttr->GetItemState( SID_ATTR_GRAF_FRMSIZE ) ) + { + Point aNewOrigin( pObj->GetLogicRect().TopLeft() ); + const Size& rGrfSize = pOutAttr->Get( SID_ATTR_GRAF_FRMSIZE ).GetSize(); + Size aNewGrfSize = o3tl::convert(rGrfSize, o3tl::Length::twip, o3tl::Length::mm100); + Size aOldGrfSize( pObj->GetLogicRect().GetSize() ); + + tools::Rectangle aNewRect( aNewOrigin, aNewGrfSize ); + Point aOffset( (aNewGrfSize.Width() - aOldGrfSize.Width()) >> 1, + (aNewGrfSize.Height() - aOldGrfSize.Height()) >> 1 ); + + // #106181# rotate snap rect before setting it + const GeoStat& aGeo = pObj->GetGeoStat(); + + if (aGeo.m_nRotationAngle || aGeo.m_nShearAngle) + { + tools::Polygon aPol(aNewRect); + + // also transform origin offset + if (aGeo.m_nShearAngle) + { + ShearPoly(aPol, + aNewRect.TopLeft(), + aGeo.mfTanShearAngle); + ShearPoint(aOffset, Point(0,0), aGeo.mfTanShearAngle); + } + if (aGeo.m_nRotationAngle) + { + RotatePoly(aPol, + aNewRect.TopLeft(), + aGeo.mfSinRotationAngle,aGeo.mfCosRotationAngle); + RotatePoint(aOffset, Point(0,0), aGeo.mfSinRotationAngle,aGeo.mfCosRotationAngle); + } + + // apply offset + aPol.Move( -aOffset.X(), -aOffset.Y() ); + aNewRect=aPol.GetBoundRect(); + } + else + { + aNewRect.Move( -aOffset.X(), -aOffset.Y() ); + } + + if( !aSet.Count() ) + rView.SetMarkedObjRect( aNewRect ); + else + { + if( bUndo ) + { + rView.BegUndo( aUndoStr ); + rView.AddUndo(rView.GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj)); + } + pObj->SetSnapRect( aNewRect ); + rView.SetAttributes( aSet ); + + if( bUndo ) + rView.EndUndo(); + aSet.ClearItem(); + } + } + } + } + + rPool.SetDefaultMetric( eOldMetric ); + } + } + } + break; + + case SID_COLOR_SETTINGS: + { + svx::ToolboxAccess aToolboxAccess( TOOLBOX_NAME ); + aToolboxAccess.toggleToolbox(); + rReq.Done(); + break; + } + + default: + break; + } + + if( aSet.Count() ) + { + if( bUndo ) + rView.BegUndo( aUndoStr ); + + rView.SetAttributes( aSet ); + + if( bUndo ) + rView.EndUndo(); + } +} + +void SvxGrafAttrHelper::GetGrafAttrState( SfxItemSet& rSet, SdrView const & rView ) +{ + SfxItemPool& rPool = rView.GetModel().GetItemPool(); + SfxItemSet aAttrSet( rPool ); + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + const SdrMarkList& rMarkList = rView.GetMarkedObjectList(); + bool bEnableColors = true; + bool bEnableTransparency = true; + bool bEnableCrop = ( 1 == rMarkList.GetMarkCount() ); + + for( size_t i = 0, nCount = rMarkList.GetMarkCount(); i < nCount; ++i ) + { + SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >( rMarkList.GetMark( i )->GetMarkedSdrObj() ); + + if( !pGrafObj || + ( pGrafObj->GetGraphicType() == GraphicType::NONE ) || + ( pGrafObj->GetGraphicType() == GraphicType::Default )) + { + bEnableColors = bEnableTransparency = bEnableCrop = false; + break; + } + else if( bEnableTransparency && ( pGrafObj->HasGDIMetaFile() || pGrafObj->IsAnimated() ) ) + { + bEnableTransparency = false; + } + } + + rView.GetAttributes( aAttrSet ); + + while( nWhich ) + { + sal_uInt16 nSlotId = SfxItemPool::IsWhich( nWhich ) ? rPool.GetSlotId( nWhich ) : nWhich; + + switch( nSlotId ) + { + case SID_ATTR_GRAF_MODE: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFMODE ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxUInt16Item( nSlotId, + sal::static_int_cast< sal_uInt16 >( aAttrSet.Get(SDRATTR_GRAFMODE).GetValue() ) ) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_MODE ); + } + } + } + break; + + case SID_ATTR_GRAF_RED: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFRED ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFRED).GetValue() ) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_RED ); + } + } + } + break; + + case SID_ATTR_GRAF_GREEN: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFGREEN ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFGREEN).GetValue()) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_GREEN ); + } + } + } + break; + + case SID_ATTR_GRAF_BLUE: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFBLUE ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFBLUE).GetValue()) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_BLUE ); + } + } + } + break; + + case SID_ATTR_GRAF_LUMINANCE: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFLUMINANCE ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFLUMINANCE).GetValue()) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_LUMINANCE ); + } + } + } + break; + + case SID_ATTR_GRAF_CONTRAST: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFCONTRAST ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxInt16Item( nSlotId, + aAttrSet.Get(SDRATTR_GRAFCONTRAST).GetValue()) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_CONTRAST ); + } + } + } + break; + + case SID_ATTR_GRAF_GAMMA: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFGAMMA ) ) + { + if( bEnableColors ) + { + rSet.Put( SfxUInt32Item( nSlotId, + aAttrSet.Get(SDRATTR_GRAFGAMMA).GetValue() ) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_GAMMA ); + } + } + } + break; + + case SID_ATTR_GRAF_TRANSPARENCE: + { + if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFTRANSPARENCE ) ) + { + if( bEnableTransparency ) + { + rSet.Put( SfxUInt16Item( nSlotId, + aAttrSet.Get(SDRATTR_GRAFTRANSPARENCE).GetValue() ) ); + } + else + { + rSet.DisableItem( SID_ATTR_GRAF_TRANSPARENCE ); + } + } + } + break; + + case SID_ATTR_GRAF_CROP: + { + if( !bEnableCrop ) + rSet.DisableItem( nSlotId ); + } + break; + + case SID_COLOR_SETTINGS : + { + svx::ToolboxAccess aToolboxAccess( TOOLBOX_NAME ); + rSet.Put( SfxBoolItem( nWhich, aToolboxAccess.isToolboxVisible() ) ); + break; + } + + default: + break; + } + + nWhich = aIter.NextWhich(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/itemwin.cxx b/svx/source/tbxctrls/itemwin.cxx new file mode 100644 index 0000000000..1a9b6d3bcf --- /dev/null +++ b/svx/source/tbxctrls/itemwin.cxx @@ -0,0 +1,347 @@ +/* -*- 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/FillStyle.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <sfx2/tbxctrl.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/module.hxx> + +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/virdev.hxx> + +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> + +#include <svx/xlnwtit.hxx> +#include <svx/xtable.hxx> +#include <svx/itemwin.hxx> +#include <svtools/unitconv.hxx> +#include "linemetricbox.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +SvxMetricField::SvxMetricField( + vcl::Window* pParent, const Reference< XFrame >& rFrame ) + : InterimItemWindow(pParent, "svx/ui/metricfieldbox.ui", "MetricFieldBox") + , m_xWidget(m_xBuilder->weld_metric_spin_button("metricfield", FieldUnit::MM)) + , nCurValue(0) + , eDestPoolUnit(MapUnit::Map100thMM) + , eDlgUnit(SfxModule::GetModuleFieldUnit(rFrame)) + , mxFrame(rFrame) +{ + InitControlBase(&m_xWidget->get_widget()); + + m_xWidget->set_range(0, 5000, FieldUnit::NONE); + m_xWidget->connect_value_changed(LINK(this, SvxMetricField, ModifyHdl)); + m_xWidget->connect_focus_in(LINK(this, SvxMetricField, FocusInHdl)); + m_xWidget->get_widget().connect_key_press(LINK(this, SvxMetricField, KeyInputHdl)); + + SetFieldUnit(*m_xWidget, eDlgUnit); + + SetSizePixel(m_xWidget->get_preferred_size()); +} + +void SvxMetricField::dispose() +{ + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +SvxMetricField::~SvxMetricField() +{ + disposeOnce(); +} + +void SvxMetricField::set_sensitive(bool bSensitive) +{ + Enable(bSensitive); + m_xWidget->set_sensitive(bSensitive); + if (!bSensitive) + m_xWidget->set_text(""); +} + +void SvxMetricField::Update( const XLineWidthItem* pItem ) +{ + if ( pItem ) + { + // tdf#132169 we always get the value in MapUnit::Map100thMM but have + // to set it in the core metric of the target application + if (pItem->GetValue() != GetCoreValue(*m_xWidget, MapUnit::Map100thMM)) + SetMetricValue(*m_xWidget, pItem->GetValue(), MapUnit::Map100thMM); + } + else + m_xWidget->set_text(""); +} + +IMPL_LINK_NOARG(SvxMetricField, ModifyHdl, weld::MetricSpinButton&, void) +{ + auto nTmp = GetCoreValue(*m_xWidget, eDestPoolUnit); + XLineWidthItem aLineWidthItem( nTmp ); + + Any a; + aLineWidthItem.QueryValue( a ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineWidth", a) }; + SfxToolBoxControl::Dispatch( Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ), + ".uno:LineWidth", + aArgs ); +} + +void SvxMetricField::ReleaseFocus_Impl() +{ + if( SfxViewShell::Current() ) + { + vcl::Window* pShellWnd = SfxViewShell::Current()->GetWindow(); + if ( pShellWnd ) + pShellWnd->GrabFocus(); + } +} + +void SvxMetricField::SetDestCoreUnit( MapUnit eUnit ) +{ + eDestPoolUnit = eUnit; +} + +void SvxMetricField::RefreshDlgUnit() +{ + FieldUnit eTmpUnit = SfxModule::GetModuleFieldUnit( mxFrame ); + if ( eDlgUnit != eTmpUnit ) + { + eDlgUnit = eTmpUnit; + SetFieldUnit(*m_xWidget, eDlgUnit); + } +} + +IMPL_LINK_NOARG(SvxMetricField, FocusInHdl, weld::Widget&, void) +{ + nCurValue = m_xWidget->get_value(FieldUnit::NONE); +} + +IMPL_LINK(SvxMetricField, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + if (nCode == KEY_ESCAPE) + { + m_xWidget->set_value(nCurValue, FieldUnit::NONE); + ModifyHdl(*m_xWidget); + ReleaseFocus_Impl(); + bHandled = true; + } + + return bHandled || ChildKeyInput(rKEvt); +} + +void SvxMetricField::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + SetSizePixel(m_xWidget->get_preferred_size()); + } + + InterimItemWindow::DataChanged( rDCEvt ); +} + +void SvxFillTypeBox::Fill(weld::ComboBox& rListBox) +{ + rListBox.freeze(); + + rListBox.append_text(SvxResId(RID_SVXSTR_INVISIBLE)); + rListBox.append_text(SvxResId(RID_SVXSTR_COLOR)); + rListBox.append_text(SvxResId(RID_SVXSTR_GRADIENT)); + rListBox.append_text(SvxResId(RID_SVXSTR_HATCH)); + rListBox.append_text(SvxResId(RID_SVXSTR_BITMAP)); + rListBox.append_text(SvxResId(RID_SVXSTR_PATTERN)); + rListBox.append_text(SvxResId(RID_SVXSTR_USE_BACKGROUND)); + + rListBox.thaw(); + + rListBox.set_active(1); // solid color +} + +namespace +{ + void formatBitmapExToSize(BitmapEx& rBitmapEx, const Size& rSize) + { + if(rBitmapEx.IsEmpty() || rSize.IsEmpty()) + return; + + 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); + } +} // end of anonymous namespace + +void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XHatchListRef &pList) +{ + if( !pList.is() ) + return; + + tools::Long nCount = pList->Count(); + ScopedVclPtrInstance< VirtualDevice > pVD; + rBox.freeze(); + + for( tools::Long i = 0; i < nCount; i++ ) + { + const XHatchEntry* pEntry = pList->GetHatch(i); + const BitmapEx aBitmapEx = pList->GetUiBitmap( i ); + if( !aBitmapEx.IsEmpty() ) + { + const Size aBmpSize(aBitmapEx.GetSizePixel()); + pVD->SetOutputSizePixel(aBmpSize, false); + pVD->DrawBitmapEx(Point(), aBitmapEx); + rBox.append("", pEntry->GetName(), *pVD); + } + else + rBox.append_text(pEntry->GetName()); + } + + rBox.thaw(); +} + +void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XGradientListRef &pList) +{ + if( !pList.is() ) + return; + + tools::Long nCount = pList->Count(); + ScopedVclPtrInstance< VirtualDevice > pVD; + rBox.freeze(); + + for( tools::Long i = 0; i < nCount; i++ ) + { + const XGradientEntry* pEntry = pList->GetGradient(i); + const BitmapEx aBitmapEx = pList->GetUiBitmap( i ); + if( !aBitmapEx.IsEmpty() ) + { + const Size aBmpSize(aBitmapEx.GetSizePixel()); + pVD->SetOutputSizePixel(aBmpSize, false); + pVD->DrawBitmapEx(Point(), aBitmapEx); + rBox.append("", pEntry->GetName(), *pVD); + } + else + rBox.append_text(pEntry->GetName()); + } + + rBox.thaw(); +} + +void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XBitmapListRef &pList) +{ + if( !pList.is() ) + return; + + tools::Long nCount = pList->Count(); + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size aSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize()); + ScopedVclPtrInstance< VirtualDevice > pVD; + pVD->SetOutputSizePixel(aSize, false); + rBox.freeze(); + + for( tools::Long i = 0; i < nCount; i++ ) + { + const XBitmapEntry* pEntry = pList->GetBitmap( i ); + BitmapEx aBitmapEx = pEntry->GetGraphicObject().GetGraphic().GetBitmapEx(); + formatBitmapExToSize(aBitmapEx, aSize); + pVD->DrawBitmapEx(Point(), aBitmapEx); + rBox.append("", pEntry->GetName(), *pVD); + } + + rBox.thaw(); +} + +void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XPatternListRef &pList) +{ + if( !pList.is() ) + return; + + tools::Long nCount = pList->Count(); + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const Size aSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize()); + ScopedVclPtrInstance< VirtualDevice > pVD; + pVD->SetOutputSizePixel(aSize, false); + rBox.freeze(); + + for( tools::Long i = 0; i < nCount; i++ ) + { + const XBitmapEntry* pEntry = pList->GetBitmap( i ); + BitmapEx aBitmapEx = pEntry->GetGraphicObject().GetGraphic().GetBitmapEx(); + formatBitmapExToSize(aBitmapEx, aSize); + pVD->DrawBitmapEx(Point(), aBitmapEx); + rBox.append("", pEntry->GetName(), *pVD); + } + + rBox.thaw(); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/layctrl.cxx b/svx/source/tbxctrls/layctrl.cxx new file mode 100644 index 0000000000..0ec276a5a9 --- /dev/null +++ b/svx/source/tbxctrls/layctrl.cxx @@ -0,0 +1,799 @@ +/* -*- 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 <utility> +#include <vcl/customweld.hxx> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> + +#include <svx/strings.hrc> +#include <layctrl.hxx> +#include <svx/dialmgr.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <svtools/colorcfg.hxx> +#include <svtools/toolbarmenu.hxx> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> + +// namespaces +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; + +namespace { + +class TableWidget final : public weld::CustomWidgetController +{ +private: + rtl::Reference<SvxTableToolBoxControl> mxControl; + OUString maCommand; + + tools::Long nCol; + tools::Long nLine; + + static const tools::Long TABLE_CELLS_HORIZ; + static const tools::Long TABLE_CELLS_VERT; + + tools::Long mnTableCellWidth; + tools::Long mnTableCellHeight; + + tools::Long mnTableWidth; + tools::Long mnTableHeight; + + ::Color aFontColor; + ::Color aLineColor; + ::Color aFillColor; + ::Color aHighlightFillColor; + ::Color aBackgroundColor; + + void Update(tools::Long nNewCol, tools::Long nNewLine); + void InsertTable(); + +public: + TableWidget(SvxTableToolBoxControl* pControl, OUString aCommand); + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + + virtual bool KeyInput(const KeyEvent&) override; + virtual bool MouseButtonDown(const MouseEvent&) override; + virtual bool MouseMove(const MouseEvent&) override; + virtual bool MouseButtonUp(const MouseEvent&) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; +}; + +class TableWindow final : public WeldToolbarPopup +{ +private: + std::unique_ptr<weld::Button> mxTableButton; + std::unique_ptr<TableWidget> mxTableWidget; + std::unique_ptr<weld::CustomWeld> mxTableWidgetWin; + rtl::Reference<SvxTableToolBoxControl> mxControl; + + DECL_LINK(SelectHdl, weld::Button&, void); + +public: + TableWindow( SvxTableToolBoxControl* pControl, weld::Widget* pParent, + const OUString& rCmd); + virtual void GrabFocus() override + { + mxTableWidget->GrabFocus(); + } +}; + +} + +const tools::Long TableWidget::TABLE_CELLS_HORIZ = 10; +const tools::Long TableWidget::TABLE_CELLS_VERT = 15; + +IMPL_LINK_NOARG(TableWindow, SelectHdl, weld::Button&, void) +{ + mxControl->CloseAndShowTableDialog(); +} + +TableWindow::TableWindow(SvxTableToolBoxControl* pControl, weld::Widget* pParent, const OUString& rCmd) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/tablewindow.ui", "TableWindow") + , mxTableButton(m_xBuilder->weld_button("moreoptions")) + , mxTableWidget(new TableWidget(pControl, rCmd)) + , mxTableWidgetWin(new weld::CustomWeld(*m_xBuilder, "table", *mxTableWidget)) + , mxControl(pControl) +{ + mxTableButton->set_label( SvxResId( RID_SVXSTR_MORE ) ); + mxTableButton->connect_clicked( LINK( this, TableWindow, SelectHdl ) ); + mxTableButton->show(); +} + +TableWidget::TableWidget(SvxTableToolBoxControl* pControl, OUString aCommand) + : mxControl(pControl) + , maCommand(std::move(aCommand)) + , nCol(0) + , nLine(0) + , mnTableCellWidth(0) + , mnTableCellHeight(0) + , mnTableWidth(0) + , mnTableHeight(0) +{ + const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings(); + aFontColor = rStyles.GetLabelTextColor(); + aLineColor = rStyles.GetShadowColor(); + aFillColor = rStyles.GetWindowColor(); + aHighlightFillColor = rStyles.GetHighlightColor(); + aBackgroundColor = rStyles.GetFaceColor(); +} + +void TableWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + float fScaleFactor = pDrawingArea->get_ref_device().GetDPIScaleFactor(); + + mnTableCellWidth = 15 * fScaleFactor; + mnTableCellHeight = 15 * fScaleFactor; + + mnTableWidth = TABLE_CELLS_HORIZ*mnTableCellWidth; + mnTableHeight = TABLE_CELLS_VERT*mnTableCellHeight; + + //Â + 1 to leave space to draw the right/bottom borders + Size aSize(mnTableWidth + 1, mnTableHeight + 1); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + CustomWidgetController::SetDrawingArea(pDrawingArea); + SetOutputSizePixel(aSize); +} + +bool TableWidget::MouseMove(const MouseEvent& rMEvt) +{ + Point aPos = rMEvt.GetPosPixel(); + Point aMousePos( aPos ); + + tools::Long nNewCol = ( aMousePos.X() + mnTableCellWidth ) / mnTableCellWidth; + tools::Long nNewLine = ( aMousePos.Y() + mnTableCellHeight ) / mnTableCellHeight; + + Update( nNewCol, nNewLine ); + + return true; +} + +bool TableWidget::KeyInput(const KeyEvent& rKEvt) +{ + bool bHandled = false; + sal_uInt16 nModifier = rKEvt.GetKeyCode().GetModifier(); + sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode(); + if ( !nModifier ) + { + bHandled = true; + tools::Long nNewCol = nCol; + tools::Long nNewLine = nLine; + switch(nKey) + { + case KEY_UP: + if ( nNewLine > 1 ) + nNewLine--; + else + mxControl->EndPopupMode(); + break; + case KEY_DOWN: + if ( nNewLine < TABLE_CELLS_VERT ) + { + nNewLine++; + if ( nNewCol == 0 ) + nNewCol = 1; + } + else + mxControl->CloseAndShowTableDialog(); + break; + case KEY_LEFT: + if ( nNewCol > 1 ) + nNewCol--; + else + mxControl->EndPopupMode(); + break; + case KEY_RIGHT: + if ( nNewCol < TABLE_CELLS_HORIZ ) + { + nNewCol++; + if ( nNewLine == 0 ) + nNewLine = 1; + } + else + mxControl->CloseAndShowTableDialog(); + break; + case KEY_ESCAPE: + mxControl->EndPopupMode(); + break; + case KEY_RETURN: + InsertTable(); + mxControl->EndPopupMode(); + return true; + default: + bHandled = false; + } + if ( bHandled ) + { + Update( nNewCol, nNewLine ); + } + } + else if (KEY_MOD1 == nModifier && KEY_RETURN == nKey) + { + InsertTable(); + mxControl->EndPopupMode(); + return true; + } + + return bHandled; +} + +bool TableWidget::MouseButtonUp(const MouseEvent&) +{ + InsertTable(); + mxControl->EndPopupMode(); + return true; +} + +bool TableWidget::MouseButtonDown(const MouseEvent&) +{ + return true; +} + +void TableWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.Push(vcl::PushFlags::FONT); + + rRenderContext.SetBackground( aBackgroundColor ); + vcl::Font aFont = rRenderContext.GetFont(); + aFont.SetColor( aFontColor ); + aFont.SetFillColor( aBackgroundColor ); + aFont.SetTransparent( false ); + rRenderContext.SetFont( aFont ); + + const tools::Long nSelectionWidth = nCol * mnTableCellWidth; + const tools::Long nSelectionHeight = nLine * mnTableCellHeight; + + // the non-selected parts of the table + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(aFillColor); + rRenderContext.DrawRect(tools::Rectangle(nSelectionWidth, 0, mnTableWidth, nSelectionHeight)); + rRenderContext.DrawRect(tools::Rectangle(0, nSelectionHeight, nSelectionWidth, mnTableHeight)); + rRenderContext.DrawRect(tools::Rectangle(nSelectionWidth, nSelectionHeight, mnTableWidth, mnTableHeight)); + + // the selection + if (nCol > 0 && nLine > 0) + { + rRenderContext.SetFillColor(aHighlightFillColor); + rRenderContext.DrawRect(tools::Rectangle(0, 0, nSelectionWidth, nSelectionHeight)); + } + + // lines inside of the table + rRenderContext.SetLineColor(aLineColor); + for (tools::Long i = 1; i < TABLE_CELLS_VERT; ++i) + { + rRenderContext.DrawLine(Point(0, i*mnTableCellHeight), + Point(mnTableWidth, i*mnTableCellHeight)); + } + + for (tools::Long i = 1; i < TABLE_CELLS_HORIZ; ++i) + { + rRenderContext.DrawLine(Point( i*mnTableCellWidth, 0), + Point( i*mnTableCellWidth, mnTableHeight)); + } + + // the text near the mouse cursor telling the table dimensions + if (!nCol || !nLine) + { + rRenderContext.Pop(); + return; + } + + OUString aText = OUString::number( nCol ) + " x " + OUString::number( nLine ); + if (maCommand == ".uno:ShowMultiplePages") + { + aText += " " + SvxResId(RID_SVXSTR_PAGES); + } + + Size aTextSize(rRenderContext.GetTextWidth(aText), rRenderContext.GetTextHeight()); + + tools::Long nTextX = nSelectionWidth + mnTableCellWidth; + tools::Long nTextY = nSelectionHeight + mnTableCellHeight; + const tools::Long nTipBorder = 2; + + if (aTextSize.Width() + mnTableCellWidth + 2 * nTipBorder < nSelectionWidth) + nTextX = nSelectionWidth - mnTableCellWidth - aTextSize.Width(); + + if (aTextSize.Height() + mnTableCellHeight + 2 * nTipBorder < nSelectionHeight) + nTextY = nSelectionHeight - mnTableCellHeight - aTextSize.Height(); + + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(aBackgroundColor); + rRenderContext.DrawRect(tools::Rectangle(nTextX - 2 * nTipBorder, + nTextY - 2 * nTipBorder, + nTextX + aTextSize.Width() + nTipBorder, + nTextY + aTextSize.Height() + nTipBorder)); + + // #i95350# force RTL output + if (IsRTLEnabled()) + aText = u"\u202D" + aText; + + rRenderContext.DrawText(Point(nTextX, nTextY), aText); + + rRenderContext.Pop(); +} + +void TableWidget::InsertTable() +{ + if (nCol && nLine) + { + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("Columns", sal_Int16( nCol )), + comphelper::makePropertyValue("Rows", sal_Int16( nLine )) }; + + mxControl->TableDialog( aArgs ); + } +} + +void TableWidget::Update( tools::Long nNewCol, tools::Long nNewLine ) +{ + if ( nNewCol < 0 || nNewCol > TABLE_CELLS_HORIZ ) + nNewCol = 0; + + if ( nNewLine < 0 || nNewLine > TABLE_CELLS_VERT ) + nNewLine = 0; + + if ( nNewCol != nCol || nNewLine != nLine ) + { + nCol = nNewCol; + nLine = nNewLine; + Invalidate(tools::Rectangle(0, 0, mnTableWidth, mnTableHeight)); + } +} + +void SvxTableToolBoxControl::TableDialog( const Sequence< PropertyValue >& rArgs ) +{ + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); + if ( xDispatchProvider.is() ) + { + css::util::URL aTargetURL; + Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) ); + aTargetURL.Complete = m_aCommandURL; + xTrans->parseStrict( aTargetURL ); + + Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); + if ( xDispatch.is() ) + xDispatch->dispatch( aTargetURL, rArgs ); + } +} + +void SvxTableToolBoxControl::CloseAndShowTableDialog() +{ + // close the toolbar tool + EndPopupMode(); + + // and open the table dialog instead + TableDialog( Sequence< PropertyValue >() ); +} + +namespace { + +class ColumnsWidget final : public weld::CustomWidgetController +{ +private: + static constexpr tools::Long WIDTH = 5; + + rtl::Reference<SvxColumnsToolBoxControl> mxControl; + weld::SpinButton& mrSpinButton; + + ::Color aLineColor; + ::Color aHighlightLineColor; + ::Color aFillColor; + ::Color aHighlightFillColor; + ::Color aFaceColor; + tools::Long nCol; + tools::Long nMX; + bool m_bMod1; + + DECL_LINK(ValueChangedHdl, weld::SpinButton&, void); + DECL_LINK(ActivateHdl, weld::Entry&, bool); + + void InsertColumns(); + void UpdateSize_Impl( tools::Long nNewCol ); +public: + ColumnsWidget(SvxColumnsToolBoxControl* pControl, weld::SpinButton& rSpinButton); + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + + virtual bool KeyInput(const KeyEvent&) override; + virtual bool MouseButtonDown(const MouseEvent&) override; + virtual bool MouseMove(const MouseEvent&) override; + virtual bool MouseButtonUp(const MouseEvent&) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; +}; + + +class ColumnsWindow final : public WeldToolbarPopup +{ +private: + std::unique_ptr<weld::SpinButton> mxSpinButton; + std::unique_ptr<ColumnsWidget> mxColumnsWidget; + std::unique_ptr<weld::CustomWeld> mxColumnsWidgetWin; + rtl::Reference<SvxColumnsToolBoxControl> mxControl; + +public: + ColumnsWindow(SvxColumnsToolBoxControl* pControl, weld::Widget* pParent); + + virtual void GrabFocus() override + { + mxColumnsWidget->GrabFocus(); + } +}; + +} + +ColumnsWindow::ColumnsWindow(SvxColumnsToolBoxControl* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/columnswindow.ui", "ColumnsWindow") + , mxSpinButton(m_xBuilder->weld_spin_button("spinbutton")) + , mxColumnsWidget(new ColumnsWidget(pControl, *mxSpinButton)) + , mxColumnsWidgetWin(new weld::CustomWeld(*m_xBuilder, "columns", *mxColumnsWidget)) + , mxControl(pControl) +{ +} + +ColumnsWidget::ColumnsWidget(SvxColumnsToolBoxControl* pControl, weld::SpinButton& rSpinButton) + : mxControl(pControl) + , mrSpinButton(rSpinButton) + , nCol(1) + , nMX(0) + , m_bMod1(false) +{ + mrSpinButton.connect_value_changed(LINK(this, ColumnsWidget, ValueChangedHdl)); + mrSpinButton.connect_activate(LINK(this, ColumnsWidget, ActivateHdl)); + + const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings(); + aLineColor = rStyles.GetLabelTextColor(); + aHighlightLineColor = rStyles.GetHighlightTextColor(); + aFillColor = rStyles.GetWindowColor(); + aHighlightFillColor = rStyles.GetHighlightColor(); + aFaceColor = rStyles.GetFaceColor(); +} + +IMPL_LINK_NOARG(ColumnsWidget, ValueChangedHdl, weld::SpinButton&, void) +{ + UpdateSize_Impl(mrSpinButton.get_value()); +} + +IMPL_LINK_NOARG(ColumnsWidget, ActivateHdl, weld::Entry&, bool) +{ + InsertColumns(); + mxControl->EndPopupMode(); + return true; +} + +void ColumnsWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + OutputDevice& rDevice = pDrawingArea->get_ref_device(); + Size aLogicSize = rDevice.LogicToPixel( Size( 95, 155 ), MapMode( MapUnit::Map10thMM ) ); + nMX = aLogicSize.Width(); + Size aSize(nMX*WIDTH-1, aLogicSize.Height()); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + CustomWidgetController::SetDrawingArea(pDrawingArea); + SetOutputSizePixel(aSize); +} + +bool ColumnsWidget::MouseMove(const MouseEvent& rMEvt) +{ + Point aPos = rMEvt.GetPosPixel(); + + tools::Long nNewCol = 1; + if ( aPos.X() > 0 ) + nNewCol = aPos.X() / nMX + 1; + if ( nNewCol > 20 ) + nNewCol = 20; + UpdateSize_Impl( nNewCol ); + + return true; +} + +void ColumnsWidget::UpdateSize_Impl( tools::Long nNewCol ) +{ + if ( nNewCol == nCol ) + return; + + Size aWinSize = GetOutputSizePixel(); + + Invalidate( tools::Rectangle( 0, aWinSize.Height() - 2, + aWinSize.Width(), aWinSize.Height() ) ); + + tools::Long nMinCol = 0, nMaxCol = 0; + + if ( nNewCol < nCol ) + { + nMinCol = nNewCol; + nMaxCol = nCol; + } + else + { + nMinCol = nCol; + nMaxCol = nNewCol; + } + + Invalidate( tools::Rectangle( nMinCol*nMX-1, 0, + nMaxCol*nMX+1, aWinSize.Height() - 2 ) ); + nCol = nNewCol; + mrSpinButton.set_value(nCol); +} + +bool ColumnsWidget::MouseButtonDown(const MouseEvent&) +{ + return true; +} + +bool ColumnsWidget::KeyInput(const KeyEvent& rKEvt) +{ + bool bHandled = false; + sal_uInt16 nModifier = rKEvt.GetKeyCode().GetModifier(); + sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode(); + if(!nModifier) + { + if( KEY_LEFT == nKey || KEY_RIGHT == nKey || + KEY_RETURN == nKey ||KEY_ESCAPE == nKey || + KEY_UP == nKey) + { + bHandled = true; + tools::Long nNewCol = nCol; + switch(nKey) + { + case KEY_LEFT : + if(nNewCol) + nNewCol--; + break; + case KEY_RIGHT : + nNewCol++; + break; + case KEY_RETURN : + InsertColumns(); + mxControl->EndPopupMode(); + break; + case KEY_ESCAPE : + case KEY_UP : + mxControl->EndPopupMode(); + break; + } + UpdateSize_Impl( nNewCol ); + } + } + else if(KEY_MOD1 == nModifier && KEY_RETURN == nKey) + { + m_bMod1 = true; + InsertColumns(); + mxControl->EndPopupMode(); + } + return bHandled; +} + +bool ColumnsWidget::MouseButtonUp(const MouseEvent&) +{ + InsertColumns(); + mxControl->EndPopupMode(); + return true; +} + +void ColumnsWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.Push(vcl::PushFlags::FONT); + + rRenderContext.SetBackground(); + vcl::Font aFont( rRenderContext.GetFont() ); + aFont.SetColor( aLineColor ); + aFont.SetFillColor( aFaceColor ); + aFont.SetTransparent( false ); + rRenderContext.SetFont( aFont ); + + tools::Long i; + tools::Long nLineWidth; + Size aSize(GetOutputSizePixel()); + + for (i = 0; i < WIDTH; i++) + { + if (i < nCol) + { + rRenderContext.SetLineColor(aHighlightLineColor); + rRenderContext.SetFillColor(aHighlightFillColor); + } + else + { + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(aFillColor); + } + + rRenderContext.DrawRect(tools::Rectangle(i * nMX - 1, -1, i * nMX + nMX, aSize.Height() - 1)); + + tools::Long j = 4; + while (j < aSize.Height() - 4) + { + if (!(j % 16)) + nLineWidth = 10; + else + nLineWidth = 4; + rRenderContext.DrawLine(Point(i * nMX + 4, j), Point(i * nMX + nMX - nLineWidth - 4, j)); + j += 4; + } + } + + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(aFaceColor); + + rRenderContext.DrawRect(tools::Rectangle(0, + aSize.Height() - 2, + aSize.Width() / 2 - 1, + aSize.Height())); + + rRenderContext.DrawRect(tools::Rectangle(aSize.Width() / 2, + aSize.Height() - 2, + aSize.Width(), + aSize.Height())); + + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(); + rRenderContext.DrawRect(tools::Rectangle( 0, 0, aSize.Width() - 1, aSize.Height() - 1)); + + rRenderContext.Pop(); +} + +void SvxColumnsToolBoxControl::InsertColumns(const Sequence< PropertyValue >& rArgs) +{ + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); + if ( xDispatchProvider.is() ) + { + css::util::URL aTargetURL; + Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) ); + aTargetURL.Complete = m_aCommandURL; + xTrans->parseStrict( aTargetURL ); + + Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); + if ( xDispatch.is() ) + xDispatch->dispatch( aTargetURL, rArgs ); + } +} + +void ColumnsWidget::InsertColumns() +{ + if (nCol) + { + Sequence< PropertyValue > aArgs{ + comphelper::makePropertyValue("Columns", sal_Int16( nCol )), + comphelper::makePropertyValue("Modifier", sal_Int16( m_bMod1 ? KEY_MOD1 : 0 )) + }; + mxControl->InsertColumns(aArgs); + } +} + +SvxTableToolBoxControl::SvxTableToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext) + : PopupWindowController(rContext, nullptr, OUString()) +{ +} + +void SvxTableToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) +{ + PopupWindowController::initialize(rArguments); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId)); +} + +SvxTableToolBoxControl::~SvxTableToolBoxControl() +{ +} + +std::unique_ptr<WeldToolbarPopup> SvxTableToolBoxControl::weldPopupWindow() +{ + return std::make_unique<TableWindow>(this, m_pToolbar, m_aCommandURL); +} + +VclPtr<vcl::Window> SvxTableToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + bool bToolBox = getToolboxId(nId, &pToolBox); + + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<TableWindow>(this, pParent->GetFrameWeld(), m_aCommandURL)); + + mxInterimPopover->SetText(bToolBox ? pToolBox->GetItemText(nId) : OUString()); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +OUString SvxTableToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.TableToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxTableToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_TableToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire(new SvxTableToolBoxControl(rContext)); +} + +SvxColumnsToolBoxControl::SvxColumnsToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext) + : PopupWindowController(rContext, nullptr, OUString()) +{ +} + +void SvxColumnsToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) +{ + PopupWindowController::initialize(rArguments); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId)); +} + +SvxColumnsToolBoxControl::~SvxColumnsToolBoxControl() +{ +} + +std::unique_ptr<WeldToolbarPopup> SvxColumnsToolBoxControl::weldPopupWindow() +{ + return std::make_unique<ColumnsWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> SvxColumnsToolBoxControl::createVclPopupWindow(vcl::Window* pParent) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + bool bToolBox = getToolboxId(nId, &pToolBox); + + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<ColumnsWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->SetText(bToolBox ? pToolBox->GetItemText(nId) : OUString()); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +OUString SvxColumnsToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.ColumnsToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxColumnsToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_ColumnsToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire(new SvxColumnsToolBoxControl(rContext)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/lboxctrl.cxx b/svx/source/tbxctrls/lboxctrl.cxx new file mode 100644 index 0000000000..24b89e8ed6 --- /dev/null +++ b/svx/source/tbxctrls/lboxctrl.cxx @@ -0,0 +1,347 @@ +/* -*- 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/types.h> +#include <vcl/event.hxx> +#include <vcl/toolbox.hxx> +#include <sfx2/bindings.hxx> +#include <svtools/toolbarmenu.hxx> +#include <svx/dialmgr.hxx> +#include <lboxctrl.hxx> +#include <tools/urlobj.hxx> + +#include <svx/strings.hrc> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; + +class SvxPopupWindowListBox final : public WeldToolbarPopup +{ + rtl::Reference<SvxUndoRedoControl> m_xControl; + std::unique_ptr<weld::TreeView> m_xListBox; + std::unique_ptr<weld::TreeIter> m_xScratchIter; + int m_nSelectedRows; + int m_nVisRows; + + void UpdateRow(int nRow); + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(ActivateHdl, weld::TreeView&, bool); + DECL_LINK(MouseMoveHdl, const MouseEvent&, bool); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool); + +public: + SvxPopupWindowListBox(SvxUndoRedoControl* pControl, weld::Widget* pParent, + const std::vector<OUString>& rUndoRedoList); + + virtual void GrabFocus() override + { + m_xListBox->grab_focus(); + } +}; + +SvxPopupWindowListBox::SvxPopupWindowListBox(SvxUndoRedoControl* pControl, weld::Widget* pParent, + const std::vector<OUString>& rUndoRedoList) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingundoredo.ui", "FloatingUndoRedo") + , m_xControl(pControl) + , m_xListBox(m_xBuilder->weld_tree_view("treeview")) + , m_xScratchIter(m_xListBox->make_iterator()) + , m_nVisRows(10) +{ + m_xListBox->set_selection_mode(SelectionMode::Multiple); + + for (const OUString& s : rUndoRedoList) + m_xListBox->append_text(s); + if (!rUndoRedoList.empty()) + { + m_xListBox->set_cursor(0); + m_xListBox->select(0); + m_nSelectedRows = 1; + } + else + m_nSelectedRows = 0; + + m_xListBox->set_size_request(m_xListBox->get_approximate_digit_width() * 25, + m_xListBox->get_height_rows(m_nVisRows) + 2); + + m_xListBox->connect_row_activated(LINK(this, SvxPopupWindowListBox, ActivateHdl)); + m_xListBox->connect_mouse_move(LINK(this, SvxPopupWindowListBox, MouseMoveHdl)); + m_xListBox->connect_mouse_press(LINK(this, SvxPopupWindowListBox, MousePressHdl)); + m_xListBox->connect_mouse_release(LINK(this, SvxPopupWindowListBox, MouseReleaseHdl)); + m_xListBox->connect_key_press(LINK(this, SvxPopupWindowListBox, KeyInputHdl)); +} + +void SvxUndoRedoControl::SetInfo( sal_Int32 nCount ) +{ + TranslateId pId; + if (nCount == 1) + pId = getCommandURL() == ".uno:Undo" ? RID_SVXSTR_NUM_UNDO_ACTION : RID_SVXSTR_NUM_REDO_ACTION; + else + pId = getCommandURL() == ".uno:Undo" ? RID_SVXSTR_NUM_UNDO_ACTIONS : RID_SVXSTR_NUM_REDO_ACTIONS; + OUString aActionStr = SvxResId(pId); + OUString aText = aActionStr.replaceAll("$(ARG1)", OUString::number(nCount)); + SetText(aText); +} + +void SvxPopupWindowListBox::UpdateRow(int nRow) +{ + int nOldSelectedRows = m_nSelectedRows; + while (m_nSelectedRows < nRow + 1) + { + m_xListBox->select(m_nSelectedRows++); + } + while (m_nSelectedRows - 1 > nRow) + { + m_xListBox->unselect(--m_nSelectedRows); + } + if (nOldSelectedRows != m_nSelectedRows) + m_xControl->SetInfo(m_nSelectedRows); +} + +IMPL_LINK(SvxPopupWindowListBox, MouseMoveHdl, const MouseEvent&, rMEvt, bool) +{ + if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false)) + UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter)); + return false; +} + +IMPL_LINK(SvxPopupWindowListBox, MousePressHdl, const MouseEvent&, rMEvt, bool) +{ + if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false)) + { + UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter)); + ActivateHdl(*m_xListBox); + } + return true; +} + +IMPL_LINK(SvxPopupWindowListBox, MouseReleaseHdl, const MouseEvent&, rMEvt, bool) +{ + if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false)) + UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter)); + return true; +} + +IMPL_LINK(SvxPopupWindowListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + const vcl::KeyCode& rKCode = rKEvt.GetKeyCode(); + if (rKCode.GetModifier()) // only with no modifiers held + return true; + + sal_uInt16 nCode = rKCode.GetCode(); + + if (nCode == KEY_UP || nCode == KEY_PAGEUP || + nCode == KEY_DOWN || nCode == KEY_PAGEDOWN) + { + sal_Int32 nIndex = m_nSelectedRows - 1; + sal_Int32 nOrigIndex = nIndex; + sal_Int32 nCount = m_xListBox->n_children(); + + if (nCode == KEY_UP) + --nIndex; + else if (nCode == KEY_DOWN) + ++nIndex; + else if (nCode == KEY_PAGEUP) + nIndex -= m_nVisRows; + else if (nCode == KEY_PAGEDOWN) + nIndex += m_nVisRows; + + if (nIndex < 0) + nIndex = 0; + if (nIndex >= nCount) + nIndex = nCount - 1; + + if (nIndex != nOrigIndex) + { + m_xListBox->scroll_to_row(nIndex); + if (nIndex > nOrigIndex) + { + for (int i = nOrigIndex + 1; i <= nIndex; ++i) + UpdateRow(i); + } + else + { + for (int i = nOrigIndex - 1; i >= nIndex; --i) + UpdateRow(i); + } + } + return true; + } + + return false; +} + +IMPL_LINK_NOARG(SvxPopupWindowListBox, ActivateHdl, weld::TreeView&, bool) +{ + m_xControl->Do(m_nSelectedRows); + m_xControl->EndPopupMode(); + return true; +} + +void SvxUndoRedoControl::Do(sal_Int16 nCount) +{ + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); + if ( !xDispatchProvider.is() ) + return; + + css::util::URL aTargetURL; + Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) ); + aTargetURL.Complete = m_aCommandURL; + xTrans->parseStrict( aTargetURL ); + + Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); + if ( xDispatch.is() ) + { + INetURLObject aObj( m_aCommandURL ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(aObj.GetURLPath(), nCount) }; + xDispatch->dispatch(aTargetURL, aArgs); + } +} + +SvxUndoRedoControl::SvxUndoRedoControl(const css::uno::Reference<css::uno::XComponentContext>& rContext) + : PopupWindowController(rContext, nullptr, OUString()) +{ +} + +void SvxUndoRedoControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) +{ + PopupWindowController::initialize(rArguments); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + if (getModuleName() != "com.sun.star.script.BasicIDE") + { + if (pToolBox) + pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId)); + if (m_pToolbar) + aDefaultTooltip = m_pToolbar->get_item_tooltip_text(m_aCommandURL); + else + aDefaultTooltip = pToolBox->GetQuickHelpText(nId); + } +} + +SvxUndoRedoControl::~SvxUndoRedoControl() +{ +} + +void SvxUndoRedoControl::SetText(const OUString& rText) +{ + mxInterimPopover->SetText(rText); +} + +// XStatusListener +void SAL_CALL SvxUndoRedoControl::statusChanged(const css::frame::FeatureStateEvent& rEvent) +{ + if (rEvent.FeatureURL.Main == ".uno:GetUndoStrings" || rEvent.FeatureURL.Main == ".uno:GetRedoStrings") + { + css::uno::Sequence<OUString> aStrings; + rEvent.State >>= aStrings; + aUndoRedoList = comphelper::sequenceToContainer<std::vector<OUString>>(aStrings); + return; + } + + PopupWindowController::statusChanged(rEvent); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + if (!rEvent.IsEnabled) + { + if (m_pToolbar) + m_pToolbar->set_item_tooltip_text(m_aCommandURL, aDefaultTooltip); + else + pToolBox->SetQuickHelpText(nId, aDefaultTooltip); + return; + } + + OUString aQuickHelpText; + if (rEvent.State >>= aQuickHelpText) + { + if (m_pToolbar) + m_pToolbar->set_item_tooltip_text(m_aCommandURL, aQuickHelpText); + else + pToolBox->SetQuickHelpText(nId, aQuickHelpText); + } +} + +std::unique_ptr<WeldToolbarPopup> SvxUndoRedoControl::weldPopupWindow() +{ + if ( m_aCommandURL == ".uno:Undo" ) + updateStatus( ".uno:GetUndoStrings"); + else + updateStatus( ".uno:GetRedoStrings"); + + return std::make_unique<SvxPopupWindowListBox>(this, m_pToolbar, aUndoRedoList); +} + +VclPtr<vcl::Window> SvxUndoRedoControl::createVclPopupWindow( vcl::Window* pParent ) +{ + if ( m_aCommandURL == ".uno:Undo" ) + updateStatus( ".uno:GetUndoStrings"); + else + updateStatus( ".uno:GetRedoStrings"); + + auto xPopupWin = std::make_unique<SvxPopupWindowListBox>(this, pParent->GetFrameWeld(), aUndoRedoList); + + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::move(xPopupWin)); + + SetInfo(1); // count of selected rows + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +OUString SvxUndoRedoControl::getImplementationName() +{ + return "com.sun.star.comp.svx.UndoRedoToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxUndoRedoControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_UndoRedoToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire(new SvxUndoRedoControl(rContext)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/linectrl.cxx b/svx/source/tbxctrls/linectrl.cxx new file mode 100644 index 0000000000..3be0d011c6 --- /dev/null +++ b/svx/source/tbxctrls/linectrl.cxx @@ -0,0 +1,646 @@ +/* -*- 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 <tools/debug.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> +#include <sfx2/objsh.hxx> + +#include <svtools/toolbarmenu.hxx> +#include <svtools/popupwindowcontroller.hxx> +#include <svtools/valueset.hxx> + +#include <svx/strings.hrc> +#include <svx/svxids.hrc> +#include <helpids.h> + +#include <svx/drawitem.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlncapit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnstit.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xtable.hxx> +#include <svx/linectrl.hxx> +#include <svx/itemwin.hxx> +#include <svx/dialmgr.hxx> +#include <tbxcolorupdate.hxx> + +#include <memory> + +#include <comphelper/lok.hxx> +#include <comphelper/propertyvalue.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star; + +// For End Line Controller +#define MAX_LINES 12 + +SvxLineStyleToolBoxControl::SvxLineStyleToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) + : svt::PopupWindowController( rContext, nullptr, OUString() ) +{ + addStatusListener(".uno:LineDash"); +} + +SvxLineStyleToolBoxControl::~SvxLineStyleToolBoxControl() +{ +} + +void SAL_CALL SvxLineStyleToolBoxControl::statusChanged( const frame::FeatureStateEvent& rEvent ) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + if ( rEvent.FeatureURL.Complete == m_aCommandURL ) + { + if (m_pToolbar) + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + else + pToolBox->EnableItem( nId, rEvent.IsEnabled ); + } + + m_xBtnUpdater->Update(rEvent); + + SfxObjectShell* pSh = SfxObjectShell::Current(); + if (!pSh) + return; + + const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST ); + if (!pItem) + return; + + XDashListRef xList = pItem->GetDashList(); + int nIndex = m_xBtnUpdater->GetStyleIndex(); + bool bNoneLineStyle = false; + switch (nIndex) + { + case -1: + case 0: + { + BitmapEx aEmpty(xList->GetBitmapForUISolidLine()); + aEmpty.Erase(Application::GetSettings().GetStyleSettings().GetFieldColor()); + if (m_pToolbar) + { + Graphic aGraf(aEmpty); + m_pToolbar->set_item_image(m_aCommandURL, aGraf.GetXGraphic()); + } + else + pToolBox->SetItemImage(nId, Image(aEmpty)); + bNoneLineStyle = true; + break; + } + case 1: + if (m_pToolbar) + { + Graphic aGraf(xList->GetBitmapForUISolidLine()); + m_pToolbar->set_item_image(m_aCommandURL, aGraf.GetXGraphic()); + } + else + pToolBox->SetItemImage(nId, Image(xList->GetBitmapForUISolidLine())); + break; + default: + if (m_pToolbar) + { + Graphic aGraf(xList->GetUiBitmap(nIndex - 2)); + m_pToolbar->set_item_image(m_aCommandURL, aGraf.GetXGraphic()); + } + else + pToolBox->SetItemImage(nId, Image(xList->GetUiBitmap(nIndex - 2))); + break; + } + if (m_aLineStyleIsNoneFunction) + m_aLineStyleIsNoneFunction(bNoneLineStyle); +} + +void SAL_CALL SvxLineStyleToolBoxControl::execute(sal_Int16 /*KeyModifier*/) +{ + if (m_pToolbar) + { + // Toggle the popup also when toolbutton is activated + m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL)); + } + else + { + // Open the popup also when Enter key is pressed. + createPopupWindow(); + } +} + +void SvxLineStyleToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments ) +{ + svt::PopupWindowController::initialize( rArguments ); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + { + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); + } + + m_xBtnUpdater.reset(new svx::ToolboxButtonLineStyleUpdater); +} + +void SvxLineStyleToolBoxControl::setLineStyleSelectFunction(const LineStyleSelectFunction& rLineStyleSelectFunction) +{ + m_aLineStyleSelectFunction = rLineStyleSelectFunction; +} + +void SvxLineStyleToolBoxControl::setLineStyleIsNoneFunction(const LineStyleIsNoneFunction& rLineStyleIsNoneFunction) +{ + m_aLineStyleIsNoneFunction = rLineStyleIsNoneFunction; +} + +void SvxLineStyleToolBoxControl::dispatchLineStyleCommand(const OUString& rCommand, const Sequence<PropertyValue>& rArgs) +{ + if (m_aLineStyleSelectFunction && m_aLineStyleSelectFunction(rCommand, rArgs[0].Value)) + return; + + dispatchCommand(rCommand, rArgs); +} + +std::unique_ptr<WeldToolbarPopup> SvxLineStyleToolBoxControl::weldPopupWindow() +{ + return std::make_unique<SvxLineBox>(this, m_pToolbar, m_xBtnUpdater->GetStyleIndex()); +} + +VclPtr<vcl::Window> SvxLineStyleToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<SvxLineBox>(this, pParent->GetFrameWeld(), m_xBtnUpdater->GetStyleIndex())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +OUString SvxLineStyleToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.LineStyleToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxLineStyleToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_LineStyleToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxLineStyleToolBoxControl( rContext ) ); +} + +namespace { + +class SvxLineEndToolBoxControl final : public svt::PopupWindowController +{ +public: + explicit SvxLineEndToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ); + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence<css::uno::Any>& rArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override; + +private: + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; +}; + +class SvxLineEndWindow final : public WeldToolbarPopup +{ +private: + XLineEndListRef mpLineEndList; + rtl::Reference<SvxLineEndToolBoxControl> mxControl; + std::unique_ptr<ValueSet> mxLineEndSet; + std::unique_ptr<weld::CustomWeld> mxLineEndSetWin; + sal_uInt16 mnLines; + Size maBmpSize; + + DECL_LINK( SelectHdl, ValueSet*, void ); + void FillValueSet(); + void SetSize(); + + virtual void GrabFocus() override + { + mxLineEndSet->GrabFocus(); + } + +public: + SvxLineEndWindow(SvxLineEndToolBoxControl* pControl, weld::Widget* pParent); + virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; +}; + +} + +constexpr sal_uInt16 gnCols = 2; + +SvxLineEndWindow::SvxLineEndWindow(SvxLineEndToolBoxControl* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatinglineend.ui", "FloatingLineEnd") + , mxControl(pControl) + , mxLineEndSet(new ValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true))) + , mxLineEndSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLineEndSet)) + , mnLines(12) +{ + mxLineEndSet->SetStyle(mxLineEndSet->GetStyle() | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT); + mxLineEndSet->SetHelpId(HID_POPUP_LINEEND_CTRL); + m_xTopLevel->set_help_id(HID_POPUP_LINEEND); + + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if ( pDocSh ) + { + const SfxPoolItem* pItem = pDocSh->GetItem( SID_LINEEND_LIST ); + if( pItem ) + mpLineEndList = static_cast<const SvxLineEndListItem*>( pItem )->GetLineEndList(); + } + DBG_ASSERT( mpLineEndList.is(), "LineEndList not found" ); + + mxLineEndSet->SetSelectHdl( LINK( this, SvxLineEndWindow, SelectHdl ) ); + mxLineEndSet->SetColCount( gnCols ); + + // ValueSet fill with entries of LineEndList + FillValueSet(); + + AddStatusListener( ".uno:LineEndListState"); +} + +IMPL_LINK_NOARG(SvxLineEndWindow, SelectHdl, ValueSet*, void) +{ + std::unique_ptr<XLineEndItem> pLineEndItem; + std::unique_ptr<XLineStartItem> pLineStartItem; + sal_uInt16 nId = mxLineEndSet->GetSelectedItemId(); + + if( nId == 1 ) + { + pLineStartItem.reset(new XLineStartItem()); + } + else if( nId == 2 ) + { + pLineEndItem.reset(new XLineEndItem()); + } + else if( nId % 2 ) // beginning of line + { + const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd( (nId - 1) / 2 - 1 ); + pLineStartItem.reset(new XLineStartItem(pEntry->GetName(), pEntry->GetLineEnd())); + } + else // end of line + { + const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd( nId / 2 - 2 ); + pLineEndItem.reset(new XLineEndItem(pEntry->GetName(), pEntry->GetLineEnd())); + } + + OUString name; + Any a; + + if ( pLineStartItem ) + { + name = "LineStart"; + pLineStartItem->QueryValue( a ); + } + else + { + name = "LineEnd"; + pLineEndItem->QueryValue( a ); + } + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(name, a) }; + + /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + mxLineEndSet->SetNoSelection(); + + mxControl->dispatchCommand(mxControl->getCommandURL(), aArgs); + + mxControl->EndPopupMode(); +} + +void SvxLineEndWindow::FillValueSet() +{ + if( !mpLineEndList.is() ) + return; + + ScopedVclPtrInstance< VirtualDevice > pVD; + + tools::Long nCount = mpLineEndList->Count(); + + // First entry: no line end. + // An entry is temporarily added to get the UI bitmap + basegfx::B2DPolyPolygon aNothing; + mpLineEndList->Insert(std::make_unique<XLineEndEntry>(aNothing, + comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE) + : SvxResId(RID_SVXSTR_NONE))); + const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd(nCount); + BitmapEx aBmp = mpLineEndList->GetUiBitmap( nCount ); + OSL_ENSURE( !aBmp.IsEmpty(), "UI bitmap was not created" ); + + maBmpSize = aBmp.GetSizePixel(); + pVD->SetOutputSizePixel( maBmpSize, false ); + maBmpSize.setWidth( maBmpSize.Width() / 2 ); + Point aPt0( 0, 0 ); + Point aPt1( maBmpSize.Width(), 0 ); + + pVD->DrawBitmapEx( Point(), aBmp ); + mxLineEndSet->InsertItem(1, Image(pVD->GetBitmapEx(aPt0, maBmpSize)), pEntry->GetName()); + mxLineEndSet->InsertItem(2, Image(pVD->GetBitmapEx(aPt1, maBmpSize)), pEntry->GetName()); + + mpLineEndList->Remove(nCount); + + for( tools::Long i = 0; i < nCount; i++ ) + { + pEntry = mpLineEndList->GetLineEnd( i ); + DBG_ASSERT( pEntry, "Could not access LineEndEntry" ); + aBmp = mpLineEndList->GetUiBitmap( i ); + OSL_ENSURE( !aBmp.IsEmpty(), "UI bitmap was not created" ); + + pVD->DrawBitmapEx( aPt0, aBmp ); + mxLineEndSet->InsertItem(static_cast<sal_uInt16>((i+1)*2L+1), + Image(pVD->GetBitmapEx(aPt0, maBmpSize)), pEntry->GetName()); + mxLineEndSet->InsertItem(static_cast<sal_uInt16>((i+2)*2L), + Image(pVD->GetBitmapEx(aPt1, maBmpSize)), pEntry->GetName()); + } + mnLines = std::min( static_cast<sal_uInt16>(nCount + 1), sal_uInt16(MAX_LINES) ); + mxLineEndSet->SetLineCount( mnLines ); + + SetSize(); +} + +void SvxLineEndWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + if ( rEvent.FeatureURL.Complete != ".uno:LineEndListState" ) + return; + + // The list of line ends (LineEndList) has changed + css::uno::Reference< css::uno::XWeak > xWeak; + if ( rEvent.State >>= xWeak ) + { + mpLineEndList.set( static_cast< XLineEndList* >( xWeak.get() ) ); + DBG_ASSERT( mpLineEndList.is(), "LineEndList not found" ); + + mxLineEndSet->Clear(); + FillValueSet(); + } +} + +void SvxLineEndWindow::SetSize() +{ + sal_uInt16 nItemCount = mxLineEndSet->GetItemCount(); + sal_uInt16 nMaxLines = nItemCount / gnCols; + + WinBits nBits = mxLineEndSet->GetStyle(); + if ( mnLines == nMaxLines ) + nBits &= ~WB_VSCROLL; + else + nBits |= WB_VSCROLL; + mxLineEndSet->SetStyle( nBits ); + + Size aSize( maBmpSize ); + aSize.AdjustWidth(6 ); + aSize.AdjustHeight(6 ); + aSize = mxLineEndSet->CalcWindowSizePixel( aSize ); + mxLineEndSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); + mxLineEndSet->SetOutputSizePixel(aSize); +} + +SvxLineEndToolBoxControl::SvxLineEndToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) + : svt::PopupWindowController( rContext, nullptr, OUString() ) +{ +} + +void SAL_CALL SvxLineEndToolBoxControl::execute(sal_Int16 /*KeyModifier*/) +{ + if (m_pToolbar) + { + // Toggle the popup also when toolbutton is activated + m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL)); + } + else + { + // Open the popup also when Enter key is pressed. + createPopupWindow(); + } +} + +void SvxLineEndToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments ) +{ + svt::PopupWindowController::initialize( rArguments ); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if ( getToolboxId( nId, &pToolBox ) ) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +std::unique_ptr<WeldToolbarPopup> SvxLineEndToolBoxControl::weldPopupWindow() +{ + return std::make_unique<SvxLineEndWindow>(this, m_pToolbar); +} + +VclPtr<vcl::Window> SvxLineEndToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<SvxLineEndWindow>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + mxInterimPopover->SetText(SvxResId(RID_SVXSTR_LINEEND)); + + return mxInterimPopover; +} + +OUString SvxLineEndToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.LineEndToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxLineEndToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_LineEndToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxLineEndToolBoxControl( rContext ) ); +} + +SvxLineBox::SvxLineBox(SvxLineStyleToolBoxControl* pControl, weld::Widget* pParent, int nInitialIndex) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatinglinestyle.ui", "FloatingLineStyle") + , mxControl(pControl) + , mxLineStyleSet(new ValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true))) + , mxLineStyleSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLineStyleSet)) +{ + mxLineStyleSet->SetStyle(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT); + + FillControl(); + + mxLineStyleSet->SelectItem(nInitialIndex + 1); + + mxLineStyleSet->SetSelectHdl( LINK( this, SvxLineBox, SelectHdl ) ); +} + +void SvxLineBox::GrabFocus() +{ + mxLineStyleSet->GrabFocus(); +} + +SvxLineBox::~SvxLineBox() +{ +} + +// Fills the listbox (provisional) with strings + +void SvxLineBox::Fill( const XDashListRef &pList ) +{ + mxLineStyleSet->Clear(); + + if( !pList.is() ) + return; + + // entry for 'none' + mxLineStyleSet->InsertItem(1, Image(), pList->GetStringForUiNoLine()); + + // entry for solid line + auto aBmp = pList->GetBitmapForUISolidLine(); + Size aBmpSize = aBmp.GetSizePixel(); + mxLineStyleSet->InsertItem(2, Image(aBmp), pList->GetStringForUiSolidLine()); + + // entries for dashed lines + tools::Long nCount = pList->Count(); + for( tools::Long i = 0; i < nCount; i++ ) + { + const XDashEntry* pEntry = pList->GetDash(i); + const BitmapEx aBitmap = pList->GetUiBitmap(i); + + mxLineStyleSet->InsertItem(i + 3, Image(aBitmap), pEntry->GetName()); + } + + sal_uInt16 nLines = std::min( static_cast<sal_uInt16>(nCount + 2), sal_uInt16(MAX_LINES) ); + mxLineStyleSet->SetLineCount(nLines); + + WinBits nBits = mxLineStyleSet->GetStyle(); + if ( nLines == mxLineStyleSet->GetItemCount() ) + nBits &= ~WB_VSCROLL; + else + nBits |= WB_VSCROLL; + mxLineStyleSet->SetStyle( nBits ); + + Size aSize(aBmpSize); + aSize.AdjustWidth(6); + aSize.AdjustHeight(6); + aSize = mxLineStyleSet->CalcWindowSizePixel(aSize); + mxLineStyleSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); + mxLineStyleSet->SetOutputSizePixel(aSize); +} + +IMPL_LINK_NOARG(SvxLineBox, SelectHdl, ValueSet*, void) +{ + drawing::LineStyle eXLS; + sal_Int32 nPos = mxLineStyleSet->GetSelectedItemId(); + --nPos; // ids start at 1, get the pos of the id + + switch ( nPos ) + { + case 0: + eXLS = drawing::LineStyle_NONE; + break; + + case 1: + eXLS = drawing::LineStyle_SOLID; + break; + + default: + { + eXLS = drawing::LineStyle_DASH; + const SfxObjectShell* pObjSh = SfxObjectShell::Current(); + if (nPos != -1 && pObjSh && pObjSh->GetItem(SID_DASH_LIST)) + { + // LineDashItem will only be sent if it also has a dash. + // Notify cares! + SvxDashListItem const * pItem = pObjSh->GetItem( SID_DASH_LIST ); + const XDashEntry* pEntry = pItem->GetDashList()->GetDash(nPos - 2); + XLineDashItem aLineDashItem(pEntry->GetName(), pEntry->GetDash()); + + Any a; + aLineDashItem.QueryValue ( a ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineDash", a) }; + mxControl->dispatchLineStyleCommand(".uno:LineDash", aArgs); + + // set also cap style using the toolbar line style selection popup + css::drawing::DashStyle eStyle = pEntry->GetDash().GetDashStyle(); + XLineCapItem aLineCapItem( + eStyle == drawing::DashStyle_RECT || eStyle == drawing::DashStyle_RECTRELATIVE + ? css::drawing::LineCap_BUTT + : css::drawing::LineCap_ROUND ); + aLineCapItem.QueryValue ( a ); + Sequence< PropertyValue > aArgs2{ comphelper::makePropertyValue("LineCap", a) }; + mxControl->dispatchLineStyleCommand(".uno:LineCap", aArgs2); + } + } + break; + } + + XLineStyleItem aLineStyleItem( eXLS ); + Any a; + aLineStyleItem.QueryValue ( a ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("XLineStyle", a) }; + mxControl->dispatchLineStyleCommand(".uno:XLineStyle", aArgs); + + mxControl->EndPopupMode(); +} + +void SvxLineBox::FillControl() +{ + SfxObjectShell* pSh = SfxObjectShell::Current(); + if (pSh) + { + const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST ); + if (pItem) + Fill(pItem->GetDashList()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/linemetricbox.hxx b/svx/source/tbxctrls/linemetricbox.hxx new file mode 100644 index 0000000000..81f19a1c64 --- /dev/null +++ b/svx/source/tbxctrls/linemetricbox.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#pragma once + +#include <vcl/InterimItemWindow.hxx> +#include <com/sun/star/frame/XFrame.hpp> + +class XLineWidthItem; + +class SvxMetricField final : public InterimItemWindow +{ +private: + std::unique_ptr<weld::MetricSpinButton> m_xWidget; + int nCurValue; + MapUnit eDestPoolUnit; + FieldUnit eDlgUnit; + css::uno::Reference< css::frame::XFrame > mxFrame; + + DECL_LINK(ModifyHdl, weld::MetricSpinButton&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(FocusInHdl, weld::Widget&, void); + + static void ReleaseFocus_Impl(); + + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + +public: + SvxMetricField( vcl::Window* pParent, + const css::uno::Reference< css::frame::XFrame >& rFrame ); + virtual void dispose() override; + virtual ~SvxMetricField() override; + + void Update( const XLineWidthItem* pItem ); + void SetDestCoreUnit( MapUnit eUnit ); + void RefreshDlgUnit(); + + void set_sensitive(bool bSensitive); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/linewidthctrl.cxx b/svx/source/tbxctrls/linewidthctrl.cxx new file mode 100644 index 0000000000..166f4bb451 --- /dev/null +++ b/svx/source/tbxctrls/linewidthctrl.cxx @@ -0,0 +1,101 @@ +/* -*- 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 <vcl/toolbox.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <svl/itempool.hxx> +#include <svx/svxids.hrc> +#include <svx/xlnwtit.hxx> +#include <svx/linectrl.hxx> +#include "linemetricbox.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star; + +SFX_IMPL_TOOLBOX_CONTROL( SvxLineWidthToolBoxControl, XLineWidthItem ); + +SvxLineWidthToolBoxControl::SvxLineWidthToolBoxControl( + sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + addStatusListener( ".uno:MetricUnit"); +} + + +SvxLineWidthToolBoxControl::~SvxLineWidthToolBoxControl() +{ +} + +void SvxLineWidthToolBoxControl::StateChangedAtToolBoxControl( + sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + SvxMetricField* pFld = static_cast<SvxMetricField*>( + GetToolBox().GetItemWindow( GetId() )); + DBG_ASSERT( pFld, "Window not found" ); + + if ( nSID == SID_ATTR_METRIC ) + { + pFld->RefreshDlgUnit(); + } + else + { + if ( eState == SfxItemState::DISABLED ) + { + pFld->set_sensitive(false); + } + else + { + pFld->set_sensitive(true); + + if ( eState == SfxItemState::DEFAULT ) + { + DBG_ASSERT( dynamic_cast<const XLineWidthItem*>( pState) != nullptr, "wrong ItemType" ); + + pFld->SetDestCoreUnit(GetCoreMetric()); + + pFld->Update( static_cast<const XLineWidthItem*>(pState) ); + } + else + pFld->Update( nullptr ); + } + } +} + +MapUnit SvxLineWidthToolBoxControl::GetCoreMetric() +{ + SfxObjectShell* pSh = SfxObjectShell::Current(); + SfxItemPool& rPool = pSh ? pSh->GetPool() : SfxGetpApp()->GetPool(); + sal_uInt16 nWhich = rPool.GetWhich(SID_ATTR_LINE_WIDTH); + return rPool.GetMetric(nWhich); +} + +VclPtr<InterimItemWindow> SvxLineWidthToolBoxControl::CreateItemWindow(vcl::Window *pParent) +{ + VclPtr<SvxMetricField> pWindow = VclPtr<SvxMetricField>::Create(pParent, m_xFrame); + pWindow->Show(); + + return pWindow; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx new file mode 100644 index 0000000000..9a3669aac5 --- /dev/null +++ b/svx/source/tbxctrls/tbcontrl.cxx @@ -0,0 +1,4523 @@ +/* -*- 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 <utility> + +#include <comphelper/configurationlistener.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/propertyvalue.hxx> +#include <tools/color.hxx> +#include <svl/numformat.hxx> +#include <svl/poolitem.hxx> +#include <svl/itemset.hxx> +#include <svl/itempool.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/event.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/customweld.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/weldutils.hxx> +#include <svtools/valueset.hxx> +#include <svtools/ctrlbox.hxx> +#include <svl/style.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/borderhelper.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <sfx2/tbxctrl.hxx> +#include <sfx2/tplpitem.hxx> +#include <sfx2/sfxstatuslistener.hxx> +#include <sfx2/viewsh.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/virdev.hxx> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <svx/strings.hrc> +#include <svx/svxids.hrc> +#include <helpids.h> +#include <sfx2/sidebar/Sidebar.hxx> +#include <svx/xtable.hxx> +#include <editeng/editids.hrc> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/flstitem.hxx> +#include <editeng/lineitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/svxfont.hxx> +#include <editeng/cmapitem.hxx> +#include <svx/colorwindow.hxx> +#include <svx/colorbox.hxx> +#include <svx/tbcontrl.hxx> +#include <svx/dialmgr.hxx> +#include <svx/PaletteManager.hxx> +#include <memory> + +#include <tbxcolorupdate.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> +#include <svx/xdef.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> +#include <svl/currencytable.hxx> +#include <svtools/langtab.hxx> +#include <cppu/unotype.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <officecfg/Office/Common.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <o3tl/typed_flags_set.hxx> +#include <bitmaps.hlst> +#include <sal/log.hxx> +#include <unotools/collatorwrapper.hxx> + +#include <comphelper/lok.hxx> +#include <tools/json_writer.hxx> + +#include <editeng/editeng.hxx> + +#define MAX_MRU_FONTNAME_ENTRIES 5 + +#define COMBO_WIDTH_IN_CHARS 18 + +#define MAX_MRU_CURRENCIES 5 + +#define INVALID_CURRENCY sal_uInt16(-2) + +// namespaces +using namespace ::editeng; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace +{ +struct ScriptInfo +{ + tools::Long textWidth; + SvtScriptType scriptType; + sal_Int32 changePos; + ScriptInfo(SvtScriptType scrptType, sal_Int32 position) + : textWidth(0) + , scriptType(scrptType) + , changePos(position) + { + } +}; + +class SvxStyleBox_Base +{ +public: + SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, OUString rCommand, SfxStyleFamily eFamily, + const Reference<XFrame>& _xFrame, OUString aClearFormatKey, + OUString aMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl); + + virtual ~SvxStyleBox_Base() + { + } + + void SetFamily( SfxStyleFamily eNewFamily ); + + void SetDefaultStyle( const OUString& rDefault ) { sDefaultStyle = rDefault; } + + int get_count() const { return m_xWidget->get_count(); } + OUString get_text(int nIndex) const { return m_xWidget->get_text(nIndex); } + OUString get_active_text() const { return m_xWidget->get_active_text(); } + + void append_text(const OUString& rStr) + { + OUString sId(OUString::number(m_xWidget->get_count())); + m_xWidget->append(sId, rStr); + } + + void insert_separator(int pos, const OUString& rId) + { + m_xWidget->insert_separator(pos, rId); + } + + void set_active_or_entry_text(const OUString& rText) + { + const int nFound = m_xWidget->find_text(rText); + if (nFound != -1) + m_xWidget->set_active(nFound); + else + m_xWidget->set_entry_text(rText); + } + + void set_active(int nActive) + { + m_xWidget->set_active(nActive); + } + + void freeze() + { + m_xWidget->freeze(); + } + + void save_value() + { + m_xWidget->save_value(); + } + + void clear() + { + m_xWidget->clear(); + m_nMaxUserDrawFontWidth = 0; + } + + void thaw() + { + m_xWidget->thaw(); + } + + virtual bool DoKeyInput(const KeyEvent& rKEvt); + +private: + std::optional<SvxFont> m_oFont; + std::optional<SvxFont> m_oCJKFont; + std::optional<SvxFont> m_oCTLFont; + + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(ActivateHdl, weld::ComboBox&, bool); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void); + DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void); + DECL_LINK(CustomGetSizeHdl, OutputDevice&, Size); + + /// Calculate the optimal width of the dropdown. Very expensive operation, triggers lots of font measurement. + void CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext); + + void Select(bool bNonTravelSelect); + + tools::Rectangle CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio = 1); + +protected: + SvxStyleToolBoxControl& m_rCtrl; + + std::unique_ptr<weld::Builder> m_xMenuBuilder; + std::unique_ptr<weld::Menu> m_xMenu; + std::unique_ptr<weld::ComboBox> m_xWidget; + + SfxStyleFamily eStyleFamily; + int m_nMaxUserDrawFontWidth; + int m_nLastItemWithMenu; + bool bRelease; + Reference< XFrame > m_xFrame; + OUString m_aCommand; + OUString aClearFormatKey; + OUString aMoreKey; + OUString sDefaultStyle; + bool bInSpecialMode; + + void ReleaseFocus(); + static Color TestColorsVisible(const Color &FontCol, const Color &BackCol); + void UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges); + void SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected); + DECL_LINK(MenuSelectHdl, const OUString&, void); + DECL_STATIC_LINK(SvxStyleBox_Base, ShowMoreHdl, void*, void); +}; + +class SvxStyleBox_Impl final : public InterimItemWindow + , public SvxStyleBox_Base +{ +public: + SvxStyleBox_Impl(vcl::Window* pParent, const OUString& rCommand, SfxStyleFamily eFamily, + const Reference< XFrame >& _xFrame,const OUString& rClearFormatKey, const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl); + + virtual ~SvxStyleBox_Impl() override + { + disposeOnce(); + } + + virtual void dispose() override + { + m_xWidget.reset(); + m_xMenu.reset(); + m_xMenuBuilder.reset(); + InterimItemWindow::dispose(); + } + + virtual bool DoKeyInput(const KeyEvent& rKEvt) override; + +private: + + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + void SetOptimalSize(); +}; + +class SvxFontNameBox_Impl; +class SvxFontNameBox_Base; + +class SvxFontNameToolBoxControl final : public cppu::ImplInheritanceHelper<svt::ToolboxController, + css::lang::XServiceInfo> +{ +public: + SvxFontNameToolBoxControl(); + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + + // XToolbarController + virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +private: + VclPtr<SvxFontNameBox_Impl> m_xVclBox; + std::unique_ptr<SvxFontNameBox_Base> m_xWeldBox; + SvxFontNameBox_Base* m_pBox; +}; + +class FontOptionsListener final : public comphelper::ConfigurationListenerProperty<bool> +{ +private: + SvxFontNameBox_Base& m_rBox; + + virtual void setProperty(const css::uno::Any &rProperty) override; +public: + FontOptionsListener(const rtl::Reference<comphelper::ConfigurationListener>& rListener, const OUString& rProp, SvxFontNameBox_Base& rBox) + : comphelper::ConfigurationListenerProperty<bool>(rListener, rProp) + , m_rBox(rBox) + { + } +}; + +class SvxFontNameBox_Base +{ +private: + rtl::Reference<comphelper::ConfigurationListener> m_xListener; + FontOptionsListener m_aWYSIWYG; + FontOptionsListener m_aHistory; + +protected: + SvxFontNameToolBoxControl& m_rCtrl; + + std::unique_ptr<FontNameBox> m_xWidget; + const FontList* pFontList; + ::std::unique_ptr<FontList> m_aOwnFontList; + vcl::Font aCurFont; + sal_uInt16 nFtCount; + bool bRelease; + Reference< XFrame > m_xFrame; + bool mbCheckingUnknownFont; + bool mbDropDownActive; + + void ReleaseFocus_Impl(); + + void Select(bool bNonTravelSelect); + + void EndPreview() + { + Sequence< PropertyValue > aArgs; + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, ".uno:CharEndPreviewFontName", aArgs); + } + + bool CheckFontIsAvailable(std::u16string_view fontname); + void CheckAndMarkUnknownFont(); + +public: + SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const Reference<XFrame>& rFrame, + SvxFontNameToolBoxControl& rCtrl); + virtual ~SvxFontNameBox_Base() + { + m_xListener->dispose(); + } + + void FillList(); + void Update( const css::awt::FontDescriptor* pFontDesc ); + sal_uInt16 GetListCount() const { return nFtCount; } + void Clear() { m_xWidget->clear(); nFtCount = 0; } + void Fill( const FontList* pList ) + { + m_xWidget->Fill(pList); + nFtCount = pList->GetFontNameCount(); + } + + void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); } + + virtual void set_sensitive(bool bSensitive) + { + m_xWidget->set_sensitive(bSensitive); + } + + void set_active_or_entry_text(const OUString& rText); + + void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent); + + virtual bool DoKeyInput(const KeyEvent& rKEvt); + + void EnableControls(); + + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(ActivateHdl, weld::ComboBox&, bool); + DECL_LINK(FocusInHdl, weld::Widget&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + DECL_LINK(PopupToggledHdl, weld::ComboBox&, void); + DECL_LINK(LivePreviewHdl, const FontMetric&, void); + DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void); +}; + +void FontOptionsListener::setProperty(const css::uno::Any &rProperty) +{ + comphelper::ConfigurationListenerProperty<bool>::setProperty(rProperty); + m_rBox.EnableControls(); +} + +class SvxFontNameBox_Impl final : public InterimItemWindow + , public SvxFontNameBox_Base +{ +private: + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void GetFocus() override + { + if (m_xWidget) + m_xWidget->grab_focus(); + InterimItemWindow::GetFocus(); + } + + void SetOptimalSize(); + + virtual bool DoKeyInput(const KeyEvent& rKEvt) override; + +public: + SvxFontNameBox_Impl(vcl::Window* pParent, + const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl); + + virtual void dispose() override + { + m_xWidget.reset(); + InterimItemWindow::dispose(); + } + + virtual ~SvxFontNameBox_Impl() override + { + disposeOnce(); + } + + virtual Reference< css::accessibility::XAccessible > CreateAccessible() override; + + virtual void set_sensitive(bool bSensitive) override + { + m_xWidget->set_sensitive(bSensitive); + if (bSensitive) + InterimItemWindow::Enable(); + else + InterimItemWindow::Disable(); + } +}; + + +// SelectHdl needs the Modifiers, get them in MouseButtonUp +class SvxFrmValueSet_Impl final : public ValueSet +{ +private: + sal_uInt16 nModifier; + + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override + { + nModifier = rMEvt.GetModifier(); + return ValueSet::MouseButtonUp(rMEvt); + } + +public: + SvxFrmValueSet_Impl() + : ValueSet(nullptr) + , nModifier(0) + { + } + sal_uInt16 GetModifier() const {return nModifier;} +}; + +} + +namespace { + +class SvxFrameToolBoxControl; + +class SvxFrameWindow_Impl final : public WeldToolbarPopup +{ +private: + rtl::Reference<SvxFrameToolBoxControl> mxControl; + std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet; + std::unique_ptr<weld::CustomWeld> mxFrameSetWin; + std::vector<std::pair<BitmapEx, OUString>> aImgVec; + bool bParagraphMode; + bool m_bIsWriter; + + void InitImageList(); + void CalcSizeValueSet(); + DECL_LINK( SelectHdl, ValueSet*, void ); + + void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem); + void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem); + +public: + SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent); + virtual void GrabFocus() override + { + mxFrameSet->GrabFocus(); + } + + virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; +}; + +class SvxFrameToolBoxControl : public svt::PopupWindowController +{ +public: + explicit SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext ); + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override; +private: + virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override; +}; + + class LineListBox final : public ValueSet + { + public: + typedef Color (*ColorFunc)(Color); + typedef Color (*ColorDistFunc)(Color, Color); + + LineListBox(); + + /** Set the width in Twips */ + Size SetWidth( tools::Long nWidth ) + { + tools::Long nOldWidth = m_nWidth; + m_nWidth = nWidth; + return UpdateEntries( nOldWidth ); + } + + void SetNone( const OUString& sNone ) + { + m_sNone = sNone; + } + + /** Insert a listbox entry with all widths in Twips. */ + void InsertEntry(const BorderWidthImpl& rWidthImpl, + SvxBorderLineStyle nStyle, tools::Long nMinWidth = 0, + ColorFunc pColor1Fn = &sameColor, + ColorFunc pColor2Fn = &sameColor, + ColorDistFunc pColorDistFn = &sameDistColor); + + SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const; + + SvxBorderLineStyle GetSelectEntryStyle() const; + + void SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; } + + const Color& GetColor() const { return aColor; } + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + private: + + void ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, + Color nColor1, Color nColor2, Color nColorDist, + SvxBorderLineStyle nStyle, BitmapEx& rBmp); + + void UpdatePaintLineColor(); // returns sal_True if maPaintCol has changed + + Size UpdateEntries( tools::Long nOldWidth ); + sal_Int32 GetStylePos( sal_Int32 nListPos, tools::Long nWidth ); + + const Color& GetPaintColor() const + { + return maPaintCol; + } + + Color GetColorLine1( sal_Int32 nPos ); + Color GetColorLine2( sal_Int32 nPos ); + Color GetColorDist( sal_Int32 nPos ); + + LineListBox( const LineListBox& ) = delete; + LineListBox& operator =( const LineListBox& ) = delete; + + std::vector<std::unique_ptr<ImpLineListData>> m_vLineList; + tools::Long m_nWidth; + OUString m_sNone; + ScopedVclPtr<VirtualDevice> aVirDev; + Size aTxtSize; + Color const aColor; + Color maPaintCol; + FieldUnit eSourceUnit; + }; + + SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const + { + SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID; + size_t nPos = GetSelectItemPos(); + if (nPos != VALUESET_ITEM_NOTFOUND) + { + if (!m_sNone.isEmpty()) + --nPos; + nStyle = GetEntryStyle( nPos ); + } + + return nStyle; + } + + void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance, + Color aColor1, Color aColor2, Color aColorDist, + SvxBorderLineStyle nStyle, BitmapEx& rBmp ) + { + auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS; + Size aSize(nMinWidth, aTxtSize.Height()); + aSize.AdjustWidth( -(aTxtSize.Width()) ); + aSize.AdjustWidth( -6 ); + + // SourceUnit to Twips + if ( eSourceUnit == FieldUnit::POINT ) + { + nLine1 /= 5; + nLine2 /= 5; + nDistance /= 5; + } + + // Paint the lines + aSize = aVirDev->PixelToLogic( aSize ); + tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height(); + sal_uInt32 n1 = nLine1; + sal_uInt32 n2 = nLine2; + tools::Long nDist = nDistance; + n1 += nPix-1; + n1 -= n1%nPix; + if ( n2 ) + { + nDist += nPix-1; + nDist -= nDist%nPix; + n2 += nPix-1; + n2 -= n2%nPix; + } + tools::Long nVirHeight = n1+nDist+n2; + if ( nVirHeight > aSize.Height() ) + aSize.setHeight( nVirHeight ); + // negative width should not be drawn + if ( aSize.Width() <= 0 ) + return; + + Size aVirSize = aVirDev->LogicToPixel( aSize ); + if ( aVirDev->GetOutputSizePixel() != aVirSize ) + aVirDev->SetOutputSizePixel( aVirSize ); + aVirDev->SetFillColor( aColorDist ); + aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) ); + + aVirDev->SetFillColor( aColor1 ); + + double y1 = double( n1 ) / 2; + svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle ); + + if ( n2 ) + { + double y2 = n1 + nDist + double( n2 ) / 2; + aVirDev->SetFillColor( aColor2 ); + svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID ); + } + rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) ); + } + + LineListBox::LineListBox() + : ValueSet(nullptr) + , m_nWidth( 5 ) + , aVirDev(VclPtr<VirtualDevice>::Create()) + , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()) + , maPaintCol(COL_BLACK) + , eSourceUnit(FieldUnit::POINT) + { + aVirDev->SetLineColor(); + aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) ); + } + + void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea) + { + ValueSet::SetDrawingArea(pDrawingArea); + + OutputDevice& rDevice = pDrawingArea->get_ref_device(); + + aTxtSize.setWidth( rDevice.approximate_digit_width() ); + aTxtSize.setHeight( rDevice.GetTextHeight() ); + + UpdatePaintLineColor(); + } + + sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth ) + { + sal_Int32 nPos = -1; + if (!m_sNone.isEmpty()) + nListPos--; + + sal_Int32 n = 0; + size_t i = 0; + size_t nCount = m_vLineList.size(); + while ( nPos == -1 && i < nCount ) + { + auto& pData = m_vLineList[ i ]; + if ( pData->GetMinWidth() <= nWidth ) + { + if ( nListPos == n ) + nPos = static_cast<sal_Int32>(i); + n++; + } + i++; + } + + return nPos; + } + + void LineListBox::InsertEntry( + const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth, + ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn ) + { + m_vLineList.emplace_back(new ImpLineListData( + rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn)); + } + + SvxBorderLineStyle LineListBox::GetEntryStyle( sal_Int32 nPos ) const + { + ImpLineListData* pData = (0 <= nPos && o3tl::make_unsigned(nPos) < m_vLineList.size()) ? m_vLineList[ nPos ].get() : nullptr; + return pData ? pData->GetStyle() : SvxBorderLineStyle::NONE; + } + + void LineListBox::UpdatePaintLineColor() + { + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor ); + + bool bRet = aNewCol != maPaintCol; + + if( bRet ) + maPaintCol = aNewCol; + } + + Size LineListBox::UpdateEntries( tools::Long nOldWidth ) + { + Size aSize; + + UpdatePaintLineColor( ); + + sal_Int32 nSelEntry = GetSelectItemPos(); + sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth ); + + // Remove the old entries + Clear(); + + sal_uInt16 nId(1); + + // Add the new entries based on the defined width + if (!m_sNone.isEmpty()) + InsertItem(nId++, Image(), m_sNone); + + sal_uInt16 n = 0; + sal_uInt16 nCount = m_vLineList.size( ); + while ( n < nCount ) + { + auto& pData = m_vLineList[ n ]; + if ( pData->GetMinWidth() <= m_nWidth ) + { + BitmapEx aBmp; + ImpGetLine( pData->GetLine1ForWidth( m_nWidth ), + pData->GetLine2ForWidth( m_nWidth ), + pData->GetDistForWidth( m_nWidth ), + GetColorLine1( GetItemCount( ) ), + GetColorLine2( GetItemCount( ) ), + GetColorDist( GetItemCount( ) ), + pData->GetStyle(), aBmp ); + InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle())); + Size aBmpSize = aBmp.GetSizePixel(); + if (aBmpSize.Width() > aSize.Width()) + aSize.setWidth(aBmpSize.getWidth()); + if (aBmpSize.Height() > aSize.Height()) + aSize.setHeight(aBmpSize.getHeight()); + if ( n == nTypePos ) + SelectItem(nId); + } + else if ( n == nTypePos ) + SetNoSelection(); + n++; + ++nId; + } + + Invalidate(); + + return aSize; + } + + Color LineListBox::GetColorLine1( sal_Int32 nPos ) + { + sal_Int32 nStyle = GetStylePos( nPos, m_nWidth ); + if (nStyle == -1) + return GetPaintColor( ); + auto& pData = m_vLineList[ nStyle ]; + return pData->GetColorLine1( GetColor( ) ); + } + + Color LineListBox::GetColorLine2( sal_Int32 nPos ) + { + sal_Int32 nStyle = GetStylePos( nPos, m_nWidth ); + if (nStyle == -1) + return GetPaintColor( ); + auto& pData = m_vLineList[ nStyle ]; + return pData->GetColorLine2( GetColor( ) ); + } + + Color LineListBox::GetColorDist( sal_Int32 nPos ) + { + Color rResult = Application::GetSettings().GetStyleSettings().GetFieldColor(); + + sal_Int32 nStyle = GetStylePos( nPos, m_nWidth ); + if (nStyle == -1) + return rResult; + auto& pData = m_vLineList[ nStyle ]; + return pData->GetColorDist( GetColor( ), rResult ); + } +} + +namespace { + +class SvxLineWindow_Impl final : public WeldToolbarPopup +{ +private: + rtl::Reference<SvxFrameToolBoxControl> m_xControl; + std::unique_ptr<LineListBox> m_xLineStyleLb; + std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin; + bool m_bIsWriter; + + DECL_LINK( SelectHdl, ValueSet*, void ); + +public: + SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent); + virtual void GrabFocus() override + { + m_xLineStyleLb->GrabFocus(); + } +}; + +} + +class SvxStyleToolBoxControl; + +class SfxStyleControllerItem_Impl : public SfxStatusListener +{ + public: + SfxStyleControllerItem_Impl( const Reference< XDispatchProvider >& rDispatchProvider, + sal_uInt16 nSlotId, + const OUString& rCommand, + SvxStyleToolBoxControl& rTbxCtl ); + + protected: + virtual void StateChangedAtStatusListener( SfxItemState eState, const SfxPoolItem* pState ) override; + + private: + SvxStyleToolBoxControl& rControl; +}; + +#define BUTTON_PADDING 10 +#define ITEM_HEIGHT 30 + +SvxStyleBox_Base::SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, + OUString aCommand, + SfxStyleFamily eFamily, + const Reference< XFrame >& _xFrame, + OUString _aClearFormatKey, + OUString _aMoreKey, + bool bInSpec, SvxStyleToolBoxControl& rCtrl) + : m_rCtrl(rCtrl) + , m_xMenuBuilder(Application::CreateBuilder(nullptr, "svx/ui/stylemenu.ui")) + , m_xMenu(m_xMenuBuilder->weld_menu("menu")) + , m_xWidget(std::move(xWidget)) + , eStyleFamily( eFamily ) + , m_nMaxUserDrawFontWidth(0) + , m_nLastItemWithMenu(-1) + , bRelease( true ) + , m_xFrame(_xFrame) + , m_aCommand(std::move( aCommand )) + , aClearFormatKey(std::move( _aClearFormatKey )) + , aMoreKey(std::move( _aMoreKey )) + , bInSpecialMode( bInSpec ) +{ + m_xWidget->connect_changed(LINK(this, SvxStyleBox_Base, SelectHdl)); + m_xWidget->connect_key_press(LINK(this, SvxStyleBox_Base, KeyInputHdl)); + m_xWidget->connect_entry_activate(LINK(this, SvxStyleBox_Base, ActivateHdl)); + m_xWidget->connect_focus_out(LINK(this, SvxStyleBox_Base, FocusOutHdl)); + m_xWidget->connect_get_property_tree(LINK(this, SvxStyleBox_Base, DumpAsPropertyTreeHdl)); + m_xWidget->set_help_id(HID_STYLE_LISTBOX); + m_xWidget->set_entry_completion(true); + m_xMenu->connect_activate(LINK(this, SvxStyleBox_Base, MenuSelectHdl)); + + m_xWidget->connect_custom_get_size(LINK(this, SvxStyleBox_Base, CustomGetSizeHdl)); + m_xWidget->connect_custom_render(LINK(this, SvxStyleBox_Base, CustomRenderHdl)); + m_xWidget->set_custom_renderer(true); + + m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 3); +} + +IMPL_LINK(SvxStyleBox_Base, CustomGetSizeHdl, OutputDevice&, rArg, Size) +{ + CalcOptimalExtraUserWidth(rArg); + if (comphelper::LibreOfficeKit::isActive()) + return Size(m_nMaxUserDrawFontWidth * rArg.GetDPIX() / 96, ITEM_HEIGHT * rArg.GetDPIY() / 96); + return Size(m_nMaxUserDrawFontWidth, ITEM_HEIGHT); +} + +SvxStyleBox_Impl::SvxStyleBox_Impl(vcl::Window* pParent, + const OUString& rCommand, + SfxStyleFamily eFamily, + const Reference< XFrame >& _xFrame, + const OUString& rClearFormatKey, + const OUString& rMoreKey, + bool bInSpec, SvxStyleToolBoxControl& rCtrl) + : InterimItemWindow(pParent, "svx/ui/applystylebox.ui", "ApplyStyleBox") + , SvxStyleBox_Base(m_xBuilder->weld_combo_box("applystyle"), rCommand, eFamily, _xFrame, + rClearFormatKey, rMoreKey, bInSpec, rCtrl) +{ + InitControlBase(m_xWidget.get()); + + set_id("applystyle"); + SetOptimalSize(); +} + +void SvxStyleBox_Base::ReleaseFocus() +{ + if ( !bRelease ) + { + bRelease = true; + return; + } + if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() ) + m_xFrame->getContainerWindow()->setFocus(); +} + +IMPL_LINK(SvxStyleBox_Base, MenuSelectHdl, const OUString&, rMenuIdent, void) +{ + if (m_nLastItemWithMenu < 0 || m_nLastItemWithMenu >= m_xWidget->get_count()) + return; + + OUString sEntry = m_xWidget->get_text(m_nLastItemWithMenu); + + ReleaseFocus(); // It must be after getting entry pos! + Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("Param", sEntry), + comphelper::makePropertyValue("Family", + sal_Int16( eStyleFamily )) }; + + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + if (rMenuIdent == "update") + { + SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleUpdateByExample", aArgs); + } + else if (rMenuIdent == "edit") + { + SfxToolBoxControl::Dispatch(xProvider, ".uno:EditStyle", aArgs); + } +} + +IMPL_STATIC_LINK_NOARG(SvxStyleBox_Base, ShowMoreHdl, void*, void) +{ + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + DBG_ASSERT( pViewFrm, "SvxStyleBox_Base::Select(): no viewframe" ); + if (!pViewFrm) + return; + pViewFrm->ShowChildWindow(SID_SIDEBAR); + ::sfx2::sidebar::Sidebar::ShowPanel(u"StyleListPanel", pViewFrm->GetFrame().GetFrameInterface(), true); +} + +IMPL_LINK(SvxStyleBox_Base, SelectHdl, weld::ComboBox&, rCombo, void) +{ + Select(rCombo.changed_by_direct_pick()); // only when picked from the list +} + +IMPL_LINK_NOARG(SvxStyleBox_Base, ActivateHdl, weld::ComboBox&, bool) +{ + Select(true); + return true; +} + +void SvxStyleBox_Base::Select(bool bNonTravelSelect) +{ + if (!bNonTravelSelect) + return; + + OUString aSearchEntry(m_xWidget->get_active_text()); + bool bDoIt = true, bClear = false; + if( bInSpecialMode ) + { + if( aSearchEntry == aClearFormatKey && m_xWidget->get_active() == 0 ) + { + aSearchEntry = sDefaultStyle; + bClear = true; + //not only apply default style but also call 'ClearFormatting' + Sequence< PropertyValue > aEmptyVals; + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, ".uno:ResetAttributes", aEmptyVals); + } + else if (aSearchEntry == aMoreKey && m_xWidget->get_active() == (m_xWidget->get_count() - 1)) + { + Application::PostUserEvent(LINK(nullptr, SvxStyleBox_Base, ShowMoreHdl)); + //tdf#113214 change text back to previous entry + set_active_or_entry_text(m_xWidget->get_saved_value()); + bDoIt = false; + } + } + + //Do we need to create a new style? + SfxObjectShell *pShell = SfxObjectShell::Current(); + if (!pShell) + return; + + SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool(); + SfxStyleSheetBase* pStyle = nullptr; + + bool bCreateNew = false; + + if ( pPool ) + { + pStyle = pPool->First(eStyleFamily); + while ( pStyle && pStyle->GetName() != aSearchEntry ) + pStyle = pPool->Next(); + } + + if ( !pStyle ) + { + // cannot find the style for whatever reason + // therefore create a new style + bCreateNew = true; + } + + /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + ReleaseFocus(); + + if( !bDoIt ) + return; + + if ( bClear ) + set_active_or_entry_text(aSearchEntry); + m_xWidget->save_value(); + + Sequence< PropertyValue > aArgs( 2 ); + auto pArgs = aArgs.getArray(); + pArgs[0].Value <<= aSearchEntry; + pArgs[1].Name = "Family"; + pArgs[1].Value <<= sal_Int16( eStyleFamily ); + + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + if( bCreateNew ) + { + pArgs[0].Name = "Param"; + SfxToolBoxControl::Dispatch(xProvider, ".uno:StyleNewByExample", aArgs); + } + else + { + pArgs[0].Name = "Template"; + SfxToolBoxControl::Dispatch(xProvider, m_aCommand, aArgs); + } +} + +void SvxStyleBox_Base::SetFamily( SfxStyleFamily eNewFamily ) +{ + eStyleFamily = eNewFamily; +} + +IMPL_LINK_NOARG(SvxStyleBox_Base, FocusOutHdl, weld::Widget&, void) +{ + if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus + set_active_or_entry_text(m_xWidget->get_saved_value()); +} + +IMPL_LINK(SvxStyleBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return DoKeyInput(rKEvt); +} + +bool SvxStyleBox_Base::DoKeyInput(const KeyEvent& rKEvt) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch (nCode) + { + case KEY_TAB: + bRelease = false; + Select(true); + break; + case KEY_ESCAPE: + set_active_or_entry_text(m_xWidget->get_saved_value()); + if (!m_rCtrl.IsInSidebar()) + { + ReleaseFocus(); + bHandled = true; + } + break; + } + + return bHandled; +} + +bool SvxStyleBox_Impl::DoKeyInput(const KeyEvent& rKEvt) +{ + return SvxStyleBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt); +} + +void SvxStyleBox_Impl::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + SetOptimalSize(); + } + + InterimItemWindow::DataChanged( rDCEvt ); +} + +void SvxStyleBox_Impl::SetOptimalSize() +{ + // set width in chars low so the size request will not be overridden + m_xWidget->set_entry_width_chars(1); + // tdf#132338 purely using this calculation to keep things their traditional width + Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS + 3) * 4, 0), MapMode(MapUnit::MapAppFont))); + m_xWidget->set_size_request(aSize.Width(), -1); + + SetSizePixel(get_preferred_size()); +} + +namespace +{ +std::vector<ScriptInfo> CheckScript(const OUString &rStyleName) +{ + assert(!rStyleName.isEmpty()); // must have a preview text here! + + std::vector<ScriptInfo> aScriptChanges; + + auto aEditEngine = EditEngine(nullptr); + aEditEngine.SetText(rStyleName); + + auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 }); + for (sal_Int32 i = 1; i <= rStyleName.getLength(); i++) + { + auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i }); + if (aNextScript != aScript || i == rStyleName.getLength()) + aScriptChanges.emplace_back(aScript, i); + aScript = aNextScript; + } + + return aScriptChanges; +} +} + +tools::Rectangle SvxStyleBox_Base::CalcBoundRect(vcl::RenderContext& rRenderContext, const OUString &rStyleName, std::vector<ScriptInfo>& rScriptChanges, double fRatio) +{ + tools::Rectangle aTextRect; + + SvtScriptType aScript; + sal_uInt16 nIdx = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd; + size_t nCnt = rScriptChanges.size(); + + if (nCnt) + { + nEnd = rScriptChanges[nIdx].changePos; + aScript = rScriptChanges[nIdx].scriptType; + } + else + { + nEnd = rStyleName.getLength(); + aScript = SvtScriptType::LATIN; + } + + do + { + auto oFont = (aScript == SvtScriptType::ASIAN) ? + m_oCJKFont : + ((aScript == SvtScriptType::COMPLEX) ? + m_oCTLFont : + m_oFont); + + rRenderContext.Push(vcl::PushFlags::FONT); + + if (oFont) + rRenderContext.SetFont(*oFont); + + if (fRatio != 1) + { + vcl::Font aFont(rRenderContext.GetFont()); + Size aPixelSize(aFont.GetFontSize()); + aPixelSize.setWidth(aPixelSize.Width() * fRatio); + aPixelSize.setHeight(aPixelSize.Height() * fRatio); + aFont.SetFontSize(aPixelSize); + rRenderContext.SetFont(aFont); + } + + tools::Rectangle aRect; + rRenderContext.GetTextBoundRect(aRect, rStyleName, nStart, nStart, nEnd - nStart); + aTextRect = aTextRect.Union(aRect); + + tools::Long nWidth = rRenderContext.GetTextWidth(rStyleName, nStart, nEnd - nStart); + + rRenderContext.Pop(); + + if (nIdx >= rScriptChanges.size()) + break; + + rScriptChanges[nIdx++].textWidth = nWidth; + + if (nEnd < rStyleName.getLength() && nIdx < nCnt) + { + nStart = nEnd; + nEnd = rScriptChanges[nIdx].changePos; + aScript = rScriptChanges[nIdx].scriptType; + } + else + break; + } + while(true); + + return aTextRect; +} + +void SvxStyleBox_Base::UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const tools::Rectangle& rTextRect, const OUString &rStyleName, const std::vector<ScriptInfo>& rScriptChanges) +{ + // IMG_TXT_DISTANCE in ilstbox.hxx is 6, then 1 is added as + // nBorder, and we are adding 1 in order to look better when + // italics is present + const int nLeftDistance = 8; + + Point aPos(rRect.TopLeft()); + aPos.AdjustX(nLeftDistance ); + + double fRatio = 1; + if (rTextRect.Bottom() > rRect.GetHeight()) + fRatio = static_cast<double>(rRect.GetHeight()) / rTextRect.Bottom(); + else + aPos.AdjustY((rRect.GetHeight() - rTextRect.Bottom()) / 2); + + SvtScriptType aScript; + sal_uInt16 nIdx = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd; + size_t nCnt = rScriptChanges.size(); + + if (nCnt) + { + nEnd = rScriptChanges[nIdx].changePos; + aScript = rScriptChanges[nIdx].scriptType; + } + else + { + nEnd = rStyleName.getLength(); + aScript = SvtScriptType::LATIN; + } + + + do + { + auto oFont = (aScript == SvtScriptType::ASIAN) ? + m_oCJKFont : + ((aScript == SvtScriptType::COMPLEX) ? + m_oCTLFont : + m_oFont); + + rRenderContext.Push(vcl::PushFlags::FONT); + + if (oFont) + rRenderContext.SetFont(*oFont); + + if (fRatio != 1) + { + vcl::Font aFont(rRenderContext.GetFont()); + Size aPixelSize(aFont.GetFontSize()); + aPixelSize.setWidth(aPixelSize.Width() * fRatio); + aPixelSize.setHeight(aPixelSize.Height() * fRatio); + aFont.SetFontSize(aPixelSize); + rRenderContext.SetFont(aFont); + } + + rRenderContext.DrawText(aPos, rStyleName, nStart, nEnd - nStart); + + rRenderContext.Pop(); + + aPos.AdjustX(rScriptChanges[nIdx++].textWidth * fRatio); + if (nEnd < rStyleName.getLength() && nIdx < nCnt) + { + nStart = nEnd; + nEnd = rScriptChanges[nIdx].changePos; + aScript = rScriptChanges[nIdx].scriptType; + } + else + break; + } + while(true); +} + +static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich) +{ + rWhich = rSet.GetPool()->GetWhich(nSlot); + return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT; +} + +static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont) +{ + sal_uInt16 nWhich; + if (GetWhich(rSet, nSlot, nWhich)) + { + const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich)); + rFont.SetFamilyName(rFontItem.GetFamilyName()); + rFont.SetStyleName(rFontItem.GetStyleName()); + return true; + } + return false; +} + +static bool SetFontSize(vcl::RenderContext& rRenderContext, const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont) +{ + sal_uInt16 nWhich; + if (GetWhich(rSet, nSlot, nWhich)) + { + const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich)); + if (SfxObjectShell *pShell = SfxObjectShell::Current()) + { + Size aFontSize(0, rFontHeightItem.GetHeight()); + Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit()))); + rFont.SetFontSize(aPixelSize); + return true; + } + } + return false; +} + +static void SetFontStyle(const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont) +{ + sal_uInt16 nWhich; + if (GetWhich(rSet, nPosture, nWhich)) + { + const auto& rItem = static_cast<const SvxPostureItem&>(rSet.Get(nWhich)); + rFont.SetItalic(rItem.GetPosture()); + } + + if (GetWhich(rSet, nWeight, nWhich)) + { + const auto& rItem = static_cast<const SvxWeightItem&>(rSet.Get(nWhich)); + rFont.SetWeight(rItem.GetWeight()); + } +} + +void SvxStyleBox_Base::SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + if (!bIsNotSelected) + rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor()); + else + rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor()); + + // handle the push-button + if (!bIsNotSelected) + { + if (nItem == 0 || nItem == m_xWidget->get_count() - 1) + m_xWidget->set_item_menu(OUString::number(nItem), nullptr); + else + { + m_nLastItemWithMenu = nItem; + m_xWidget->set_item_menu(OUString::number(nItem), m_xMenu.get()); + } + } + + if (nItem <= 0 || nItem >= m_xWidget->get_count() - 1) + return; + + SfxObjectShell *pShell = SfxObjectShell::Current(); + if (!pShell) + return; + + SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool(); + if (!pPool) + return; + + SfxStyleSheetBase* pStyle = pPool->First(eStyleFamily); + while (pStyle && pStyle->GetName() != rStyleName) + pStyle = pPool->Next(); + + if (!pStyle ) + return; + + std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview()); + if (!pItemSet) return; + + SvxFont aFont; + SvxFont aCJKFont; + SvxFont aCTLFont; + + SetFontStyle(*pItemSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, aFont); + SetFontStyle(*pItemSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, aCJKFont); + SetFontStyle(*pItemSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, aCTLFont); + + const SfxPoolItem *pItem = pItemSet->GetItem( SID_ATTR_CHAR_CONTOUR ); + if ( pItem ) + { + auto aVal = static_cast< const SvxContourItem* >( pItem )->GetValue(); + aFont.SetOutline(aVal); + aCJKFont.SetOutline(aVal); + aCTLFont.SetOutline(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_SHADOWED ); + if ( pItem ) + { + auto aVal = static_cast< const SvxShadowedItem* >( pItem )->GetValue(); + aFont.SetShadow(aVal); + aCJKFont.SetShadow(aVal); + aCTLFont.SetShadow(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_RELIEF ); + if ( pItem ) + { + auto aVal = static_cast< const SvxCharReliefItem* >( pItem )->GetValue(); + aFont.SetRelief(aVal); + aCJKFont.SetRelief(aVal); + aCTLFont.SetRelief(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_UNDERLINE ); + if ( pItem ) + { + auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle(); + aFont.SetUnderline(aVal); + aCJKFont.SetUnderline(aVal); + aCTLFont.SetUnderline(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_OVERLINE ); + if ( pItem ) + { + auto aVal = static_cast< const SvxOverlineItem* >( pItem )->GetValue(); + aFont.SetOverline(aVal); + aCJKFont.SetOverline(aVal); + aCTLFont.SetOverline(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_STRIKEOUT ); + if ( pItem ) + { + auto aVal = static_cast< const SvxCrossedOutItem* >( pItem )->GetStrikeout(); + aFont.SetStrikeout(aVal); + aCJKFont.SetStrikeout(aVal); + aCTLFont.SetStrikeout(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_CASEMAP ); + if ( pItem ) + { + auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap(); + aFont.SetCaseMap(aVal); + aCJKFont.SetCaseMap(aVal); + aCTLFont.SetCaseMap(aVal); + } + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_EMPHASISMARK ); + if ( pItem ) + { + auto aVal = static_cast< const SvxEmphasisMarkItem* >( pItem )->GetEmphasisMark(); + aFont.SetEmphasisMark(aVal); + aCJKFont.SetEmphasisMark(aVal); + aCTLFont.SetEmphasisMark(aVal); + } + + // setup the device & draw + Color aFontCol = COL_AUTO, aBackCol = COL_AUTO; + + pItem = pItemSet->GetItem( SID_ATTR_CHAR_COLOR ); + // text color, when nothing is selected + if ( (nullptr != pItem) && bIsNotSelected) + aFontCol = static_cast< const SvxColorItem* >( pItem )->GetValue(); + + drawing::FillStyle style = drawing::FillStyle_NONE; + // which kind of Fill style is selected + pItem = pItemSet->GetItem( XATTR_FILLSTYLE ); + // only when ok and not selected + if ( (nullptr != pItem) && bIsNotSelected) + style = static_cast< const XFillStyleItem* >( pItem )->GetValue(); + + switch(style) + { + case drawing::FillStyle_SOLID: + { + // set background color + pItem = pItemSet->GetItem( XATTR_FILLCOLOR ); + if ( nullptr != pItem ) + aBackCol = static_cast< const XFillColorItem* >( pItem )->GetColorValue(); + + if ( aBackCol != COL_AUTO ) + { + rRenderContext.SetFillColor(aBackCol); + rRenderContext.DrawRect(rRect); + } + } + break; + + default: break; + //TODO Draw the other background styles: gradient, hatching and bitmap + } + + // when the font and background color are too similar, adjust the Font-Color + if( (aFontCol != COL_AUTO) || (aBackCol != COL_AUTO) ) + aFontCol = TestColorsVisible(aFontCol, (aBackCol != COL_AUTO) ? aBackCol : rRenderContext.GetBackground().GetColor()); + + // set text color + if ( aFontCol != COL_AUTO ) + rRenderContext.SetTextColor(aFontCol); + + if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) && + SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont)) + m_oFont = aFont; + + if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) && + SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont)) + m_oCJKFont = aCJKFont; + + if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) && + SetFontSize(rRenderContext, *pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont)) + m_oCTLFont = aCTLFont; +} + +IMPL_LINK(SvxStyleBox_Base, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void) +{ + vcl::RenderContext& rRenderContext = std::get<0>(aPayload); + const ::tools::Rectangle& rRect = std::get<1>(aPayload); + bool bSelected = std::get<2>(aPayload); + const OUString& rId = std::get<3>(aPayload); + + sal_uInt32 nIndex = rId.toUInt32(); + + OUString aStyleName(m_xWidget->get_text(nIndex)); + + rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR); + + SetupEntry(rRenderContext, nIndex, rRect, aStyleName, !bSelected); + auto aScriptChanges = CheckScript(aStyleName); + auto aTextRect = CalcBoundRect(rRenderContext, aStyleName, aScriptChanges); + UserDrawEntry(rRenderContext, rRect, aTextRect, aStyleName, aScriptChanges); + + rRenderContext.Pop(); +} + +void SvxStyleBox_Base::CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext) +{ + if (m_nMaxUserDrawFontWidth) + return; + + tools::Long nMaxNormalFontWidth = 0; + sal_Int32 nEntryCount = m_xWidget->get_count(); + for (sal_Int32 i = 0; i < nEntryCount; ++i) + { + OUString sStyleName(get_text(i)); + tools::Rectangle aTextRectForDefaultFont; + rRenderContext.GetTextBoundRect(aTextRectForDefaultFont, sStyleName); + + const tools::Long nWidth = aTextRectForDefaultFont.GetWidth(); + + nMaxNormalFontWidth = std::max(nWidth, nMaxNormalFontWidth); + } + + m_nMaxUserDrawFontWidth = nMaxNormalFontWidth; + for (sal_Int32 i = 1; i < nEntryCount-1; ++i) + { + OUString sStyleName(get_text(i)); + + if (sStyleName.isEmpty()) + continue; + + rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR); + SetupEntry(rRenderContext, i, tools::Rectangle(0, 0, RECT_MAX, ITEM_HEIGHT), sStyleName, true); + auto aScriptChanges = CheckScript(sStyleName); + tools::Rectangle aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges); + if (aTextRectForActualFont.Bottom() > ITEM_HEIGHT) + { + //Font didn't fit, re-calculate with adjustment ratio. + double fRatio = static_cast<double>(ITEM_HEIGHT) / aTextRectForActualFont.Bottom(); + aTextRectForActualFont = CalcBoundRect(rRenderContext, sStyleName, aScriptChanges, fRatio); + } + rRenderContext.Pop(); + + const int nWidth = aTextRectForActualFont.GetWidth() + m_xWidget->get_menu_button_width() + BUTTON_PADDING; + + m_nMaxUserDrawFontWidth = std::max(nWidth, m_nMaxUserDrawFontWidth); + } +} + +// test is the color between Font- and background-color to be identify +// return is always the Font-Color +// when both light or dark, change the Contrast +// in other case do not change the origin color +// when the color is R=G=B=128 the DecreaseContrast make 128 the need an exception +Color SvxStyleBox_Base::TestColorsVisible(const Color &FontCol, const Color &BackCol) +{ + constexpr sal_uInt8 ChgVal = 60; // increase/decrease the Contrast + + Color retCol = FontCol; + if ((FontCol.IsDark() == BackCol.IsDark()) && (FontCol.IsBright() == BackCol.IsBright())) + { + sal_uInt8 lumi = retCol.GetLuminance(); + + if((lumi > 120) && (lumi < 140)) + retCol.DecreaseLuminance(ChgVal / 2); + else + retCol.DecreaseContrast(ChgVal); + } + + return retCol; +} + +IMPL_LINK(SvxStyleBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void) +{ + if (!m_xWidget) + return; + + { + auto entriesNode = rJsonWriter.startNode("entries"); + for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i) + { + auto entryNode = rJsonWriter.startNode(""); + rJsonWriter.put("", m_xWidget->get_text(i)); + } + } + + int nActive = m_xWidget->get_active(); + rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1)); + + { + auto selectedNode = rJsonWriter.startNode("selectedEntries"); + if (nActive != -1) + { + auto node = rJsonWriter.startNode(""); + rJsonWriter.put("", static_cast<sal_Int32>(nActive)); + } + } + + rJsonWriter.put("command", ".uno:StyleApply"); +} + +static bool lcl_GetDocFontList(const FontList** ppFontList, SvxFontNameBox_Base* pBox) +{ + bool bChanged = false; + const SfxObjectShell* pDocSh = SfxObjectShell::Current(); + const SvxFontListItem* pFontListItem = nullptr; + + if ( pDocSh ) + pFontListItem = + static_cast<const SvxFontListItem*>(pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST )); + else + { + ::std::unique_ptr<FontList> aFontList(new FontList(Application::GetDefaultDevice())); + *ppFontList = aFontList.get(); + pBox->SetOwnFontList(std::move(aFontList)); + bChanged = true; + } + + if ( pFontListItem ) + { + const FontList* pNewFontList = pFontListItem->GetFontList(); + DBG_ASSERT( pNewFontList, "Doc-FontList not available!" ); + + // No old list, but a new list + if ( !*ppFontList && pNewFontList ) + { + // => take over + *ppFontList = pNewFontList; + bChanged = true; + } + else + { + // Comparing the font lists is not perfect. + // When you change the font list in the Doc, you can track + // changes here only on the Listbox, because ppFontList + // has already been updated. + bChanged = + ( ( *ppFontList != pNewFontList ) || + pBox->GetListCount() != pNewFontList->GetFontNameCount() ); + // HACK: Comparing is incomplete + + if ( bChanged ) + *ppFontList = pNewFontList; + } + + if ( pBox ) + pBox->set_sensitive(true); + } + else if ( pBox && ( pDocSh || !ppFontList )) + { + // Disable box only when we have a SfxObjectShell and didn't get a font list OR + // we don't have a SfxObjectShell and no current font list. + // It's possible that we currently have no SfxObjectShell, but a current font list. + // See #i58471: When a user set the focus into the font name combo box and opens + // the help window with F1. After closing the help window, we disable the font name + // combo box. The SfxObjectShell::Current() method returns in that case zero. But the + // font list hasn't changed and therefore the combo box shouldn't be disabled! + pBox->set_sensitive(false); + } + + // Fill the FontBox, also the new list if necessary + if ( pBox && bChanged ) + { + if ( *ppFontList ) + pBox->Fill( *ppFontList ); + else + pBox->Clear(); + } + return bChanged; +} + +SvxFontNameBox_Base::SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, + const Reference<XFrame>& rFrame, + SvxFontNameToolBoxControl& rCtrl) + : m_xListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Common/Font/View")) + , m_aWYSIWYG(m_xListener, "ShowFontBoxWYSIWYG", *this) + , m_aHistory(m_xListener, "History", *this) + , m_rCtrl(rCtrl) + , m_xWidget(new FontNameBox(std::move(xWidget))) + , pFontList(nullptr) + , nFtCount(0) + , bRelease(true) + , m_xFrame(rFrame) + , mbCheckingUnknownFont(false) + , mbDropDownActive(false) +{ + EnableControls(); + + m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Base, SelectHdl)); + m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Base, KeyInputHdl)); + m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Base, ActivateHdl)); + m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Base, FocusInHdl)); + m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Base, FocusOutHdl)); + m_xWidget->connect_popup_toggled(LINK(this, SvxFontNameBox_Base, PopupToggledHdl)); + m_xWidget->connect_live_preview(LINK(this, SvxFontNameBox_Base, LivePreviewHdl)); + m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Base, DumpAsPropertyTreeHdl)); + + m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 5); +} + +SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XFrame>& rFrame, + SvxFontNameToolBoxControl& rCtrl) + : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox", true, reinterpret_cast<sal_uInt64>(SfxViewShell::Current())) + , SvxFontNameBox_Base(m_xBuilder->weld_combo_box("fontnamecombobox"), rFrame, rCtrl) +{ + set_id("fontnamecombobox"); + SetOptimalSize(); +} + +void SvxFontNameBox_Base::FillList() +{ + if (!m_xWidget) // e.g. disposed + return; + // Save old Selection, set back in the end + int nStartPos, nEndPos; + m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos); + + // Did Doc-Fontlist change? + lcl_GetDocFontList(&pFontList, this); + + m_xWidget->select_entry_region(nStartPos, nEndPos); +} + +bool SvxFontNameBox_Base::CheckFontIsAvailable(std::u16string_view fontname) +{ + lcl_GetDocFontList(&pFontList, this); + return pFontList && pFontList->IsAvailable(fontname); +} + +void SvxFontNameBox_Base::CheckAndMarkUnknownFont() +{ + if (mbCheckingUnknownFont) //tdf#117537 block rentry + return; + mbCheckingUnknownFont = true; + OUString fontname = m_xWidget->get_active_text(); + // tdf#154680 If a font is set and that font is unknown, show it in italic. + vcl::Font font = m_xWidget->get_entry_font(); + if (fontname.isEmpty() || CheckFontIsAvailable(fontname)) + { + if( font.GetItalic() != ITALIC_NONE ) + { + font.SetItalic( ITALIC_NONE ); + m_xWidget->set_entry_font(font); + m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME)); + } + } + else + { + if( font.GetItalic() != ITALIC_NORMAL ) + { + font.SetItalic( ITALIC_NORMAL ); + m_xWidget->set_entry_font(font); + m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE)); + } + } + mbCheckingUnknownFont = false; +} + +void SvxFontNameBox_Base::Update( const css::awt::FontDescriptor* pFontDesc ) +{ + if ( pFontDesc ) + { + aCurFont.SetFamilyName ( pFontDesc->Name ); + aCurFont.SetFamily ( FontFamily( pFontDesc->Family ) ); + aCurFont.SetStyleName ( pFontDesc->StyleName ); + aCurFont.SetPitch ( FontPitch( pFontDesc->Pitch ) ); + aCurFont.SetCharSet ( rtl_TextEncoding( pFontDesc->CharSet ) ); + } + OUString aCurName = aCurFont.GetFamilyName(); + OUString aText = m_xWidget->get_active_text(); + if (aText != aCurName) + set_active_or_entry_text(aCurName); +} + +void SvxFontNameBox_Base::set_active_or_entry_text(const OUString& rText) +{ + m_xWidget->set_active_or_entry_text(rText); + CheckAndMarkUnknownFont(); +} + +IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusInHdl, weld::Widget&, void) +{ + FillList(); +} + +IMPL_LINK(SvxFontNameBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return DoKeyInput(rKEvt); +} + +bool SvxFontNameBox_Base::DoKeyInput(const KeyEvent& rKEvt) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch (nCode) + { + case KEY_TAB: + bRelease = false; + Select(true); + break; + + case KEY_ESCAPE: + set_active_or_entry_text(m_xWidget->get_saved_value()); + if (!m_rCtrl.IsInSidebar()) + { + ReleaseFocus_Impl(); + bHandled = true; + } + break; + } + + return bHandled; +} + +bool SvxFontNameBox_Impl::DoKeyInput(const KeyEvent& rKEvt) +{ + return SvxFontNameBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusOutHdl, weld::Widget&, void) +{ + if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus + { + set_active_or_entry_text(m_xWidget->get_saved_value()); + // send EndPreview + EndPreview(); + } +} + +IMPL_LINK(SvxFontNameBox_Base, LivePreviewHdl, const FontMetric&, rFontMetric, void) +{ + Sequence<PropertyValue> aArgs(1); + + SvxFontItem aFontItem(rFontMetric.GetFamilyType(), + rFontMetric.GetFamilyName(), + rFontMetric.GetStyleName(), + rFontMetric.GetPitch(), + rFontMetric.GetCharSet(), + SID_ATTR_CHAR_FONT); + PropertyValue* pArgs = aArgs.getArray(); + aFontItem.QueryValue(pArgs[0].Value); + pArgs[0].Name = "CharPreviewFontName"; + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs); +} + +IMPL_LINK_NOARG(SvxFontNameBox_Base, PopupToggledHdl, weld::ComboBox&, void) +{ + mbDropDownActive = !mbDropDownActive; + if (!mbDropDownActive) + EndPreview(); +} + +void SvxFontNameBox_Impl::SetOptimalSize() +{ + // set width in chars low so the size request will not be overridden + m_xWidget->set_entry_width_chars(1); + // tdf#132338 purely using this calculation to keep things their traditional width + Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS +5) * 4, 0), MapMode(MapUnit::MapAppFont))); + m_xWidget->set_size_request(aSize.Width(), -1); + + SetSizePixel(get_preferred_size()); +} + +void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + SetOptimalSize(); + } + else if ( ( rDCEvt.GetType() == DataChangedEventType::FONTS ) || + ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) ) + { + // The old font list in shell has likely been destroyed at this point, so we need to get + // the new one before doing anything further. + lcl_GetDocFontList( &pFontList, this ); + } +} + +void SvxFontNameBox_Base::ReleaseFocus_Impl() +{ + if ( !bRelease ) + { + bRelease = true; + return; + } + if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() ) + m_xFrame->getContainerWindow()->setFocus(); +} + +void SvxFontNameBox_Base::EnableControls() +{ + bool bEnableMRU = m_aHistory.get(); + sal_uInt16 nEntries = bEnableMRU ? MAX_MRU_FONTNAME_ENTRIES : 0; + + bool bNewWYSIWYG = m_aWYSIWYG.get(); + bool bOldWYSIWYG = m_xWidget->IsWYSIWYGEnabled(); + + if (m_xWidget->get_max_mru_count() != nEntries || bNewWYSIWYG != bOldWYSIWYG) + { + // refill in the next GetFocus-Handler + pFontList = nullptr; + Clear(); + m_xWidget->set_max_mru_count(nEntries); + } + + if (bNewWYSIWYG != bOldWYSIWYG) + m_xWidget->EnableWYSIWYG(bNewWYSIWYG); +} + +IMPL_LINK(SvxFontNameBox_Base, SelectHdl, weld::ComboBox&, rCombo, void) +{ + Select(rCombo.changed_by_direct_pick()); // only when picked from the list +} + +IMPL_LINK_NOARG(SvxFontNameBox_Base, ActivateHdl, weld::ComboBox&, bool) +{ + Select(true); + return true; +} + +void SvxFontNameBox_Base::Select(bool bNonTravelSelect) +{ + Sequence< PropertyValue > aArgs( 1 ); + auto pArgs = aArgs.getArray(); + std::unique_ptr<SvxFontItem> pFontItem; + if ( pFontList ) + { + FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(), + aCurFont.GetWeight(), + aCurFont.GetItalic() ) ); + aCurFont = aFontMetric; + + pFontItem.reset( new SvxFontItem( aFontMetric.GetFamilyType(), + aFontMetric.GetFamilyName(), + aFontMetric.GetStyleName(), + aFontMetric.GetPitch(), + aFontMetric.GetCharSet(), + SID_ATTR_CHAR_FONT ) ); + + Any a; + pFontItem->QueryValue( a ); + pArgs[0].Value = a; + } + + const Reference<XDispatchProvider> xProvider(m_xFrame, UNO_QUERY); + if (bNonTravelSelect) + { + CheckAndMarkUnknownFont(); + // #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call. + // This instance may be deleted in the meantime (i.e. when a dialog is opened + // while in Dispatch()), accessing members will crash in this case. + ReleaseFocus_Impl(); + EndPreview(); + if (pFontItem) + { + pArgs[0].Name = "CharFontName"; + SfxToolBoxControl::Dispatch(xProvider, ".uno:CharFontName", aArgs); + } + } + else + { + if (pFontItem) + { + pArgs[0].Name = "CharPreviewFontName"; + SfxToolBoxControl::Dispatch(xProvider, ".uno:CharPreviewFontName", aArgs); + } + } +} + +IMPL_LINK(SvxFontNameBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void) +{ + { + auto entriesNode = rJsonWriter.startNode("entries"); + for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i) + { + auto entryNode = rJsonWriter.startNode(""); + rJsonWriter.put("", m_xWidget->get_text(i)); + } + } + + int nSelectedEntry = m_xWidget->get_active(); + rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nSelectedEntry == -1 ? 0 : 1)); + + { + auto selectedNode = rJsonWriter.startNode("selectedEntries"); + if (nSelectedEntry != -1) + { + auto entryNode = rJsonWriter.startNode(""); + rJsonWriter.put("", m_xWidget->get_text(nSelectedEntry)); + } + } + + rJsonWriter.put("command", ".uno:CharFontName"); +} + +ColorWindow::ColorWindow(OUString rCommand, + std::shared_ptr<PaletteManager> xPaletteManager, + ColorStatus& rColorStatus, + sal_uInt16 nSlotId, + const Reference< XFrame >& rFrame, + const MenuOrToolMenuButton& rMenuButton, + TopLevelParentFunction aTopLevelParentFunction, + ColorSelectFunction aColorSelectFunction) + : WeldToolbarPopup(rFrame, rMenuButton.get_widget(), "svx/ui/colorwindow.ui", "palette_popup_window") + , theSlotId(nSlotId) + , maCommand(std::move(rCommand)) + , maMenuButton(rMenuButton) + , mxPaletteManager(std::move(xPaletteManager)) + , mrColorStatus(rColorStatus) + , maTopLevelParentFunction(std::move(aTopLevelParentFunction)) + , maColorSelectFunction(std::move(aColorSelectFunction)) + , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true))) + , mxRecentColorSet(new SvxColorValueSet(nullptr)) + , mxPaletteListBox(m_xBuilder->weld_combo_box("palette_listbox")) + , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button")) + , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button")) + , mxButtonPicker(m_xBuilder->weld_button("color_picker_button")) + , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4")) + , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet)) + , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet)) + , mpDefaultButton(nullptr) +{ + mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); + mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); + + switch ( theSlotId ) + { + case SID_ATTR_CHAR_COLOR_BACKGROUND: + case SID_BACKGROUND_COLOR: + case SID_ATTR_CHAR_BACK_COLOR: + case SID_TABLE_CELL_BACKGROUND_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) ); + break; + } + case SID_AUTHOR_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) ); + break; + } + case SID_BMPMASK_COLOR: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) ); + break; + } + case SID_ATTR_CHAR_COLOR: + case SID_ATTR_CHAR_COLOR2: + case SID_EXTRUSION_3D_COLOR: + { + mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC)); + break; + } + case SID_FM_CTL_PROPERTIES: + { + mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) ); + break; + } + default: + { + mxButtonAutoColor->hide(); + mxAutomaticSeparator->hide(); + break; + } + } + + mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl)); + std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList(); + mxPaletteListBox->freeze(); + for (const auto& rPalette : aPaletteList) + mxPaletteListBox->append_text(rPalette); + mxPaletteListBox->thaw(); + OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() ); + mxPaletteListBox->set_active_text(aPaletteName); + const int nSelectedEntry(mxPaletteListBox->get_active()); + if (nSelectedEntry != -1) + mxPaletteManager->SetPalette(nSelectedEntry); + + mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl)); + mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl)); + mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl)); + + mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); + mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); + m_xTopLevel->set_help_id(HID_POPUP_COLOR); + mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL); + + mxPaletteManager->ReloadColorSet(*mxColorSet); + const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount()); + Size aSize = mxColorSet->layoutAllVisible(nMaxItems); + mxColorSet->set_size_request(aSize.Width(), aSize.Height()); + + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount()); + mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height()); + + AddStatusListener( ".uno:ColorTableState" ); + AddStatusListener( maCommand ); + if ( maCommand == ".uno:FrameLineColor" ) + { + AddStatusListener( ".uno:BorderTLBR" ); + AddStatusListener( ".uno:BorderBLTR" ); + } +} + +void ColorWindow::GrabFocus() +{ + if (mxColorSet->IsNoSelection() && mpDefaultButton) + mpDefaultButton->grab_focus(); + else + mxColorSet->GrabFocus(); +} + +void ColorWindow::ShowNoneButton() +{ + mxButtonNoneColor->show(); +} + +ColorWindow::~ColorWindow() +{ +} + +NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet) +{ + Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId()); + OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId()); + return { aColor, sColorName }; +} + +namespace +{ + NamedColor GetAutoColor(sal_uInt16 nSlotId) + { + Color aColor; + OUString sColorName; + switch (nSlotId) + { + case SID_ATTR_CHAR_COLOR_BACKGROUND: + case SID_BACKGROUND_COLOR: + case SID_ATTR_CHAR_BACK_COLOR: + case SID_TABLE_CELL_BACKGROUND_COLOR: + aColor = COL_TRANSPARENT; + sColorName = SvxResId(RID_SVXSTR_NOFILL); + break; + case SID_AUTHOR_COLOR: + aColor = COL_TRANSPARENT; + sColorName = SvxResId(RID_SVXSTR_BY_AUTHOR); + break; + case SID_BMPMASK_COLOR: + aColor = COL_TRANSPARENT; + sColorName = SvxResId(RID_SVXSTR_TRANSPARENT); + break; + case SID_FM_CTL_PROPERTIES: + aColor = COL_TRANSPARENT; + sColorName = SvxResId(RID_SVXSTR_DEFAULT); + break; + case SID_ATTR_CHAR_COLOR: + case SID_ATTR_CHAR_COLOR2: + case SID_EXTRUSION_3D_COLOR: + default: + aColor = COL_AUTO; + sColorName = EditResId(RID_SVXSTR_AUTOMATIC); + break; + } + + return {aColor, sColorName}; + } + + NamedColor GetNoneColor() + { + OUString aName = comphelper::LibreOfficeKit::isActive() + ? SvxResId(RID_SVXSTR_INVISIBLE) + : SvxResId(RID_SVXSTR_NONE); + return { COL_NONE_COLOR, aName }; + } +} + +NamedColor ColorWindow::GetSelectEntryColor() const +{ + if (!mxColorSet->IsNoSelection()) + return GetSelectEntryColor(mxColorSet.get()); + if (!mxRecentColorSet->IsNoSelection()) + return GetSelectEntryColor(mxRecentColorSet.get()); + if (mxButtonNoneColor.get() == mpDefaultButton) + return GetNoneColor(); + return GetAutoColor(); +} + +IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void) +{ + NamedColor aNamedColor = GetSelectEntryColor(pColorSet); + + if (pColorSet != mxRecentColorSet.get()) + { + mxPaletteManager->AddRecentColor(aNamedColor.m_aColor, aNamedColor.m_aName); + if (!maMenuButton.get_active()) + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + } + + mxPaletteManager->SetSplitButtonColor(aNamedColor); + + // deliberate take a copy here in case maMenuButton.set_inactive + // triggers a callback that destroys ourself + ColorSelectFunction aColorSelectFunction(maColorSelectFunction); + OUString sCommand(maCommand); + // Same for querying IsTheme early. + bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected(); + sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId(); + + if (bThemePaletteSelected) + { + sal_uInt16 nThemeIndex; + sal_uInt16 nEffectIndex; + if (PaletteManager::GetThemeAndEffectIndex(nSelectedItemId, nThemeIndex, nEffectIndex)) + { + aNamedColor.m_nThemeIndex = nThemeIndex; + mxPaletteManager->GetLumModOff(nThemeIndex, nEffectIndex, aNamedColor.m_nLumMod, aNamedColor.m_nLumOff); + } + } + + maMenuButton.set_inactive(); + aColorSelectFunction(sCommand, aNamedColor); +} + +IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void) +{ + int nPos = mxPaletteListBox->get_active(); + mxPaletteManager->SetPalette( nPos ); + mxPaletteManager->ReloadColorSet(*mxColorSet); + mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); +} + +NamedColor ColorWindow::GetAutoColor() const +{ + return ::GetAutoColor(theSlotId); +} + +IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void) +{ + NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor(); + + mxColorSet->SetNoSelection(); + mxRecentColorSet->SetNoSelection(); + mpDefaultButton = &rButton; + + mxPaletteManager->SetSplitButtonColor(aNamedColor); + + // deliberate take a copy here in case maMenuButton.set_inactive + // triggers a callback that destroys ourself + ColorSelectFunction aColorSelectFunction(maColorSelectFunction); + OUString sCommand(maCommand); + + maMenuButton.set_inactive(); + + aColorSelectFunction(sCommand, aNamedColor); +} + +IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void) +{ + // copy before set_inactive + auto nColor = GetSelectEntryColor().m_aColor; + auto pParentWindow = maTopLevelParentFunction(); + OUString sCommand = maCommand; + std::shared_ptr<PaletteManager> xPaletteManager(mxPaletteManager); + + maMenuButton.set_inactive(); + + xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor); +} + +void ColorWindow::SetNoSelection() +{ + mxColorSet->SetNoSelection(); + mxRecentColorSet->SetNoSelection(); + mpDefaultButton = nullptr; +} + +bool ColorWindow::IsNoSelection() const +{ + if (!mxColorSet->IsNoSelection()) + return false; + if (!mxRecentColorSet->IsNoSelection()) + return false; + return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible(); +} + +void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + if (rEvent.FeatureURL.Complete == ".uno:ColorTableState") + { + if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0) + { + mxPaletteManager->ReloadColorSet(*mxColorSet); + mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); + } + } + else + { + mrColorStatus.statusChanged(rEvent); + SelectEntry(mrColorStatus.GetColor()); + } +} + +bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor) +{ + for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i) + { + if (rColor == pColorSet->GetItemColor(i)) + { + pColorSet->SelectItem(i); + return true; + } + } + return false; +} + +void ColorWindow::SelectEntry(const NamedColor& rNamedColor) +{ + SetNoSelection(); + + const Color &rColor = rNamedColor.m_aColor; + + if (mxButtonAutoColor->get_visible() && rColor.IsFullyTransparent()) + { + mpDefaultButton = mxButtonAutoColor.get(); + return; + } + + if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR) + { + mpDefaultButton = mxButtonNoneColor.get(); + return; + } + + // try current palette + bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor); + // try recently used + if (!bFoundColor) + bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor); + // if it's not there, add it there now to the end of the recently used + // so its available somewhere handy, but not without trashing the + // whole recently used + if (!bFoundColor) + { + const OUString& rColorName = rNamedColor.m_aName; + mxPaletteManager->AddRecentColor(rColor, rColorName, false); + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + SelectValueSetEntry(mxRecentColorSet.get(), rColor); + } +} + +void ColorWindow::SelectEntry(const Color& rColor) +{ + OUString sColorName = "#" + rColor.AsRGBHexString().toAsciiUpperCase(); + ColorWindow::SelectEntry({rColor, sColorName}); +} + +ColorStatus::ColorStatus() : + maColor( COL_TRANSPARENT ), + maTLBRColor( COL_TRANSPARENT ), + maBLTRColor( COL_TRANSPARENT ) +{ +} + +void ColorStatus::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + Color aColor( COL_TRANSPARENT ); + css::table::BorderLine2 aTable; + + if ( rEvent.State >>= aTable ) + { + SvxBorderLine aLine; + SvxBoxItem::LineToSvxLine( aTable, aLine, false ); + if ( !aLine.isEmpty() ) + aColor = aLine.GetColor(); + } + else + rEvent.State >>= aColor; + + if ( rEvent.FeatureURL.Path == "BorderTLBR" ) + maTLBRColor = aColor; + else if ( rEvent.FeatureURL.Path == "BorderBLTR" ) + maBLTRColor = aColor; + else + maColor = aColor; +} + +Color ColorStatus::GetColor() +{ + Color aColor( maColor ); + + if ( maTLBRColor != COL_TRANSPARENT ) + { + if ( aColor != maTLBRColor && aColor != COL_TRANSPARENT ) + return COL_TRANSPARENT; + aColor = maTLBRColor; + } + + if ( maBLTRColor != COL_TRANSPARENT ) + { + if ( aColor != maBLTRColor && aColor != COL_TRANSPARENT ) + return COL_TRANSPARENT; + return maBLTRColor; + } + + return aColor; +} + + +SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder") + , mxControl(pControl) + , mxFrameSet(new SvxFrmValueSet_Impl) + , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxFrameSet)) + , bParagraphMode(false) + , m_bIsWriter(false) +{ + + // check whether the document is Writer or not + if (Reference<lang::XServiceInfo> xSI{ m_xFrame->getController()->getModel(), UNO_QUERY }) + m_bIsWriter = xSI->supportsService("com.sun.star.text.TextDocument"); + + mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT); + AddStatusListener(".uno:BorderReducedMode"); + InitImageList(); + + /* + * 1 2 3 4 5 + * ------------------------------------------------------ + * NONE LEFT RIGHT LEFTRIGHT DIAGONALDOWN + * TOP BOTTOM TOPBOTTOM OUTER DIAGONALUP + * ------------------------------------------------------ + * HOR HORINNER VERINNER ALL CRISSCROSS <- can be switched of via bParagraphMode + */ + + sal_uInt16 i = 0; + + // diagonal borders available only for Calc. + // Therefore, Calc uses 10 border types while + // Writer uses 8 of them - for a single cell. + for ( i=1; i < (m_bIsWriter ? 9 : 11); i++ ) + mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); + + //bParagraphMode should have been set in StateChanged + if ( !bParagraphMode ) + // when multiple cell selected: + // Writer has 12 border types and Calc has 15 of them. + for ( i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ ) + mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); + + // adjust frame column for Writer + sal_uInt16 colCount = m_bIsWriter ? 4 : 5; + mxFrameSet->SetColCount( colCount ); + mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) ); + CalcSizeValueSet(); + + mxFrameSet->SetHelpId( HID_POPUP_FRAME ); + mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) ); +} + +namespace { + +enum class FrmValidFlags { + NONE = 0x00, + Left = 0x01, + Right = 0x02, + Top = 0x04, + Bottom = 0x08, + HInner = 0x10, + VInner = 0x20, + AllMask = 0x3f, +}; + +} + +namespace o3tl { + template<> struct typed_flags<FrmValidFlags> : is_typed_flags<FrmValidFlags, 0x3f> {}; +} + +// By default unset lines remain unchanged. +// Via Shift unset lines are reset + +IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void) +{ + SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER ); + SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER ); + SvxBorderLine theDefLine; + + // diagonal down border + SvxBorderLine dDownBorderLine(nullptr, SvxBorderLineWidth::Hairline); + SvxLineItem dDownLineItem(SID_ATTR_BORDER_DIAG_TLBR); + + // diagonal up border + SvxBorderLine dUpBorderLine(nullptr, SvxBorderLineWidth::Hairline); + SvxLineItem dUpLineItem(SID_ATTR_BORDER_DIAG_BLTR); + + bool bIsDiagonalBorder = false; + + SvxBorderLine *pLeft = nullptr, + *pRight = nullptr, + *pTop = nullptr, + *pBottom = nullptr; + sal_uInt16 nSel = mxFrameSet->GetSelectedItemId(); + sal_uInt16 nModifier = mxFrameSet->GetModifier(); + FrmValidFlags nValidFlags = FrmValidFlags::NONE; + + // tdf#48622, tdf#145828 use correct default to create intended 0.75pt + // cell border using the border formatting tool in the standard toolbar + theDefLine.GuessLinesWidths(theDefLine.GetBorderLineStyle(), SvxBorderLineWidth::Thin); + + // nSel has 15 cases which means 15 border + // types for Calc. But Writer uses only 12 + // of them - when diagonal borders excluded. + if (m_bIsWriter) + { + // add appropriate increments + // to match the correct borders. + if (nSel > 8) { nSel += 2; } + else if (nSel > 4) { nSel++; } + } + + switch ( nSel ) + { + case 1: nValidFlags |= FrmValidFlags::AllMask; + // set nullptr to remove diagonal lines + dDownLineItem.SetLine(nullptr); + dUpLineItem.SetLine(nullptr); + SetDiagonalDownBorder(dDownLineItem); + SetDiagonalUpBorder(dUpLineItem); + break; // NONE + case 2: pLeft = &theDefLine; + nValidFlags |= FrmValidFlags::Left; + break; // LEFT + case 3: pRight = &theDefLine; + nValidFlags |= FrmValidFlags::Right; + break; // RIGHT + case 4: pLeft = pRight = &theDefLine; + nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left; + break; // LEFTRIGHT + case 5: dDownLineItem.SetLine(&dDownBorderLine); + SetDiagonalDownBorder(dDownLineItem); + bIsDiagonalBorder = true; + break; // DIAGONAL DOWN + case 6: pTop = &theDefLine; + nValidFlags |= FrmValidFlags::Top; + break; // TOP + case 7: pBottom = &theDefLine; + nValidFlags |= FrmValidFlags::Bottom; + break; // BOTTOM + case 8: pTop = pBottom = &theDefLine; + nValidFlags |= FrmValidFlags::Bottom|FrmValidFlags::Top; + break; // TOPBOTTOM + case 9: pLeft = pRight = pTop = pBottom = &theDefLine; + nValidFlags |= FrmValidFlags::Left | FrmValidFlags::Right | FrmValidFlags::Top | FrmValidFlags::Bottom; + break; // OUTER + case 10: + dUpLineItem.SetLine(&dUpBorderLine); + SetDiagonalUpBorder(dUpLineItem); + bIsDiagonalBorder = true; + break; // DIAGONAL UP + + // Inner Table: + case 11: // HOR + pTop = pBottom = &theDefLine; + aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI ); + aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT ); + nValidFlags |= FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom; + break; + + case 12: // HORINNER + pLeft = pRight = pTop = pBottom = &theDefLine; + aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI ); + aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT ); + nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom; + break; + + case 13: // VERINNER + pLeft = pRight = pTop = pBottom = &theDefLine; + aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::HORI ); + aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT ); + nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::VInner|FrmValidFlags::Top|FrmValidFlags::Bottom; + break; + + case 14: // ALL + pLeft = pRight = pTop = pBottom = &theDefLine; + aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI ); + aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT ); + nValidFlags |= FrmValidFlags::AllMask; + break; + + case 15: + // set both diagonal lines to draw criss-cross line + dDownLineItem.SetLine(&dDownBorderLine); + dUpLineItem.SetLine(&dUpBorderLine); + + SetDiagonalDownBorder(dDownLineItem); + SetDiagonalUpBorder(dUpLineItem); + bIsDiagonalBorder = true; + break; // CRISS-CROSS + + default: + break; + } + + // if diagonal borders selected, + // no need to execute this block + if (!bIsDiagonalBorder) + { + aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT ); + aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT ); + aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP ); + aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM ); + + if(nModifier == KEY_SHIFT) + nValidFlags |= FrmValidFlags::AllMask; + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, bool(nValidFlags&FrmValidFlags::Top )); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, bool(nValidFlags&FrmValidFlags::Bottom )); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, bool(nValidFlags&FrmValidFlags::Left)); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, bool(nValidFlags&FrmValidFlags::Right )); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, bool(nValidFlags&FrmValidFlags::HInner )); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, bool(nValidFlags&FrmValidFlags::VInner)); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE ); + aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false ); + + Any a1, a2; + aBorderOuter.QueryValue( a1 ); + aBorderInner.QueryValue( a2 ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("OuterBorder", a1), + comphelper::makePropertyValue("InnerBorder", a2) }; + + mxControl->dispatchCommand( ".uno:SetBorderStyle", aArgs ); + } + + // coverity[ check_after_deref : FALSE] + if (mxFrameSet) + { + /* #i33380# Moved the following line above the Dispatch() call. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + mxFrameSet->SetNoSelection(); + } + + mxControl->EndPopupMode(); +} + +void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem) +{ + // apply diagonal down border + Any a; + dDownLineItem.QueryValue(a); + Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderTLBR", a) }; + + mxControl->dispatchCommand(".uno:BorderTLBR", aArgs); +} + +void SvxFrameWindow_Impl::SetDiagonalUpBorder(const SvxLineItem& dUpLineItem) +{ + // apply diagonal up border + Any a; + dUpLineItem.QueryValue(a); + Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderBLTR", a) }; + + mxControl->dispatchCommand(".uno:BorderBLTR", aArgs); +} + +void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + if ( rEvent.FeatureURL.Complete != ".uno:BorderReducedMode" ) + return; + + bool bValue; + if ( !(rEvent.State >>= bValue) ) + return; + + bParagraphMode = bValue; + //initial calls mustn't insert or remove elements + if(!mxFrameSet->GetItemCount()) + return; + + // set 12 border types for Writer, otherwise 15 for Calc. + bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsWriter ? 12 : 15) ); + bool bResize = false; + + if ( bTableMode && bParagraphMode ) + { + for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ ) + mxFrameSet->RemoveItem(i); + bResize = true; + } + else if ( !bTableMode && !bParagraphMode ) + { + for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ ) + mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second); + bResize = true; + } + + if ( bResize ) + { + CalcSizeValueSet(); + } +} + +void SvxFrameWindow_Impl::CalcSizeValueSet() +{ + weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea(); + const OutputDevice& rDevice = pDrawingArea->get_ref_device(); + Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() ); + Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize ); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + mxFrameSet->SetOutputSizePixel(aSize); +} + +void SvxFrameWindow_Impl::InitImageList() +{ + if (m_bIsWriter) + { + // Writer-specific aImgVec. + // Since Writer doesn't have diagonal borders, + // we have to use 12 border types here. + aImgVec = { + {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)}, + {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)}, + {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)}, + {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)}, + + {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)}, + {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)}, + {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)}, + {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)}, + + {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)}, + {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)}, + {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)}, + {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)} + }; + } + else + { + // Calc has diagonal borders feature. + // Therefore use additional 3 diagonal border types, + // which make border types 15 in total. + aImgVec = { + {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)}, + {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)}, + {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)}, + {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)}, + {BitmapEx(RID_SVXBMP_FRAME14), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALDOWN)}, // diagonal down border + + {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)}, + {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)}, + {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)}, + {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)}, + {BitmapEx(RID_SVXBMP_FRAME13), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALUP)}, // diagonal up border + + {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)}, + {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)}, + {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)}, + {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)}, + {BitmapEx(RID_SVXBMP_FRAME15), SvxResId(RID_SVXSTR_PARA_PRESET_CRISSCROSS)} // criss-cross border + }; + } +} + +static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ ) +{ + return SvxBorderLine::threeDMediumColor( aMain ); +} + +SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder") + , m_xControl(pControl) + , m_xLineStyleLb(new LineListBox) + , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xLineStyleLb)) + , m_bIsWriter(false) +{ + try + { + Reference< lang::XServiceInfo > xServices(m_xFrame->getController()->getModel(), UNO_QUERY_THROW); + m_bIsWriter = xServices->supportsService("com.sun.star.text.TextDocument"); + } + catch(const uno::Exception& ) + { + } + + m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); + + m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP ); + m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE) + :SvxResId(RID_SVXSTR_NONE) ); + + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::SOLID ), SvxBorderLineStyle::SOLID ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOTTED ), SvxBorderLineStyle::DOTTED ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DASHED ), SvxBorderLineStyle::DASHED ); + + // Double lines + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOUBLE ), SvxBorderLineStyle::DOUBLE ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_SMALLGAP ), SvxBorderLineStyle::THINTHICK_SMALLGAP, 20 ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_MEDIUMGAP ), SvxBorderLineStyle::THINTHICK_MEDIUMGAP ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_LARGEGAP ), SvxBorderLineStyle::THINTHICK_LARGEGAP ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_SMALLGAP ), SvxBorderLineStyle::THICKTHIN_SMALLGAP, 20 ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ), SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_LARGEGAP ), SvxBorderLineStyle::THICKTHIN_LARGEGAP ); + + // Engraved / Embossed + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::EMBOSSED ), SvxBorderLineStyle::EMBOSSED, 15, + &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor, + &lcl_mediumColor ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::ENGRAVED ), SvxBorderLineStyle::ENGRAVED, 15, + &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor, + &lcl_mediumColor ); + + // Inset / Outset + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::OUTSET ), SvxBorderLineStyle::OUTSET, 10, + &SvxBorderLine::lightColor, &SvxBorderLine::darkColor ); + m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10, + &SvxBorderLine::darkColor, &SvxBorderLine::lightColor ); + Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default + + m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) ); + + m_xContainer->set_help_id(HID_POPUP_LINE); + + aSize.AdjustWidth(6); + aSize.AdjustHeight(6); + aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize); + m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height()); + m_xLineStyleLb->SetOutputSizePixel(aSize); +} + +IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void) +{ + SvxLineItem aLineItem( SID_FRAME_LINESTYLE ); + SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle(); + + if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 ) + { + SvxBorderLine aTmp; + aTmp.SetBorderLineStyle( nStyle ); + aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field + aLineItem.SetLine( &aTmp ); + } + else + aLineItem.SetLine( nullptr ); + + Any a; + aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 ); + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineStyle", a) }; + + m_xControl->dispatchCommand( ".uno:LineStyle", aArgs ); + + m_xControl->EndPopupMode(); +} + +SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl( + const Reference< XDispatchProvider >& rDispatchProvider, + sal_uInt16 nSlotId, // Family-ID + const OUString& rCommand, // .uno: command bound to this item + SvxStyleToolBoxControl& rTbxCtl ) // controller instance, which the item is assigned to. + : SfxStatusListener( rDispatchProvider, nSlotId, rCommand ), + rControl( rTbxCtl ) +{ +} + +void SfxStyleControllerItem_Impl::StateChangedAtStatusListener( + SfxItemState eState, const SfxPoolItem* pState ) +{ + switch ( GetId() ) + { + case SID_STYLE_FAMILY1: + case SID_STYLE_FAMILY2: + case SID_STYLE_FAMILY3: + case SID_STYLE_FAMILY4: + case SID_STYLE_FAMILY5: + { + const sal_uInt16 nIdx = GetId() - SID_STYLE_FAMILY_START; + + if ( SfxItemState::DEFAULT == eState ) + { + const SfxTemplateItem* pStateItem = + dynamic_cast<const SfxTemplateItem*>( pState ); + DBG_ASSERT( pStateItem != nullptr, "SfxTemplateItem expected" ); + rControl.SetFamilyState( nIdx, pStateItem ); + } + else + rControl.SetFamilyState( nIdx, nullptr ); + break; + } + } +} + +struct SvxStyleToolBoxControl::Impl +{ + OUString aClearForm; + OUString aMore; + ::std::vector< std::pair< OUString, OUString > > aDefaultStyles; + bool bSpecModeWriter; + bool bSpecModeCalc; + + VclPtr<SvxStyleBox_Impl> m_xVclBox; + std::unique_ptr<SvxStyleBox_Base> m_xWeldBox; + SvxStyleBox_Base* m_pBox; + + Impl() + :aClearForm ( SvxResId( RID_SVXSTR_CLEARFORM ) ) + ,aMore ( SvxResId( RID_SVXSTR_MORE_STYLES ) ) + ,bSpecModeWriter ( false ) + ,bSpecModeCalc ( false ) + ,m_pBox ( nullptr ) + { + + + } + void InitializeStyles(const Reference < frame::XModel >& xModel) + { + aDefaultStyles.clear(); + + //now convert the default style names to the localized names + try + { + Reference< style::XStyleFamiliesSupplier > xStylesSupplier( xModel, UNO_QUERY_THROW ); + Reference< lang::XServiceInfo > xServices( xModel, UNO_QUERY_THROW ); + bSpecModeWriter = xServices->supportsService("com.sun.star.text.TextDocument"); + if(bSpecModeWriter) + { + Reference<container::XNameAccess> xParaStyles; + xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>= + xParaStyles; + static const std::vector<OUString> aWriterStyles = + { + "Standard", + "Text body", + "Title", + "Subtitle", + "Heading 1", + "Heading 2", + "Heading 3", + "Heading 4", + "Quotations", + "Preformatted Text" + }; + for( const OUString& aStyle: aWriterStyles ) + { + try + { + Reference< beans::XPropertySet > xStyle; + xParaStyles->getByName( aStyle ) >>= xStyle; + OUString sName; + xStyle->getPropertyValue("DisplayName") >>= sName; + if( !sName.isEmpty() ) + aDefaultStyles.push_back( + std::pair<OUString, OUString>(aStyle, sName) ); + } + catch( const uno::Exception& ) + {} + } + + } + else if( ( + bSpecModeCalc = xServices->supportsService( + "com.sun.star.sheet.SpreadsheetDocument"))) + { + static const char* aCalcStyles[] = + { + "Default", + "Accent 1", + "Accent 2", + "Accent 3", + "Heading 1", + "Heading 2", + "Result" + }; + Reference<container::XNameAccess> xCellStyles; + xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles; + for(const char* pCalcStyle : aCalcStyles) + { + try + { + const OUString sStyleName( OUString::createFromAscii( pCalcStyle ) ); + if( xCellStyles->hasByName( sStyleName ) ) + { + Reference< beans::XPropertySet > xStyle( xCellStyles->getByName( sStyleName), UNO_QUERY_THROW ); + OUString sName; + xStyle->getPropertyValue("DisplayName") >>= sName; + if( !sName.isEmpty() ) + aDefaultStyles.push_back( + std::pair<OUString, OUString>(sStyleName, sName) ); + } + } + catch( const uno::Exception& ) + {} + } + } + } + catch(const uno::Exception& ) + { + OSL_FAIL("error while initializing style names"); + } + } +}; + +// mapping table from bound items. BE CAREFUL this table must be in the +// same order as the uno commands bound to the slots SID_STYLE_FAMILY1..n +// MAX_FAMILIES must also be correctly set! +static const char* StyleSlotToStyleCommand[MAX_FAMILIES] = +{ + ".uno:CharStyle", + ".uno:ParaStyle", + ".uno:FrameStyle", + ".uno:PageStyle", + ".uno:TemplateFamily5" +}; + +SvxStyleToolBoxControl::SvxStyleToolBoxControl() + : pImpl(new Impl) + , pStyleSheetPool(nullptr) + , nActFamily(0xffff) +{ + for (sal_uInt16 i = 0; i < MAX_FAMILIES; ++i) + { + m_xBoundItems[i].clear(); + pFamilyState[i] = nullptr; + } +} + +SvxStyleToolBoxControl::~SvxStyleToolBoxControl() +{ +} + +void SAL_CALL SvxStyleToolBoxControl::initialize(const Sequence<Any>& rArguments) +{ + svt::ToolboxController::initialize(rArguments); + + // After initialize we should have a valid frame member where we can retrieve our + // dispatch provider. + if ( !m_xFrame.is() ) + return; + + pImpl->InitializeStyles(m_xFrame->getController()->getModel()); + Reference< XDispatchProvider > xDispatchProvider( m_xFrame->getController(), UNO_QUERY ); + for ( sal_uInt16 i=0; i<MAX_FAMILIES; i++ ) + { + m_xBoundItems[i] = new SfxStyleControllerItem_Impl( xDispatchProvider, + SID_STYLE_FAMILY_START + i, + OUString::createFromAscii( StyleSlotToStyleCommand[i] ), + *this ); + pFamilyState[i] = nullptr; + } +} + +// XComponent +void SAL_CALL SvxStyleToolBoxControl::dispose() +{ + svt::ToolboxController::dispose(); + + SolarMutexGuard aSolarMutexGuard; + pImpl->m_xVclBox.disposeAndClear(); + pImpl->m_xWeldBox.reset(); + pImpl->m_pBox = nullptr; + + for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems) + { + if (!pBoundItem) + continue; + pBoundItem->UnBind(); + } + unbindListener(); + + for( sal_uInt16 i=0; i<MAX_FAMILIES; i++ ) + { + if ( m_xBoundItems[i].is() ) + { + try + { + m_xBoundItems[i]->dispose(); + } + catch ( Exception& ) + { + } + + m_xBoundItems[i].clear(); + } + pFamilyState[i].reset(); + } + pStyleSheetPool = nullptr; + pImpl.reset(); +} + +OUString SvxStyleToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.StyleToolBoxControl"; +} + +sal_Bool SvxStyleToolBoxControl::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + +css::uno::Sequence< OUString > SvxStyleToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_StyleToolBoxControl_get_implementation( + css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxStyleToolBoxControl() ); +} + +void SAL_CALL SvxStyleToolBoxControl::update() +{ + for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems) + pBoundItem->ReBind(); + bindListener(); +} + +SfxStyleFamily SvxStyleToolBoxControl::GetActFamily() const +{ + switch ( nActFamily-1 + SID_STYLE_FAMILY_START ) + { + case SID_STYLE_FAMILY1: return SfxStyleFamily::Char; + case SID_STYLE_FAMILY2: return SfxStyleFamily::Para; + case SID_STYLE_FAMILY3: return SfxStyleFamily::Frame; + case SID_STYLE_FAMILY4: return SfxStyleFamily::Page; + case SID_STYLE_FAMILY5: return SfxStyleFamily::Pseudo; + default: + OSL_FAIL( "unknown style family" ); + break; + } + return SfxStyleFamily::Para; +} + +void SvxStyleToolBoxControl::FillStyleBox() +{ + SvxStyleBox_Base* pBox = pImpl->m_pBox; + + DBG_ASSERT( pStyleSheetPool, "StyleSheetPool not found!" ); + DBG_ASSERT( pBox, "Control not found!" ); + + if ( !(pStyleSheetPool && pBox && nActFamily!=0xffff) ) + return; + + const SfxStyleFamily eFamily = GetActFamily(); + SfxStyleSheetBase* pStyle = nullptr; + bool bDoFill = false; + + auto xIter = pStyleSheetPool->CreateIterator(eFamily, SfxStyleSearchBits::Used); + sal_uInt16 nCount = xIter->Count(); + + // Check whether fill is necessary + pStyle = xIter->First(); + //!!! TODO: This condition isn't right any longer, because we always show some default entries + //!!! so the list doesn't show the count + if ( nCount != pBox->get_count() ) + { + bDoFill = true; + } + else + { + sal_uInt16 i= 0; + while ( pStyle && !bDoFill ) + { + bDoFill = ( pBox->get_text(i) != pStyle->GetName() ); + pStyle = xIter->Next(); + i++; + } + } + + if ( !bDoFill ) + return; + + OUString aStrSel(pBox->get_active_text()); + pBox->freeze(); + pBox->clear(); + + std::vector<OUString> aStyles; + + // add used styles + pStyle = xIter->Next(); + while ( pStyle ) + { + aStyles.push_back(pStyle->GetName()); + pStyle = xIter->Next(); + } + + if (pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) + { + pBox->append_text(pImpl->aClearForm); + pBox->insert_separator(1, "separator"); + + // add default styles if less than 12 items + for( const auto &rStyle : pImpl->aDefaultStyles ) + { + if ( aStyles.size() + pBox->get_count() > 12) + break; + // insert default style only if not used (and added to rStyle before) + if (std::find(aStyles.begin(), aStyles.end(), rStyle.second) >= aStyles.end()) + pBox->append_text(rStyle.second); + } + } + std::sort(aStyles.begin(), aStyles.end()); + + for (const auto& rStyle : aStyles) + pBox->append_text(rStyle); + + if ((pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) && !comphelper::LibreOfficeKit::isActive()) + pBox->append_text(pImpl->aMore); + + pBox->thaw(); + pBox->set_active_or_entry_text(aStrSel); + pBox->SetFamily( eFamily ); +} + +void SvxStyleToolBoxControl::SelectStyle( const OUString& rStyleName ) +{ + SvxStyleBox_Base* pBox = pImpl->m_pBox; + DBG_ASSERT( pBox, "Control not found!" ); + + if ( !pBox ) + return; + + OUString aStrSel(pBox->get_active_text()); + + if ( !rStyleName.isEmpty() ) + { + OUString aNewStyle = rStyleName; + + auto aFound = std::find_if(pImpl->aDefaultStyles.begin(), pImpl->aDefaultStyles.end(), + [rStyleName] (auto it) { return it.first == rStyleName || it.second == rStyleName; } + ); + + if (aFound != pImpl->aDefaultStyles.end()) + aNewStyle = aFound->second; + + if ( aNewStyle != aStrSel ) + pBox->set_active_or_entry_text( aNewStyle ); + } + else + pBox->set_active(-1); + pBox->save_value(); +} + +void SvxStyleToolBoxControl::Update() +{ + SfxStyleSheetBasePool* pPool = nullptr; + SfxObjectShell* pDocShell = SfxObjectShell::Current(); + + if ( pDocShell ) + pPool = pDocShell->GetStyleSheetPool(); + + sal_uInt16 i; + for ( i=0; i<MAX_FAMILIES; i++ ) + if( pFamilyState[i] ) + break; + + if ( i==MAX_FAMILIES || !pPool ) + { + pStyleSheetPool = pPool; + return; + } + + + const SfxTemplateItem* pItem = nullptr; + + if ( nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get()) ) + // Current range not within allowed ranges or default + { + pStyleSheetPool = pPool; + nActFamily = 2; + + pItem = pFamilyState[nActFamily-1].get(); + if ( !pItem ) + { + nActFamily++; + pItem = pFamilyState[nActFamily-1].get(); + } + } + else if ( pPool != pStyleSheetPool ) + pStyleSheetPool = pPool; + + FillStyleBox(); // Decides by itself whether Fill is needed + + if ( pItem ) + SelectStyle( pItem->GetStyleName() ); +} + +void SvxStyleToolBoxControl::SetFamilyState( sal_uInt16 nIdx, + const SfxTemplateItem* pItem ) +{ + pFamilyState[nIdx].reset( pItem == nullptr ? nullptr : new SfxTemplateItem( *pItem ) ); + Update(); +} + +void SvxStyleToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + SolarMutexGuard aGuard; + + if (m_pToolbar) + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + else + { + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId( nId, &pToolBox ) ) + return; + pToolBox->EnableItem( nId, rEvent.IsEnabled ); + } + + if (rEvent.IsEnabled) + Update(); +} + +css::uno::Reference<css::awt::XWindow> SvxStyleToolBoxControl::createItemWindow(const css::uno::Reference< css::awt::XWindow>& rParent) +{ + uno::Reference< awt::XWindow > xItemWindow; + + if (m_pBuilder) + { + SolarMutexGuard aSolarMutexGuard; + + std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("applystyle")); + + xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get())); + + pImpl->m_xWeldBox.reset(new SvxStyleBox_Base(std::move(xWidget), + ".uno:StyleApply", + SfxStyleFamily::Para, + m_xFrame, + pImpl->aClearForm, + pImpl->aMore, + pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this)); + pImpl->m_pBox = pImpl->m_xWeldBox.get(); + } + else + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent); + if ( pParent ) + { + SolarMutexGuard aSolarMutexGuard; + + pImpl->m_xVclBox = VclPtr<SvxStyleBox_Impl>::Create(pParent, + ".uno:StyleApply", + SfxStyleFamily::Para, + m_xFrame, + pImpl->aClearForm, + pImpl->aMore, + pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this); + pImpl->m_pBox = pImpl->m_xVclBox.get(); + xItemWindow = VCLUnoHelper::GetInterface(pImpl->m_xVclBox); + } + } + + if (pImpl->m_pBox && !pImpl->aDefaultStyles.empty()) + pImpl->m_pBox->SetDefaultStyle(pImpl->aDefaultStyles[0].second); + + return xItemWindow; +} + +SvxFontNameToolBoxControl::SvxFontNameToolBoxControl() + : m_pBox(nullptr) +{ +} + +void SvxFontNameBox_Base::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent ) +{ + if ( !rEvent.IsEnabled ) + { + set_sensitive(false); + Update( nullptr ); + } + else + { + set_sensitive(true); + + css::awt::FontDescriptor aFontDesc; + if ( rEvent.State >>= aFontDesc ) + Update(&aFontDesc); + else { + // no active element; delete value in the display + m_xWidget->set_active(-1); + set_active_or_entry_text(""); + } + m_xWidget->save_value(); + } +} + +void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + SolarMutexGuard aGuard; + m_pBox->statusChanged_Impl(rEvent); + + if (m_pToolbar) + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + else + { + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId( nId, &pToolBox ) ) + return; + pToolBox->EnableItem( nId, rEvent.IsEnabled ); + } +} + +css::uno::Reference<css::awt::XWindow> SvxFontNameToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + uno::Reference< awt::XWindow > xItemWindow; + + if (m_pBuilder) + { + SolarMutexGuard aSolarMutexGuard; + + std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontnamecombobox")); + + xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get())); + + m_xWeldBox.reset(new SvxFontNameBox_Base(std::move(xWidget), m_xFrame, *this)); + m_pBox = m_xWeldBox.get(); + } + else + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent); + if ( pParent ) + { + SolarMutexGuard aSolarMutexGuard; + m_xVclBox = VclPtr<SvxFontNameBox_Impl>::Create(pParent, m_xFrame, *this); + m_pBox = m_xVclBox.get(); + xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox); + } + } + + return xItemWindow; +} + +void SvxFontNameToolBoxControl::dispose() +{ + ToolboxController::dispose(); + + SolarMutexGuard aSolarMutexGuard; + m_xVclBox.disposeAndClear(); + m_xWeldBox.reset(); + m_pBox = nullptr; +} + +OUString SvxFontNameToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.FontNameToolBoxControl"; +} + +sal_Bool SvxFontNameToolBoxControl::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + +css::uno::Sequence< OUString > SvxFontNameToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation( + css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxFontNameToolBoxControl() ); +} + +SvxColorToolBoxControl::SvxColorToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) : + ImplInheritanceHelper( rContext, nullptr, OUString() ), + m_bSplitButton(true), + m_nSlotId(0), + m_aColorSelectFunction(PaletteManager::DispatchColorCommand) +{ +} + +namespace { + +sal_uInt16 MapCommandToSlotId(const OUString& rCommand) +{ + if (rCommand == ".uno:Color") + return SID_ATTR_CHAR_COLOR; + else if (rCommand == ".uno:FontColor") + return SID_ATTR_CHAR_COLOR2; + else if (rCommand == ".uno:BackColor") // deprecated - use CharBackColor + return SID_ATTR_CHAR_COLOR_BACKGROUND; + else if (rCommand == ".uno:CharBackColor") + return SID_ATTR_CHAR_BACK_COLOR; + else if (rCommand == ".uno:BackgroundColor") + return SID_BACKGROUND_COLOR; + else if (rCommand == ".uno:TableCellBackgroundColor") + return SID_TABLE_CELL_BACKGROUND_COLOR; + else if (rCommand == ".uno:Extrusion3DColor") + return SID_EXTRUSION_3D_COLOR; + else if (rCommand == ".uno:XLineColor") + return SID_ATTR_LINE_COLOR; + else if (rCommand == ".uno:FillColor") + return SID_ATTR_FILL_COLOR; + else if (rCommand == ".uno:FrameLineColor") + return SID_FRAME_LINECOLOR; + + SAL_WARN("svx.tbxcrtls", "Unknown color command: " << rCommand); + return 0; +} + +} + +void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments ) +{ + PopupWindowController::initialize( rArguments ); + + m_nSlotId = MapCommandToSlotId( m_aCommandURL ); + + if ( m_nSlotId == SID_ATTR_LINE_COLOR || m_nSlotId == SID_ATTR_FILL_COLOR || + m_nSlotId == SID_FRAME_LINECOLOR || m_nSlotId == SID_BACKGROUND_COLOR ) + { + // Sidebar uses wide buttons for those. + m_bSplitButton = !m_bSidebar; + } + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName()); + OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, m_aCommandURL, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame)); + return; + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + { + m_xBtnUpdater.reset( new svx::VclToolboxButtonColorUpdater( m_nSlotId, nId, pToolBox, !m_bSplitButton, aCommandLabel, m_aCommandURL, m_xFrame ) ); + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) ); + } +} + +void SvxColorToolBoxControl::update() +{ + PopupWindowController::update(); + + switch( m_nSlotId ) + { + case SID_ATTR_CHAR_COLOR2: + addStatusListener( ".uno:CharColorExt"); + break; + + case SID_ATTR_CHAR_BACK_COLOR: + case SID_ATTR_CHAR_COLOR_BACKGROUND: + addStatusListener( ".uno:CharBackgroundExt"); + break; + + case SID_FRAME_LINECOLOR: + addStatusListener( ".uno:BorderTLBR"); + addStatusListener( ".uno:BorderBLTR"); + break; + } +} + +void SvxColorToolBoxControl::EnsurePaletteManager() +{ + if (!m_xPaletteManager) + { + m_xPaletteManager = std::make_shared<PaletteManager>(); + m_xPaletteManager->SetBtnUpdater(m_xBtnUpdater.get()); + } +} + +SvxColorToolBoxControl::~SvxColorToolBoxControl() +{ + if (m_xPaletteManager) + m_xPaletteManager->SetBtnUpdater(nullptr); +} + +void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& aColorSelectFunction) +{ + m_aColorSelectFunction = aColorSelectFunction; + if (m_xPaletteManager) + m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction); +} + +weld::Window* SvxColorToolBoxControl::GetParentFrame() const +{ + const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow(); + return Application::GetFrameWeld(xParent); +} + +std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow() +{ + EnsurePaletteManager(); + + auto xPopover = std::make_unique<ColorWindow>( + m_aCommandURL, + m_xPaletteManager, + m_aColorStatus, + m_nSlotId, + m_xFrame, + MenuOrToolMenuButton(m_pToolbar, m_aCommandURL), + [this] { return GetParentFrame(); }, + m_aColorSelectFunction); + + return xPopover; +} + +VclPtr<vcl::Window> SvxColorToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox)) + return nullptr; + + EnsurePaletteManager(); + + auto xPopover = std::make_unique<ColorWindow>( + m_aCommandURL, + m_xPaletteManager, + m_aColorStatus, + m_nSlotId, + m_xFrame, + MenuOrToolMenuButton(this, pToolBox, nId), + [this] { return GetParentFrame(); }, + m_aColorSelectFunction); + + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::move(xPopover), true); + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL, m_sModuleName); + OUString aWindowTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties); + mxInterimPopover->SetText(aWindowTitle); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +void SvxColorToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + if ( rEvent.FeatureURL.Complete == m_aCommandURL ) + { + if (m_pToolbar) + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + else + pToolBox->EnableItem( nId, rEvent.IsEnabled ); + } + + bool bValue; + if ( !m_bSplitButton ) + { + m_aColorStatus.statusChanged( rEvent ); + m_xBtnUpdater->Update( m_aColorStatus.GetColor() ); + } + else if ( rEvent.State >>= bValue ) + { + if (m_pToolbar) + m_pToolbar->set_item_active(m_aCommandURL, bValue); + else if (pToolBox) + pToolBox->CheckItem( nId, bValue ); + } +} + +void SvxColorToolBoxControl::execute(sal_Int16 /*nSelectModifier*/) +{ + if ( !m_bSplitButton ) + { + if (m_pToolbar) + { + // Toggle the popup also when toolbutton is activated + m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL)); + } + else + { + // Open the popup also when Enter key is pressed. + createPopupWindow(); + } + return; + } + + OUString aCommand = m_aCommandURL; + Color aColor = m_xBtnUpdater->GetCurrentColor(); + + switch( m_nSlotId ) + { + case SID_ATTR_CHAR_COLOR2 : + aCommand = ".uno:CharColorExt"; + break; + } + + auto aArgs( comphelper::InitPropertySequence( { + { m_aCommandURL.copy(5), css::uno::Any(aColor) } + } ) ); + dispatchCommand( aCommand, aArgs ); + + EnsurePaletteManager(); + OUString sColorName = m_xBtnUpdater->GetCurrentColorName(); + m_xPaletteManager->AddRecentColor(aColor, sColorName); +} + +sal_Bool SvxColorToolBoxControl::opensSubToolbar() +{ + // We mark this controller as a sub-toolbar controller, so we get notified + // (through updateImage method) on button image changes, and could redraw + // the last used color on top of it. + return true; +} + +void SvxColorToolBoxControl::updateImage() +{ + m_xBtnUpdater->Update(m_xBtnUpdater->GetCurrentColor(), true); +} + +OUString SvxColorToolBoxControl::getSubToolbarName() +{ + return OUString(); +} + +void SvxColorToolBoxControl::functionSelected( const OUString& /*rCommand*/ ) +{ +} + +OUString SvxColorToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.ColorToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxColorToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_ColorToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxColorToolBoxControl( rContext ) ); +} + +SvxFrameToolBoxControl::SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext ) + : svt::PopupWindowController( rContext, nullptr, OUString() ) +{ +} + +void SAL_CALL SvxFrameToolBoxControl::execute(sal_Int16 /*KeyModifier*/) +{ + if (m_pToolbar) + { + // Toggle the popup also when toolbutton is activated + m_pToolbar->set_menu_item_active(m_aCommandURL, !m_pToolbar->get_menu_item_active(m_aCommandURL)); + } + else + { + // Open the popup also when Enter key is pressed. + createPopupWindow(); + } +} + +void SvxFrameToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) +{ + svt::PopupWindowController::initialize( rArguments ); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY ); +} + +std::unique_ptr<WeldToolbarPopup> SvxFrameToolBoxControl::weldPopupWindow() +{ + if ( m_aCommandURL == ".uno:LineStyle" ) + return std::make_unique<SvxLineWindow_Impl>(this, m_pToolbar); + return std::make_unique<SvxFrameWindow_Impl>(this, m_pToolbar); +} + +VclPtr<vcl::Window> SvxFrameToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + if ( m_aCommandURL == ".uno:LineStyle" ) + { + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<SvxLineWindow_Impl>(this, pParent->GetFrameWeld()), true); + + mxInterimPopover->Show(); + + mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME_STYLE)); + + return mxInterimPopover; + } + + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<SvxFrameWindow_Impl>(this, pParent->GetFrameWeld()), true); + + mxInterimPopover->Show(); + + mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME)); + + return mxInterimPopover; +} + +OUString SvxFrameToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.FrameToolBoxControl"; +} + +css::uno::Sequence< OUString > SvxFrameToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_FrameToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxFrameToolBoxControl( rContext ) ); +} + +SvxCurrencyToolBoxControl::SvxCurrencyToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) : + PopupWindowController( rContext, nullptr, OUString() ), + m_eLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ), + m_nFormatKey( NUMBERFORMAT_ENTRY_NOT_FOUND ) +{ +} + +SvxCurrencyToolBoxControl::~SvxCurrencyToolBoxControl() {} + +namespace +{ + /** Implementation of the currency combo widget **/ + class SvxCurrencyList_Impl : public WeldToolbarPopup + { + private: + rtl::Reference<SvxCurrencyToolBoxControl> m_xControl; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::TreeView> m_xCurrencyLb; + std::unique_ptr<weld::Button> m_xOkBtn; + OUString& m_rSelectedFormat; + LanguageType& m_eSelectedLanguage; + + std::vector<OUString> m_aFormatEntries; + LanguageType m_eFormatLanguage; + DECL_LINK(RowActivatedHdl, weld::TreeView&, bool); + DECL_LINK(OKHdl, weld::Button&, void); + + virtual void GrabFocus() override; + + public: + SvxCurrencyList_Impl(SvxCurrencyToolBoxControl* pControl, weld::Widget* pParent, OUString& rSelectedFormat, LanguageType& eSelectedLanguage) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/currencywindow.ui", "CurrencyWindow") + , m_xControl(pControl) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xCurrencyLb(m_xBuilder->weld_tree_view("currency")) + , m_xOkBtn(m_xBuilder->weld_button("ok")) + , m_rSelectedFormat(rSelectedFormat) + , m_eSelectedLanguage(eSelectedLanguage) + { + const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable(); + sal_uInt16 nLen = rCurrencyTable.size(); + + SvNumberFormatter aFormatter( m_xControl->getContext(), LANGUAGE_SYSTEM ); + m_eFormatLanguage = aFormatter.GetLanguage(); + + const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &rCurrencies = pControl->GetCurrencySymbols( ); + + sal_uInt16 nPos = 0, nCount = 0; + sal_Int32 nSelectedPos = -1; + bool bIsSymbol; + NfWSStringsDtor aStringsDtor; + + OUString sLongestString; + + m_xCurrencyLb->freeze(); + for( const SvxCurrencyToolBoxControl::SvxCurrencyData& curr : rCurrencies ) + { + const OUString& rItem = curr.m_label; + sal_uInt16 rCurrencyIndex = rCurrencies[ nCount ].m_currencyIdx; + + if ( rCurrencyIndex < nLen ) + { + m_xCurrencyLb->append_text(rItem); + + if (rItem.getLength() > sLongestString.getLength()) + sLongestString = rItem; + + bIsSymbol = nPos >= nLen; + + sal_uInt16 nDefaultFormat; + const NfCurrencyEntry& rCurrencyEntry = rCurrencyTable[ rCurrencyIndex ]; + if (rCurrencyIndex == 0) + { + // Stored with system locale, but we want the resolved + // full LCID format string. For example + // "[$$-409]#,##0.00" instead of "[$$]#,##0.00". + NfCurrencyEntry aCurrencyEntry( rCurrencyEntry); + aCurrencyEntry.SetLanguage( LanguageTag( aCurrencyEntry.GetLanguage()).getLanguageType()); + nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, aCurrencyEntry, bIsSymbol); + } + else + { + nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, rCurrencyEntry, bIsSymbol); + } + const OUString& rFormatStr = aStringsDtor[ nDefaultFormat ]; + m_aFormatEntries.push_back( rFormatStr ); + if( rFormatStr == m_rSelectedFormat ) + nSelectedPos = nPos; + ++nPos; + } + ++nCount; + } + m_xCurrencyLb->thaw(); + // enable multiple selection enabled so we can start with nothing selected + m_xCurrencyLb->set_selection_mode(SelectionMode::Multiple); + m_xCurrencyLb->connect_row_activated( LINK( this, SvxCurrencyList_Impl, RowActivatedHdl ) ); + m_xLabel->set_label(SvxResId(RID_SVXSTR_TBLAFMT_CURRENCY)); + m_xCurrencyLb->select( nSelectedPos ); + m_xOkBtn->connect_clicked(LINK(this, SvxCurrencyList_Impl, OKHdl)); + + // gtk will initially make a best guess depending on the first few entries, so copy the probable + // longest entry to the start temporarily and force in the width at this point + m_xCurrencyLb->insert_text(0, sLongestString); + m_xCurrencyLb->set_size_request(m_xCurrencyLb->get_preferred_size().Width(), m_xCurrencyLb->get_height_rows(12)); + m_xCurrencyLb->remove(0); + } + }; + + void SvxCurrencyList_Impl::GrabFocus() + { + m_xCurrencyLb->grab_focus(); + } + + IMPL_LINK_NOARG(SvxCurrencyList_Impl, OKHdl, weld::Button&, void) + { + RowActivatedHdl(*m_xCurrencyLb); + } + + IMPL_LINK_NOARG(SvxCurrencyList_Impl, RowActivatedHdl, weld::TreeView&, bool) + { + if (!m_xControl.is()) + return true; + + // multiple selection enabled so we can start with nothing selected, + // so force single selection after something is picked + int nSelected = m_xCurrencyLb->get_selected_index(); + if (nSelected == -1) + return true; + + m_xCurrencyLb->set_selection_mode(SelectionMode::Single); + + m_rSelectedFormat = m_aFormatEntries[nSelected]; + m_eSelectedLanguage = m_eFormatLanguage; + + m_xControl->execute(nSelected + 1); + + m_xCurrencyLb->scroll_to_row(0); + + m_xControl->EndPopupMode(); + + return true; + } +} + +void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) +{ + PopupWindowController::initialize(rArguments); + + if (m_pToolbar) + { + mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar)); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + return; + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL) + pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId)); +} + +const SvxCurrencyToolBoxControl::SvxCurrencyVect_t &SvxCurrencyToolBoxControl::GetCurrencySymbols( ) { + inner_GetCurrencySymbols( true, m_currencies, m_mru_currencies ); + return m_currencies; +} + +void SvxCurrencyToolBoxControl::addMruCurrency(sal_Int16 currencyPosition) { + if (currencyPosition == 1) + return; + + const SvxCurrencyData& curr = m_currencies[currencyPosition]; + auto currencyIter = std::find( m_mru_currencies.begin(), m_mru_currencies.end(), curr ); + + if ( currencyIter != m_mru_currencies.end() ) + m_mru_currencies.erase( currencyIter ); + + m_mru_currencies.insert( m_mru_currencies.begin(), curr ); + if (m_mru_currencies.size() > MAX_MRU_CURRENCIES) + m_mru_currencies.resize( MAX_MRU_CURRENCIES ); +} + +std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow() +{ + return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage); +} + +VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createVclPopupWindow( vcl::Window* pParent ) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, + std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage)); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +void SvxCurrencyToolBoxControl::execute( sal_Int16 nSelectModifier ) +{ + sal_uInt32 nFormatKey; + if (m_aFormatString.isEmpty()) + nFormatKey = NUMBERFORMAT_ENTRY_NOT_FOUND; + else + { + if ( nSelectModifier > 0 ) + { + try + { + uno::Reference< util::XNumberFormatsSupplier > xRef( m_xFrame->getController()->getModel(), uno::UNO_QUERY ); + uno::Reference< util::XNumberFormats > rxNumberFormats( xRef->getNumberFormats(), uno::UNO_SET_THROW ); + css::lang::Locale aLocale = LanguageTag::convertToLocale( m_eLanguage ); + nFormatKey = rxNumberFormats->queryKey( m_aFormatString, aLocale, false ); + if ( nFormatKey == NUMBERFORMAT_ENTRY_NOT_FOUND ) + nFormatKey = rxNumberFormats->addNew( m_aFormatString, aLocale ); + addMruCurrency(nSelectModifier); + } + catch( const uno::Exception& ) + { + nFormatKey = m_nFormatKey; + } + } + else + nFormatKey = m_nFormatKey; + } + + if( nFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("NumberFormatCurrency", + nFormatKey) }; + dispatchCommand( m_aCommandURL, aArgs ); + m_nFormatKey = nFormatKey; + } + else + PopupWindowController::execute( nSelectModifier ); +} + +OUString SvxCurrencyToolBoxControl::getImplementationName() +{ + return "com.sun.star.comp.svx.CurrencyToolBoxControl"; +} + +css::uno::Sequence<OUString> SvxCurrencyToolBoxControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const & ) +{ + return cppu::acquire( new SvxCurrencyToolBoxControl( rContext ) ); +} + +Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible() +{ + FillList(); + return InterimItemWindow::CreateAccessible(); +} + +//static +sal_uInt16 const SvxCurrencyToolBoxControl::SvxCurrencyData::InvalidCurrency = INVALID_CURRENCY; + +SvxCurrencyToolBoxControl::SvxCurrencyData::SvxCurrencyData( + sal_uInt16 currencyIdx, + bool onlyIsoCode +) : + m_currencyIdx(currencyIdx), + m_onlyIsoCode(onlyIsoCode) +{} + +bool SvxCurrencyToolBoxControl::SvxCurrencyData::operator == (const SvxCurrencyData& other) const +{ + return + (m_currencyIdx == other.m_currencyIdx) && + (m_onlyIsoCode == other.m_onlyIsoCode); +} + +//static +void SvxCurrencyToolBoxControl::GetCurrencySymbols( std::vector<OUString>& rList, bool bFlag, + std::vector<sal_uInt16>& rCurrencyList ) +{ + SvxCurrencyVect_t currencies, mru_currencies; + + inner_GetCurrencySymbols(bFlag, currencies, mru_currencies); + + rList.resize(currencies.size()); + rCurrencyList.resize(currencies.size()); + + for (size_t j = 0; j < currencies.size(); j++) { + rList[j] = std::move(currencies[j].m_label); + rCurrencyList[j] = currencies[j].m_currencyIdx; + } +} + +//static +void SvxCurrencyToolBoxControl::inner_GetCurrencySymbols( + bool bFlag, + SvxCurrencyVect_t &pCurrencies, + SvxCurrencyVect_t &p_mru_currencies) +{ + const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable(); + sal_uInt16 nCount = rCurrencyTable.size(); + + // reserving space for mru currencies on top of vector after -1 element + pCurrencies.resize( p_mru_currencies.size() + 1); + std::fill( pCurrencies.begin() + 1, pCurrencies.end(), SvxCurrencyData() ); + + // lambda for vector insertion: mru currencies are on top + auto addCurrency = [&pCurrencies, &p_mru_currencies] + (SvxCurrencyData& curr, size_t position = SIZE_MAX) + { + auto mruIter = std::find(p_mru_currencies.begin(), p_mru_currencies.end(), curr); + + if (mruIter == p_mru_currencies.end()) { + if (position == SIZE_MAX) + pCurrencies.push_back( std::move(curr) ); + else + pCurrencies.insert( pCurrencies.begin() + position, std::move(curr) ); + } + else { + size_t index = mruIter - p_mru_currencies.begin(); + pCurrencies[index] = std::move(curr); + } + }; + + SvxCurrencyData aCurr( sal_uInt16(-1) ); + aCurr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[0].GetSymbol() ) + " "; + aCurr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString( + rCurrencyTable[0].GetLanguage() ) ); + + pCurrencies[0] = aCurr; + if( bFlag ) { + aCurr.m_currencyIdx = 0; + addCurrency( aCurr ); + } + + sal_uInt16 nStart = pCurrencies.size(); + + CollatorWrapper aCollator( ::comphelper::getProcessComponentContext() ); + aCollator.loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 ); + + static constexpr OUString aTwoSpace(u" "_ustr); + + // appending "long symbol" list + for( sal_uInt16 i = 1; i < nCount; ++i ) + { + SvxCurrencyData curr( i ); + curr.m_label = ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() ); + curr.m_label += aTwoSpace; + curr.m_label += ApplyLreOrRleEmbedding( rCurrencyTable[i].GetSymbol() ); + curr.m_label += aTwoSpace; + curr.m_label += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString( + rCurrencyTable[i].GetLanguage() ) ); + + SvxCurrencyVect_t::size_type j = nStart; + for( ; j < pCurrencies.size(); ++j ) + if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 ) + break; // insert before first greater than + + addCurrency( curr, j ); + } + + // Append ISO codes to symbol list. + // XXX If this is to be changed, various other places would had to be + // adapted that assume this order! + size_t nCont = pCurrencies.size(); + + for ( sal_uInt16 i = 1; i < nCount; ++i ) + { + bool bInsert = true; + SvxCurrencyData curr( i, true ); + curr.m_label = ApplyLreOrRleEmbedding(rCurrencyTable[i].GetBankSymbol()); + + size_t j = nCont; + for ( ; j < pCurrencies.size() && bInsert; ++j ) + { + if( pCurrencies[j].m_label == curr.m_label ) + bInsert = false; + else if ( aCollator.compareString( curr.m_label, pCurrencies[j].m_label ) < 0 ) + break; // insert before first greater than + } + if ( bInsert ) + addCurrency( curr, j ); + } + + for ( int j = p_mru_currencies.size() - 1; j > 0; j-- ) + if ( pCurrencies[j].m_currencyIdx == SvxCurrencyData::InvalidCurrency ) + pCurrencies.erase( pCurrencies.begin() + j ); +} + +ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl) + : mpControl(pControl) +{ +} + +void ListBoxColorWrapper::operator()( + [[maybe_unused]] const OUString& /*rCommand*/, const NamedColor& rColor) +{ + mpControl->Selected(rColor); +} + +void ColorListBox::EnsurePaletteManager() +{ + if (!m_xPaletteManager) + { + m_xPaletteManager = std::make_shared<PaletteManager>(); + m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper)); + } +} + +void ColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton) +{ + m_nSlotId = nSlotId; + m_bShowNoneButton = bShowNoneButton; + m_xButton->set_popover(nullptr); + m_xColorWindow.reset(); + m_aSelectedColor = bShowNoneButton ? GetNoneColor() : GetAutoColor(m_nSlotId); + ShowPreview(m_aSelectedColor); + createColorWindow(); +} + +ColorListBox::ColorListBox(std::unique_ptr<weld::MenuButton> pControl, + TopLevelParentFunction aTopLevelParentFunction, + const ColorListBox* pCache) + : m_xButton(std::move(pControl)) + , m_aColorWrapper(this) + , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor()) + , m_nSlotId(0) + , m_bShowNoneButton(false) + , m_aTopLevelParentFunction(std::move(aTopLevelParentFunction)) +{ + m_xButton->connect_toggled(LINK(this, ColorListBox, ToggleHdl)); + m_aSelectedColor = GetAutoColor(m_nSlotId); + if (!pCache) + LockWidthRequest(CalcBestWidthRequest()); + else + { + LockWidthRequest(pCache->m_xButton->get_size_request().Width()); + m_xPaletteManager.reset(pCache->m_xPaletteManager->Clone()); + m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper)); + } + ShowPreview(m_aSelectedColor); +} + +IMPL_LINK(ColorListBox, ToggleHdl, weld::Toggleable&, rButton, void) +{ + if (rButton.get_active()) + { + ColorWindow* pColorWindow = getColorWindow(); + if (pColorWindow && !comphelper::LibreOfficeKit::isActive()) + pColorWindow->GrabFocus(); + } +} + +ColorListBox::~ColorListBox() +{ +} + +ColorWindow* ColorListBox::getColorWindow() const +{ + if (!m_xColorWindow) + const_cast<ColorListBox*>(this)->createColorWindow(); + return m_xColorWindow.get(); +} + +void ColorListBox::createColorWindow() +{ + const SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr; + css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>()); + + EnsurePaletteManager(); + + m_xColorWindow.reset(new ColorWindow( + OUString() /*m_aCommandURL*/, + m_xPaletteManager, + m_aColorStatus, + m_nSlotId, + xFrame, + m_xButton.get(), + m_aTopLevelParentFunction, + m_aColorWrapper)); + + SetNoSelection(); + m_xButton->set_popover(m_xColorWindow->getTopLevel()); + if (m_bShowNoneButton) + m_xColorWindow->ShowNoneButton(); + m_xColorWindow->SelectEntry(m_aSelectedColor); +} + +void ColorListBox::SelectEntry(const NamedColor& rColor) +{ + if (o3tl::trim(rColor.m_aName).empty()) + { + SelectEntry(rColor.m_aColor); + return; + } + ColorWindow* pColorWindow = getColorWindow(); + pColorWindow->SelectEntry(rColor); + m_aSelectedColor = pColorWindow->GetSelectEntryColor(); + ShowPreview(m_aSelectedColor); +} + +void ColorListBox::SelectEntry(const Color& rColor) +{ + ColorWindow* pColorWindow = getColorWindow(); + pColorWindow->SelectEntry(rColor); + m_aSelectedColor = pColorWindow->GetSelectEntryColor(); + ShowPreview(m_aSelectedColor); +} + +void ColorListBox::Selected(const NamedColor& rColor) +{ + ShowPreview(rColor); + m_aSelectedColor = rColor; + if (m_aSelectedLink.IsSet()) + m_aSelectedLink.Call(*this); +} + +//to avoid the box resizing every time the color is changed to +//the optimal size of the individual color, get the longest +//standard color and stick with that as the size for all +int ColorListBox::CalcBestWidthRequest() +{ + NamedColor aLongestColor; + tools::Long nMaxStandardColorTextWidth = 0; + XColorListRef const xColorTable = XColorList::CreateStdColorList(); + for (tools::Long i = 0; i != xColorTable->Count(); ++i) + { + XColorEntry& rEntry = *xColorTable->GetColor(i); + auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width(); + if (nColorTextWidth > nMaxStandardColorTextWidth) + { + nMaxStandardColorTextWidth = nColorTextWidth; + aLongestColor.m_aName = rEntry.GetName(); + } + } + ShowPreview(aLongestColor); + return m_xButton->get_preferred_size().Width(); +} + +void ColorListBox::LockWidthRequest(int nWidth) +{ + m_xButton->set_size_request(nWidth, -1); +} + +void ColorListBox::ShowPreview(const NamedColor &rColor) +{ + // ScGridWindow::UpdateAutoFilterFromMenu is similar + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize()); + + ScopedVclPtrInstance<VirtualDevice> xDevice; + xDevice->SetOutputSize(aImageSize); + const tools::Rectangle aRect(Point(0, 0), aImageSize); + if (m_bShowNoneButton && rColor.m_aColor == COL_NONE_COLOR) + { + const Color aW(COL_WHITE); + const Color aG(0xef, 0xef, 0xef); + int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1; + int nCheckSize = nMinDim / 3; + xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG); + xDevice->SetFillColor(); + } + else + { + if (rColor.m_aColor == COL_AUTO) + xDevice->SetFillColor(m_aAutoDisplayColor); + else + xDevice->SetFillColor(rColor.m_aColor); + } + + xDevice->SetLineColor(rStyleSettings.GetDisableColor()); + xDevice->DrawRect(aRect); + + m_xButton->set_image(xDevice.get()); + m_xButton->set_label(rColor.m_aName); +} + +MenuOrToolMenuButton::MenuOrToolMenuButton(weld::MenuButton* pMenuButton) + : m_pMenuButton(pMenuButton) + , m_pToolbar(nullptr) + , m_pControl(nullptr) + , m_nId(0) +{ +} + +MenuOrToolMenuButton::MenuOrToolMenuButton(weld::Toolbar* pToolbar, OUString aIdent) + : m_pMenuButton(nullptr) + , m_pToolbar(pToolbar) + , m_aIdent(std::move(aIdent)) + , m_pControl(nullptr) + , m_nId(0) +{ +} + +MenuOrToolMenuButton::MenuOrToolMenuButton(SvxColorToolBoxControl* pControl, ToolBox* pToolbar, ToolBoxItemId nId) + : m_pMenuButton(nullptr) + , m_pToolbar(nullptr) + , m_pControl(pControl) + , m_xToolBox(pToolbar) + , m_nId(nId) +{ +} + +MenuOrToolMenuButton::~MenuOrToolMenuButton() +{ +} + +bool MenuOrToolMenuButton::get_active() const +{ + if (m_pMenuButton) + return m_pMenuButton->get_active(); + if (m_pToolbar) + return m_pToolbar->get_menu_item_active(m_aIdent); + return m_xToolBox->GetDownItemId() == m_nId; +} + +void MenuOrToolMenuButton::set_inactive() const +{ + if (m_pMenuButton) + { + if (m_pMenuButton->get_active()) + m_pMenuButton->set_active(false); + return; + } + if (m_pToolbar) + { + if (m_pToolbar->get_menu_item_active(m_aIdent)) + m_pToolbar->set_menu_item_active(m_aIdent, false); + return; + } + m_pControl->EndPopupMode(); +} + +weld::Widget* MenuOrToolMenuButton::get_widget() const +{ + if (m_pMenuButton) + return m_pMenuButton; + if (m_pToolbar) + return m_pToolbar; + return m_xToolBox->GetFrameWeld(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbunocontroller.cxx b/svx/source/tbxctrls/tbunocontroller.cxx new file mode 100644 index 0000000000..148098c10e --- /dev/null +++ b/svx/source/tbxctrls/tbunocontroller.cxx @@ -0,0 +1,515 @@ +/* -*- 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/frame/XFrame.hpp> +#include <com/sun/star/frame/status/FontHeight.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <rtl/math.hxx> +#include <utility> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weldutils.hxx> +#include <vcl/window.hxx> +#include <vcl/settings.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <sfx2/viewsh.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/ctrlbox.hxx> +#include <svtools/toolboxcontroller.hxx> +#include <tools/json_writer.hxx> +#include <vcl/toolbox.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <memory> + +#include <vcl/InterimItemWindow.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SvxFontSizeBox_Base; +class SvxFontSizeBox_Impl; + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, lang::XServiceInfo> FontHeightToolBoxControl_Base; +class FontHeightToolBoxControl : public FontHeightToolBoxControl_Base +{ + public: + explicit FontHeightToolBoxControl( + const css::uno::Reference< css::uno::XComponentContext >& rServiceManager ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + + // XToolbarController + virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override; + virtual void SAL_CALL click() override; + virtual void SAL_CALL doubleClick() override; + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override; + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + void dispatchCommand( const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); + using svt::ToolboxController::dispatchCommand; + + private: + VclPtr<SvxFontSizeBox_Impl> m_xVclBox; + std::unique_ptr<SvxFontSizeBox_Base> m_xWeldBox; + SvxFontSizeBox_Base* m_pBox; +}; + +class SvxFontSizeBox_Base +{ +public: + SvxFontSizeBox_Base(std::unique_ptr<weld::ComboBox> xWidget, + uno::Reference< frame::XFrame > _xFrame, + FontHeightToolBoxControl& rCtrl); + + virtual ~SvxFontSizeBox_Base() + { + } + + virtual void set_sensitive(bool bSensitive) + { + m_xWidget->set_sensitive(bSensitive); + } + + void statusChanged_Impl(tools::Long nHeight, bool bErase); + void UpdateFont(); + +protected: + FontHeightToolBoxControl& m_rCtrl; + OUString m_aCurText; + bool m_bRelease; + uno::Reference<frame::XFrame> m_xFrame; + std::unique_ptr<FontSizeBox> m_xWidget; + + void ReleaseFocus_Impl(); + void Select(); + + virtual bool DoKeyInput(const KeyEvent& rKEvt); + + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(ActivateHdl, weld::ComboBox&, bool); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void); +}; + +class SvxFontSizeBox_Impl final : public InterimItemWindow + , public SvxFontSizeBox_Base +{ +public: + SvxFontSizeBox_Impl(vcl::Window* pParent, + const uno::Reference< frame::XFrame >& _xFrame, + FontHeightToolBoxControl& rCtrl); + + virtual void dispose() override + { + m_xWidget.reset(); + InterimItemWindow::dispose(); + } + + virtual void GetFocus() override + { + if (m_xWidget) + m_xWidget->grab_focus(); + InterimItemWindow::GetFocus(); + } + + virtual ~SvxFontSizeBox_Impl() override + { + disposeOnce(); + } + + void SetOptimalSize(); + + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + + virtual void set_sensitive(bool bSensitive) override + { + m_xWidget->set_sensitive(bSensitive); + if (bSensitive) + InterimItemWindow::Enable(); + else + InterimItemWindow::Disable(); + } + +private: + virtual bool DoKeyInput(const KeyEvent& rKEvt) override; +}; + +SvxFontSizeBox_Base::SvxFontSizeBox_Base(std::unique_ptr<weld::ComboBox> xWidget, + uno::Reference<frame::XFrame> xFrame, + FontHeightToolBoxControl& rCtrl) + : m_rCtrl(rCtrl) + , m_bRelease(true) + , m_xFrame(std::move(xFrame)) + , m_xWidget(new FontSizeBox(std::move(xWidget))) +{ + m_xWidget->set_value(0); + m_xWidget->set_active_or_entry_text(""); + m_xWidget->disable_entry_completion(); + + m_xWidget->connect_changed(LINK(this, SvxFontSizeBox_Base, SelectHdl)); + m_xWidget->connect_key_press(LINK(this, SvxFontSizeBox_Base, KeyInputHdl)); + m_xWidget->connect_entry_activate(LINK(this, SvxFontSizeBox_Base, ActivateHdl)); + m_xWidget->connect_focus_out(LINK(this, SvxFontSizeBox_Base, FocusOutHdl)); + m_xWidget->connect_get_property_tree(LINK(this, SvxFontSizeBox_Base, DumpAsPropertyTreeHdl)); +} + +void SvxFontSizeBox_Base::ReleaseFocus_Impl() +{ + if ( !m_bRelease ) + { + m_bRelease = true; + return; + } + + if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() ) + m_xFrame->getContainerWindow()->setFocus(); +} + +IMPL_LINK(SvxFontSizeBox_Base, SelectHdl, weld::ComboBox&, rCombo, void) +{ + if (rCombo.changed_by_direct_pick()) // only when picked from the list + Select(); +} + +IMPL_LINK_NOARG(SvxFontSizeBox_Base, ActivateHdl, weld::ComboBox&, bool) +{ + Select(); + return true; +} + +void SvxFontSizeBox_Base::Select() +{ + sal_Int64 nSelVal = m_xWidget->get_value(); + float fSelVal = float( nSelVal ) / 10; + + uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("FontHeight.Height", + fSelVal) }; + + /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call. + This instance may be deleted in the meantime (i.e. when a dialog is opened + while in Dispatch()), accessing members will crash in this case. */ + ReleaseFocus_Impl(); + + m_rCtrl.dispatchCommand( aArgs ); +} + +void SvxFontSizeBox_Base::statusChanged_Impl( tools::Long nPoint, bool bErase ) +{ + if ( !bErase ) + { + // convert the metric + tools::Long nVal = nPoint; + + // changed => set new value + if (m_xWidget->get_value() != nVal) + m_xWidget->set_value(nVal); + } + else + { + // delete value in the display + m_xWidget->set_value(-1L); + m_xWidget->set_active_or_entry_text(""); + } + m_aCurText = m_xWidget->get_active_text(); +} + +void SvxFontSizeBox_Base::UpdateFont() +{ + // filling up the sizes list + auto nOldVal = m_xWidget->get_value(); // memorize old value + FontList aFontList(Application::GetDefaultDevice()); + + m_xWidget->Fill(&aFontList); + + m_xWidget->set_value(nOldVal); // restore old value + m_aCurText = m_xWidget->get_active_text(); // memorize to reset at ESC +} + +IMPL_LINK(SvxFontSizeBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return DoKeyInput(rKEvt); +} + +bool SvxFontSizeBox_Base::DoKeyInput(const KeyEvent& rKEvt) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch (nCode) + { + case KEY_TAB: + m_bRelease = false; + Select(); + break; + + case KEY_ESCAPE: + m_xWidget->set_active_or_entry_text(m_aCurText); + if (!m_rCtrl.IsInSidebar()) + { + ReleaseFocus_Impl(); + bHandled = true; + } + break; + } + + return bHandled; +} + +bool SvxFontSizeBox_Impl::DoKeyInput(const KeyEvent& rKEvt) +{ + return SvxFontSizeBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(SvxFontSizeBox_Base, FocusOutHdl, weld::Widget&, void) +{ + if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus + m_xWidget->set_active_or_entry_text(m_aCurText); +} + +void SvxFontSizeBox_Impl::SetOptimalSize() +{ + SetSizePixel(get_preferred_size()); +} + +SvxFontSizeBox_Impl::SvxFontSizeBox_Impl(vcl::Window* pParent, + const uno::Reference<frame::XFrame>& rFrame, + FontHeightToolBoxControl& rCtrl) + : InterimItemWindow(pParent, "svx/ui/fontsizebox.ui", "FontSizeBox", true, reinterpret_cast<sal_uInt64>(SfxViewShell::Current())) + , SvxFontSizeBox_Base(m_xBuilder->weld_combo_box("fontsizecombobox"), rFrame, rCtrl) +{ +} + +void SvxFontSizeBox_Impl::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + SetOptimalSize(); + } +} + +IMPL_LINK(SvxFontSizeBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void) +{ + { + auto entriesNode = rJsonWriter.startNode("entries"); + for (int i = 0, nCount = m_xWidget->get_count(); i < nCount; ++i) + { + auto entryNode = rJsonWriter.startNode(""); + rJsonWriter.put("", m_xWidget->get_text(i)); + } + } + + int nActive = m_xWidget->get_active(); + rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1)); + { + auto selectedNode = rJsonWriter.startNode("selectedEntries"); + if (nActive != -1) + { + auto node = rJsonWriter.startNode(""); + rJsonWriter.put("", static_cast<sal_Int32>(nActive)); + } + } + + rJsonWriter.put("command", ".uno:FontHeight"); +} + +FontHeightToolBoxControl::FontHeightToolBoxControl( const uno::Reference< uno::XComponentContext >& rxContext ) + : FontHeightToolBoxControl_Base( rxContext, + uno::Reference< frame::XFrame >(), + ".uno:FontHeight" ), + m_pBox( nullptr ) +{ + addStatusListener( ".uno:CharFontName"); +} + +// XServiceInfo +sal_Bool SAL_CALL FontHeightToolBoxControl::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +OUString SAL_CALL FontHeightToolBoxControl::getImplementationName() +{ + return "com.sun.star.svx.FontHeightToolBoxController"; +} + +uno::Sequence< OUString > SAL_CALL FontHeightToolBoxControl::getSupportedServiceNames( ) +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL FontHeightToolBoxControl::dispose() +{ + svt::ToolboxController::dispose(); + + SolarMutexGuard aSolarMutexGuard; + m_xVclBox.disposeAndClear(); + m_xWeldBox.reset(); + m_pBox = nullptr; +} + +// XStatusListener +void SAL_CALL FontHeightToolBoxControl::statusChanged( + const frame::FeatureStateEvent& rEvent ) +{ + if ( !m_pBox ) + return; + + SolarMutexGuard aSolarMutexGuard; + if (rEvent.FeatureURL.Path == "FontHeight") + { + if ( rEvent.IsEnabled ) + { + m_pBox->set_sensitive(true); + frame::status::FontHeight aFontHeight; + if ( rEvent.State >>= aFontHeight ) + { + // tdf#83090 - correctly round the height of the font + aFontHeight.Height = rtl::math::round(10. * aFontHeight.Height); + m_pBox->statusChanged_Impl(tools::Long(aFontHeight.Height), false); + } + else + m_pBox->statusChanged_Impl( tools::Long( -1 ), true ); + } + else + { + m_pBox->set_sensitive(false); + m_pBox->statusChanged_Impl( tools::Long( -1 ), true ); + } + + if (m_pToolbar) + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + else + { + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + pToolBox->EnableItem(nId, rEvent.IsEnabled); + } + } + else if ( rEvent.FeatureURL.Path == "CharFontName" ) + { + m_pBox->UpdateFont(); + } +} + +// XToolbarController +void SAL_CALL FontHeightToolBoxControl::execute( sal_Int16 /*KeyModifier*/ ) +{ +} + +void SAL_CALL FontHeightToolBoxControl::click() +{ +} + +void SAL_CALL FontHeightToolBoxControl::doubleClick() +{ +} + +uno::Reference< awt::XWindow > SAL_CALL FontHeightToolBoxControl::createPopupWindow() +{ + return uno::Reference< awt::XWindow >(); +} + +uno::Reference< awt::XWindow > SAL_CALL FontHeightToolBoxControl::createItemWindow( + const uno::Reference< awt::XWindow >& xParent ) +{ + uno::Reference< awt::XWindow > xItemWindow; + + if (m_pBuilder) + { + SolarMutexGuard aSolarMutexGuard; + + std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontsizecombobox")); + + xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get())); + + m_xWeldBox.reset(new SvxFontSizeBox_Base(std::move(xWidget), m_xFrame, *this)); + m_pBox = m_xWeldBox.get(); + //Get the box to fill itself with all its sizes + m_pBox->UpdateFont(); + } + else + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + SolarMutexGuard aSolarMutexGuard; + m_xVclBox = VclPtr<SvxFontSizeBox_Impl>::Create( pParent, m_xFrame, *this ); + m_pBox = m_xVclBox.get(); + //Get the box to fill itself with all its sizes + m_pBox->UpdateFont(); + //Make it size itself to its optimal size re above sizes + m_xVclBox->SetOptimalSize(); + xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox); + } + } + + return xItemWindow; +} + +void FontHeightToolBoxControl::dispatchCommand( + const uno::Sequence< beans::PropertyValue >& rArgs ) +{ + uno::Reference< frame::XDispatchProvider > xDispatchProvider( m_xFrame, uno::UNO_QUERY ); + if ( xDispatchProvider.is() ) + { + util::URL aURL; + uno::Reference< frame::XDispatch > xDispatch; + uno::Reference< util::XURLTransformer > xURLTransformer = getURLTransformer(); + + aURL.Complete = ".uno:FontHeight"; + xURLTransformer->parseStrict( aURL ); + xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 ); + if ( xDispatch.is() ) + xDispatch->dispatch( aURL, rArgs ); + } +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_FontHeightToolBoxController_get_implementation( + css::uno::XComponentContext *rxContext, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FontHeightToolBoxControl(rxContext)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbunosearchcontrollers.cxx b/svx/source/tbxctrls/tbunosearchcontrollers.cxx new file mode 100644 index 0000000000..8e833167ea --- /dev/null +++ b/svx/source/tbxctrls/tbunosearchcontrollers.cxx @@ -0,0 +1,1491 @@ +/* -*- 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 <map> +#include <utility> +#include <vector> + +#include <config_feature_desktop.h> +#include <officecfg/Office/Common.hxx> + +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> + +#include <comphelper/propertysequence.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/DispatchDescriptor.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> + +#include <vcl/InterimItemWindow.hxx> +#include <svl/ctloptions.hxx> +#include <svl/srchitem.hxx> +#include <svtools/acceleratorexecute.hxx> +#include <svtools/toolboxcontroller.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/svapp.hxx> +#include <svx/labelitemwindow.hxx> +#include <svx/srchdlg.hxx> +#include <vcl/event.hxx> + +#include <findtextfield.hxx> + +using namespace css; + +namespace { + +constexpr OUString COMMAND_FINDTEXT = u".uno:FindText"_ustr; +constexpr OUString COMMAND_DOWNSEARCH = u".uno:DownSearch"_ustr; +constexpr OUString COMMAND_UPSEARCH = u".uno:UpSearch"_ustr; +constexpr OUStringLiteral COMMAND_FINDALL = u".uno:FindAll"; +constexpr OUString COMMAND_MATCHCASE = u".uno:MatchCase"_ustr; +constexpr OUString COMMAND_SEARCHFORMATTED = u".uno:SearchFormattedDisplayString"_ustr; + +class CheckButtonItemWindow final : public InterimItemWindow +{ +public: + CheckButtonItemWindow(vcl::Window* pParent, const OUString& rLabel) + : InterimItemWindow(pParent, "svx/ui/checkbuttonbox.ui", "CheckButtonBox") + , m_xWidget(m_xBuilder->weld_check_button("checkbutton")) + { + InitControlBase(m_xWidget.get()); + + m_xWidget->connect_key_press(LINK(this, CheckButtonItemWindow, KeyInputHdl)); + m_xWidget->set_label(rLabel); + SetSizePixel(m_xWidget->get_preferred_size()); + } + + bool get_active() const + { + return m_xWidget->get_active(); + } + + virtual void dispose() override + { + m_xWidget.reset(); + InterimItemWindow::dispose(); + } + + virtual ~CheckButtonItemWindow() override + { + disposeOnce(); + } + +private: + std::unique_ptr<weld::CheckButton> m_xWidget; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); +}; + +IMPL_LINK(CheckButtonItemWindow, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) +{ + return ChildKeyInput(rKeyEvent); +} + +void impl_executeSearch( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::frame::XFrame >& xFrame, + const ToolBox* pToolBox, + const bool aSearchBackwards, + const bool aFindAll = false ) +{ + css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( rxContext ) ); + css::util::URL aURL; + aURL.Complete = ".uno:ExecuteSearch"; + xURLTransformer->parseStrict(aURL); + + OUString sFindText; + bool aMatchCase = false; + bool bSearchFormatted = false; + if ( pToolBox ) + { + ToolBox::ImplToolItems::size_type nItemCount = pToolBox->GetItemCount(); + for ( ToolBox::ImplToolItems::size_type i=0; i<nItemCount; ++i ) + { + ToolBoxItemId id = pToolBox->GetItemId(i); + OUString sItemCommand = pToolBox->GetItemCommand(id); + if ( sItemCommand == COMMAND_FINDTEXT ) + { + FindTextFieldControl* pItemWin = static_cast<FindTextFieldControl*>(pToolBox->GetItemWindow(id)); + if (pItemWin) + { + sFindText = pItemWin->get_active_text(); + if (aFindAll && !pItemWin->ControlHasFocus()) + pItemWin->GetFocus(); + } + } else if ( sItemCommand == COMMAND_MATCHCASE ) + { + CheckButtonItemWindow* pItemWin = static_cast<CheckButtonItemWindow*>(pToolBox->GetItemWindow(id)); + if (pItemWin) + aMatchCase = pItemWin->get_active(); + } else if ( sItemCommand == COMMAND_SEARCHFORMATTED ) + { + CheckButtonItemWindow* pItemWin = static_cast<CheckButtonItemWindow*>(pToolBox->GetItemWindow(id)); + if (pItemWin) + bSearchFormatted = pItemWin->get_active(); + } + } + } + + TransliterationFlags nFlags = TransliterationFlags::NONE; + if (!aMatchCase) + nFlags |= TransliterationFlags::IGNORE_CASE; + if (SvtCTLOptions::IsCTLFontEnabled()) + nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL + | TransliterationFlags::IGNORE_KASHIDA_CTL; + + auto aArgs( comphelper::InitPropertySequence( { + { "SearchItem.SearchString", css::uno::Any( sFindText ) }, + // Related tdf#102506: make Find Bar Ctrl+F searching by value by default + { "SearchItem.CellType", css::uno::Any( sal_Int16(SvxSearchCellType::VALUE) ) }, + { "SearchItem.Backward", css::uno::Any( aSearchBackwards ) }, + { "SearchItem.SearchFlags", css::uno::Any( sal_Int32(0) ) }, + { "SearchItem.TransliterateFlags", css::uno::Any( static_cast<sal_Int32>(nFlags) ) }, + { "SearchItem.Command", css::uno::Any( static_cast<sal_Int16>(aFindAll ?SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND ) ) }, + { "SearchItem.AlgorithmType", css::uno::Any( sal_Int16(css::util::SearchAlgorithms_ABSOLUTE) ) }, + { "SearchItem.AlgorithmType2", css::uno::Any( sal_Int16(css::util::SearchAlgorithms2::ABSOLUTE) ) }, + { "SearchItem.SearchFormatted", css::uno::Any( bSearchFormatted ) } + } ) ); + + css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, css::uno::UNO_QUERY); + if ( xDispatchProvider.is() ) + { + css::uno::Reference< css::frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 ); + if ( xDispatch.is() && !aURL.Complete.isEmpty() ) + xDispatch->dispatch( aURL, aArgs ); + } +} + +} + +// tdf#154818 - remember last search string +OUString FindTextFieldControl::m_sRememberedSearchString; + +FindTextFieldControl::FindTextFieldControl( vcl::Window* pParent, + css::uno::Reference< css::frame::XFrame > xFrame, + css::uno::Reference< css::uno::XComponentContext > xContext) : + InterimItemWindow(pParent, "svx/ui/findbox.ui", "FindBox"), + m_nAsyncGetFocusId(nullptr), + m_xWidget(m_xBuilder->weld_combo_box("find")), + m_xFrame(std::move(xFrame)), + m_xContext(std::move(xContext)), + m_pAcc(svt::AcceleratorExecute::createAcceleratorHelper()) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->set_entry_placeholder_text(SvxResId(RID_SVXSTR_FINDBAR_FIND)); + m_xWidget->set_entry_completion(true, true); + m_pAcc->init(m_xContext, m_xFrame); + + m_xWidget->connect_focus_in(LINK(this, FindTextFieldControl, FocusInHdl)); + m_xWidget->connect_key_press(LINK(this, FindTextFieldControl, KeyInputHdl)); + m_xWidget->connect_entry_activate(LINK(this, FindTextFieldControl, ActivateHdl)); + + m_xWidget->set_size_request(250, -1); + SetSizePixel(m_xWidget->get_preferred_size()); + + // tdf#154269 - respect FindReplaceRememberedSearches expert option + m_nRememberSize = officecfg::Office::Common::Misc::FindReplaceRememberedSearches::get(); + if (m_nRememberSize < 1) + m_nRememberSize = 1; +} + +void FindTextFieldControl::Remember_Impl(const OUString& rStr) +{ + if (rStr.isEmpty()) + return; + + // tdf#154818 - rearrange the search items + const auto nPos = m_xWidget->find_text(rStr); + if (nPos != -1) + m_xWidget->remove(nPos); + else if (m_xWidget->get_count() >= m_nRememberSize) + m_xWidget->remove(m_nRememberSize - 1); + m_xWidget->insert_text(0, rStr); +} + +void FindTextFieldControl::SetTextToSelected_Impl() +{ + OUString aString; + + try + { + css::uno::Reference<css::frame::XController> xController(m_xFrame->getController(), css::uno::UNO_SET_THROW); + css::uno::Reference<css::frame::XModel> xModel(xController->getModel(), css::uno::UNO_SET_THROW); + css::uno::Reference<css::container::XIndexAccess> xIndexAccess(xModel->getCurrentSelection(), css::uno::UNO_QUERY_THROW); + if (xIndexAccess->getCount() > 0) + { + css::uno::Reference<css::text::XTextRange> xTextRange(xIndexAccess->getByIndex(0), css::uno::UNO_QUERY_THROW); + aString = xTextRange->getString(); + } + } + catch ( ... ) + { + } + + if ( !aString.isEmpty() ) + { + // If something is selected in the document, prepopulate with this + m_xWidget->set_entry_text(aString); + m_aChangeHdl.Call(*m_xWidget); + } + // tdf#154818 - reuse last search string + else if (!m_sRememberedSearchString.isEmpty() || get_count() > 0) + { + // prepopulate with last search word (fdo#84256) + m_xWidget->set_entry_text(m_sRememberedSearchString.isEmpty() ? m_xWidget->get_text(0) + : m_sRememberedSearchString); + } +} + +IMPL_LINK(FindTextFieldControl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) +{ + if (isDisposed()) + return true; + + bool bRet = false; + + bool bShift = rKeyEvent.GetKeyCode().IsShift(); + bool bMod1 = rKeyEvent.GetKeyCode().IsMod1(); + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + + // Close the search bar on Escape + if ( KEY_ESCAPE == nCode ) + { + bRet = true; + GrabFocusToDocument(); + + // hide the findbar + css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY); + if (xPropSet.is()) + { + css::uno::Reference< css::frame::XLayoutManager > xLayoutManager; + css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager"); + aValue >>= xLayoutManager; + if (xLayoutManager.is()) + { + static constexpr OUString sResourceURL( u"private:resource/toolbar/findbar"_ustr ); + xLayoutManager->hideElement( sResourceURL ); + xLayoutManager->destroyElement( sResourceURL ); + } + } + } + else + { + auto awtKey = svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyEvent.GetKeyCode()); + const OUString aCommand(m_pAcc->findCommand(awtKey)); + + // Select text in the search box when Ctrl-F pressed + if ( bMod1 && nCode == KEY_F ) + m_xWidget->select_entry_region(0, -1); + // Execute the search when Ctrl-G, F3 and Shift-RETURN pressed (in addition to ActivateHdl condition which handles bare RETURN) + else if ( (bMod1 && KEY_G == nCode) || (bShift && KEY_RETURN == nCode) || (KEY_F3 == nCode) ) + { + ActivateFind(bShift); + bRet = true; + } + else if (aCommand == ".uno:SearchDialog") + bRet = m_pAcc->execute(awtKey); + + // find-shortcut called with focus already in find + if (aCommand == "vnd.sun.star.findbar:FocusToFindbar") + { + m_xWidget->call_attention_to(); + bRet = true; + } + } + + return bRet || ChildKeyInput(rKeyEvent); +} + +void FindTextFieldControl::ActivateFind(bool bShift) +{ + // tdf#154818 - remember last search string + m_sRememberedSearchString = m_xWidget->get_active_text(); + Remember_Impl(m_sRememberedSearchString); + + vcl::Window* pWindow = GetParent(); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow); + + impl_executeSearch(m_xContext, m_xFrame, pToolBox, bShift); + + m_xWidget->grab_focus(); +} + +// Execute the search when activated, typically due to "Return" +IMPL_LINK_NOARG(FindTextFieldControl, ActivateHdl, weld::ComboBox&, bool) +{ + if (isDisposed()) + return true; + + ActivateFind(false); + + return true; +} + +IMPL_LINK_NOARG(FindTextFieldControl, OnAsyncGetFocus, void*, void) +{ + m_nAsyncGetFocusId = nullptr; + m_xWidget->select_entry_region(0, -1); +} + +void FindTextFieldControl::FocusIn() +{ + if (m_nAsyncGetFocusId || !m_xWidget) + return; + + // do it async to defeat entry in combobox having its own ideas about the focus + m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, FindTextFieldControl, OnAsyncGetFocus)); + + GrabFocus(); // tdf#137993 ensure the toplevel vcl::Window is activated so SfxViewFrame::Current is valid +} + +IMPL_LINK_NOARG(FindTextFieldControl, FocusInHdl, weld::Widget&, void) +{ + FocusIn(); +} + +void FindTextFieldControl::dispose() +{ + if (m_nAsyncGetFocusId) + { + Application::RemoveUserEvent(m_nAsyncGetFocusId); + m_nAsyncGetFocusId = nullptr; + } + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +FindTextFieldControl::~FindTextFieldControl() +{ + disposeOnce(); +} + +void FindTextFieldControl::connect_changed(const Link<weld::ComboBox&, void>& rLink) +{ + m_aChangeHdl = rLink; + m_xWidget->connect_changed(rLink); +} + +int FindTextFieldControl::get_count() const +{ + return m_xWidget->get_count(); +} + +OUString FindTextFieldControl::get_text(int nIndex) const +{ + return m_xWidget->get_text(nIndex); +} + +OUString FindTextFieldControl::get_active_text() const +{ + return m_xWidget->get_active_text(); +} + +void FindTextFieldControl::append_text(const OUString& rText) +{ + m_xWidget->append_text(rText); +} + +namespace { + +class SearchToolbarControllersManager +{ +public: + + SearchToolbarControllersManager(); + + static SearchToolbarControllersManager& createControllersManager(); + + void registryController( const css::uno::Reference< css::frame::XFrame >& xFrame, const css::uno::Reference< css::frame::XStatusListener >& xStatusListener, const OUString& sCommandURL ); + void freeController ( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL ); + css::uno::Reference< css::frame::XStatusListener > findController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL ); + + void saveSearchHistory(const FindTextFieldControl* m_pFindTextFieldControl); + void loadSearchHistory(FindTextFieldControl* m_pFindTextFieldControl); + +private: + + typedef ::std::vector< css::beans::PropertyValue > SearchToolbarControllersVec; + typedef ::std::map< css::uno::Reference< css::frame::XFrame >, SearchToolbarControllersVec > SearchToolbarControllersMap; + SearchToolbarControllersMap aSearchToolbarControllersMap; + std::vector<OUString> m_aSearchStrings; + +}; + +SearchToolbarControllersManager::SearchToolbarControllersManager() +{ +} + +SearchToolbarControllersManager& SearchToolbarControllersManager::createControllersManager() +{ + static SearchToolbarControllersManager theSearchToolbarControllersManager; + return theSearchToolbarControllersManager; +} + +void SearchToolbarControllersManager::saveSearchHistory(const FindTextFieldControl* pFindTextFieldControl) +{ + const sal_Int32 nECount( pFindTextFieldControl->get_count() ); + m_aSearchStrings.resize( nECount ); + for( sal_Int32 i=0; i<nECount; ++i ) + { + m_aSearchStrings[i] = pFindTextFieldControl->get_text(i); + } +} + +void SearchToolbarControllersManager::loadSearchHistory(FindTextFieldControl* pFindTextFieldControl) +{ + for( size_t i=0; i<m_aSearchStrings.size(); ++i ) + { + pFindTextFieldControl->append_text(m_aSearchStrings[i]); + } +} + +void SearchToolbarControllersManager::registryController( const css::uno::Reference< css::frame::XFrame >& xFrame, const css::uno::Reference< css::frame::XStatusListener >& xStatusListener, const OUString& sCommandURL ) +{ + SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame); + if (pIt == aSearchToolbarControllersMap.end()) + { + SearchToolbarControllersVec lControllers(1); + lControllers[0].Name = sCommandURL; + lControllers[0].Value <<= xStatusListener; + aSearchToolbarControllersMap.emplace(xFrame, lControllers); + } + else + { + sal_Int32 nSize = pIt->second.size(); + for (sal_Int32 i=0; i<nSize; ++i) + { + if (pIt->second[i].Name == sCommandURL) + return; + } + + pIt->second.resize(nSize+1); + pIt->second[nSize].Name = sCommandURL; + pIt->second[nSize].Value <<= xStatusListener; + } +} + +void SearchToolbarControllersManager::freeController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL ) +{ + SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame); + if (pIt != aSearchToolbarControllersMap.end()) + { + auto pItCtrl = std::find_if(pIt->second.begin(), pIt->second.end(), + [&sCommandURL](const css::beans::PropertyValue& rCtrl) { return rCtrl.Name == sCommandURL; }); + if (pItCtrl != pIt->second.end()) + pIt->second.erase(pItCtrl); + + if (pIt->second.empty()) + aSearchToolbarControllersMap.erase(pIt); + } +} + +css::uno::Reference< css::frame::XStatusListener > SearchToolbarControllersManager::findController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL ) +{ + css::uno::Reference< css::frame::XStatusListener > xStatusListener; + + SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame); + if (pIt != aSearchToolbarControllersMap.end()) + { + auto pItCtrl = std::find_if(pIt->second.begin(), pIt->second.end(), + [&sCommandURL](const css::beans::PropertyValue& rCtrl) { return rCtrl.Name == sCommandURL; }); + if (pItCtrl != pIt->second.end()) + pItCtrl->Value >>= xStatusListener; + } + + return xStatusListener; +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> FindTextToolbarController_Base; +class FindTextToolbarController : public FindTextToolbarController_Base +{ +public: + + FindTextToolbarController( const css::uno::Reference< css::uno::XComponentContext > & rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + + DECL_LINK(EditModifyHdl, weld::ComboBox&, void); + +private: + + void textfieldChanged(); + + VclPtr<FindTextFieldControl> m_pFindTextFieldControl; + + ToolBoxItemId m_nDownSearchId; + ToolBoxItemId m_nUpSearchId; + ToolBoxItemId m_nFindAllId; + +}; + +FindTextToolbarController::FindTextToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) + : FindTextToolbarController_Base(rxContext, css::uno::Reference< css::frame::XFrame >(), COMMAND_FINDTEXT) + , m_pFindTextFieldControl(nullptr) + , m_nDownSearchId(0) + , m_nUpSearchId(0) + , m_nFindAllId(0) +{ +} + +// XServiceInfo +OUString SAL_CALL FindTextToolbarController::getImplementationName() +{ + return "com.sun.star.svx.FindTextToolboxController"; +} + +sal_Bool SAL_CALL FindTextToolbarController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FindTextToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL FindTextToolbarController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); + if (m_pFindTextFieldControl != nullptr) { + SearchToolbarControllersManager::createControllersManager() + .saveSearchHistory(m_pFindTextFieldControl); + m_pFindTextFieldControl.disposeAndClear(); + } +} + +// XInitialization +void SAL_CALL FindTextToolbarController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize(aArguments); + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() ); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get()); + if ( pToolBox ) + { + m_nDownSearchId = pToolBox->GetItemId(COMMAND_DOWNSEARCH); + m_nUpSearchId = pToolBox->GetItemId(COMMAND_UPSEARCH); + m_nFindAllId = pToolBox->GetItemId(COMMAND_FINDALL); + } + + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +css::uno::Reference< css::awt::XWindow > SAL_CALL FindTextToolbarController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent ) +{ + css::uno::Reference< css::awt::XWindow > xItemWindow; + + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get()); + m_pFindTextFieldControl = VclPtr<FindTextFieldControl>::Create(pToolbar, m_xFrame, m_xContext); + + m_pFindTextFieldControl->connect_changed(LINK(this, FindTextToolbarController, EditModifyHdl)); + SearchToolbarControllersManager::createControllersManager().loadSearchHistory(m_pFindTextFieldControl); + } + xItemWindow = VCLUnoHelper::GetInterface( m_pFindTextFieldControl ); + + return xItemWindow; +} + +// XStatusListener +void SAL_CALL FindTextToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent ) +{ + SolarMutexGuard aSolarMutexGuard; + if ( m_bDisposed ) + return; + + OUString aFeatureURL = rEvent.FeatureURL.Complete; + if ( aFeatureURL == "AppendSearchHistory" ) + { + m_pFindTextFieldControl->Remember_Impl(m_pFindTextFieldControl->get_active_text()); + } + // enable up/down buttons in case there is already text (from the search history) + textfieldChanged(); +} + +IMPL_LINK_NOARG(FindTextToolbarController, EditModifyHdl, weld::ComboBox&, void) +{ + // Clear SearchLabel when search string altered + #if HAVE_FEATURE_DESKTOP + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); + #endif + + textfieldChanged(); +} + +void FindTextToolbarController::textfieldChanged() { + // enable or disable item DownSearch/UpSearch/FindAll of findbar + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() ); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get()); + if ( pToolBox && m_pFindTextFieldControl ) + { + bool enableButtons = !m_pFindTextFieldControl->get_active_text().isEmpty(); + pToolBox->EnableItem(m_nDownSearchId, enableButtons); + pToolBox->EnableItem(m_nUpSearchId, enableButtons); + pToolBox->EnableItem(m_nFindAllId, enableButtons); + } +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> UpDownSearchToolboxController_Base; +class UpDownSearchToolboxController : public UpDownSearchToolboxController_Base +{ +public: + enum Type { UP, DOWN }; + + UpDownSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, Type eType ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + +private: + Type meType; +}; + +UpDownSearchToolboxController::UpDownSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext, Type eType ) + : UpDownSearchToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + (eType == UP) ? COMMAND_UPSEARCH: COMMAND_DOWNSEARCH ), + meType( eType ) +{ +} + +// XServiceInfo +OUString SAL_CALL UpDownSearchToolboxController::getImplementationName() +{ + return meType == UpDownSearchToolboxController::UP? + OUString( "com.sun.star.svx.UpSearchToolboxController" ) : + OUString( "com.sun.star.svx.DownSearchToolboxController" ); +} + +sal_Bool SAL_CALL UpDownSearchToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL UpDownSearchToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL UpDownSearchToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); +} + +// XInitialization +void SAL_CALL UpDownSearchToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize( aArguments ); + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +// XToolbarController +void SAL_CALL UpDownSearchToolboxController::execute( sal_Int16 /*KeyModifier*/ ) +{ + if ( m_bDisposed ) + throw css::lang::DisposedException(); + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() ); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get()); + + impl_executeSearch(m_xContext, m_xFrame, pToolBox, meType == UP ); + + css::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL.Complete = "AppendSearchHistory"; + css::uno::Reference< css::frame::XStatusListener > xStatusListener = SearchToolbarControllersManager::createControllersManager().findController(m_xFrame, COMMAND_FINDTEXT); + if (xStatusListener.is()) + xStatusListener->statusChanged( aEvent ); +} + +// XStatusListener +void SAL_CALL UpDownSearchToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ ) +{ +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> MatchCaseToolboxController_Base; +class MatchCaseToolboxController : public MatchCaseToolboxController_Base +{ +public: + MatchCaseToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + +private: + VclPtr<CheckButtonItemWindow> m_xMatchCaseControl; +}; + +MatchCaseToolboxController::MatchCaseToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) + : MatchCaseToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + COMMAND_MATCHCASE ) + , m_xMatchCaseControl(nullptr) +{ +} + +// XServiceInfo +OUString SAL_CALL MatchCaseToolboxController::getImplementationName() +{ + return "com.sun.star.svx.MatchCaseToolboxController"; +} + +sal_Bool SAL_CALL MatchCaseToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL MatchCaseToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL MatchCaseToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); + + m_xMatchCaseControl.disposeAndClear(); +} + +// XInitialization +void SAL_CALL MatchCaseToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize(aArguments); + + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +css::uno::Reference< css::awt::XWindow > SAL_CALL MatchCaseToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent ) +{ + css::uno::Reference< css::awt::XWindow > xItemWindow; + + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get()); + m_xMatchCaseControl = VclPtr<CheckButtonItemWindow>::Create(pToolbar, SvxResId(RID_SVXSTR_FINDBAR_MATCHCASE)); + } + xItemWindow = VCLUnoHelper::GetInterface(m_xMatchCaseControl); + + return xItemWindow; +} + +// XStatusListener +void SAL_CALL MatchCaseToolboxController::statusChanged( const css::frame::FeatureStateEvent& ) +{ +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> SearchFormattedToolboxController_Base; +class SearchFormattedToolboxController : public SearchFormattedToolboxController_Base +{ +public: + SearchFormattedToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + +private: + VclPtr<CheckButtonItemWindow> m_xSearchFormattedControl; +}; + +SearchFormattedToolboxController::SearchFormattedToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ) + : SearchFormattedToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + COMMAND_SEARCHFORMATTED ) + , m_xSearchFormattedControl(nullptr) +{ +} + +// XServiceInfo +OUString SAL_CALL SearchFormattedToolboxController::getImplementationName() +{ + return "com.sun.star.svx.SearchFormattedToolboxController"; +} + +sal_Bool SAL_CALL SearchFormattedToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL SearchFormattedToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL SearchFormattedToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); + + m_xSearchFormattedControl.disposeAndClear(); +} + +// XInitialization +void SAL_CALL SearchFormattedToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize(aArguments); + + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +css::uno::Reference< css::awt::XWindow > SAL_CALL SearchFormattedToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent ) +{ + css::uno::Reference< css::awt::XWindow > xItemWindow; + + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get()); + m_xSearchFormattedControl = VclPtr<CheckButtonItemWindow>::Create(pToolbar, SvxResId(RID_SVXSTR_FINDBAR_SEARCHFORMATTED)); + } + xItemWindow = VCLUnoHelper::GetInterface(m_xSearchFormattedControl); + + return xItemWindow; +} + +// XStatusListener +void SAL_CALL SearchFormattedToolboxController::statusChanged( const css::frame::FeatureStateEvent& ) +{ +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> FindAllToolboxController_Base; +class FindAllToolboxController : public FindAllToolboxController_Base +{ +public: + FindAllToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; +}; + +FindAllToolboxController::FindAllToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext ) + : FindAllToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + ".uno:FindAll" ) +{ +} + +// XServiceInfo +OUString SAL_CALL FindAllToolboxController::getImplementationName() +{ + return "com.sun.star.svx.FindAllToolboxController"; +} + + +sal_Bool SAL_CALL FindAllToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FindAllToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL FindAllToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); +} + +// XInitialization +void SAL_CALL FindAllToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize( aArguments ); + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +// XToolbarController +void SAL_CALL FindAllToolboxController::execute( sal_Int16 /*KeyModifier*/ ) +{ + if ( m_bDisposed ) + throw css::lang::DisposedException(); + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() ); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get()); + + impl_executeSearch(m_xContext, m_xFrame, pToolBox, false, true); +} + +// XStatusListener +void SAL_CALL FindAllToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ ) +{ +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> ExitSearchToolboxController_Base; +class ExitSearchToolboxController : public ExitSearchToolboxController_Base +{ +public: + ExitSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; +}; + +ExitSearchToolboxController::ExitSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext ) + : ExitSearchToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + ".uno:ExitSearch" ) +{ +} + +// XServiceInfo +OUString SAL_CALL ExitSearchToolboxController::getImplementationName() +{ + return "com.sun.star.svx.ExitFindbarToolboxController"; +} + + +sal_Bool SAL_CALL ExitSearchToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ExitSearchToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL ExitSearchToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); +} + +// XInitialization +void SAL_CALL ExitSearchToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize( aArguments ); + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +// XToolbarController +void SAL_CALL ExitSearchToolboxController::execute( sal_Int16 /*KeyModifier*/ ) +{ + vcl::Window *pFocusWindow = Application::GetFocusWindow(); + if ( pFocusWindow ) + pFocusWindow->GrabFocusToDocument(); + + // hide the findbar + css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY); + if (xPropSet.is()) + { + css::uno::Reference< css::frame::XLayoutManager > xLayoutManager; + css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager"); + aValue >>= xLayoutManager; + if (xLayoutManager.is()) + { + static constexpr OUString sResourceURL( u"private:resource/toolbar/findbar"_ustr ); + xLayoutManager->hideElement( sResourceURL ); + xLayoutManager->destroyElement( sResourceURL ); + } + } +} + +// XStatusListener +void SAL_CALL ExitSearchToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ ) +{ +} + +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> SearchLabelToolboxController_Base; +class SearchLabelToolboxController : public SearchLabelToolboxController_Base +{ +public: + SearchLabelToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; + +private: + VclPtr<LabelItemWindow> m_xSL; +}; + +SearchLabelToolboxController::SearchLabelToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext ) + : SearchLabelToolboxController_Base( rxContext, + css::uno::Reference< css::frame::XFrame >(), + ".uno:SearchLabel" ) +{ +} + +// XServiceInfo +OUString SAL_CALL SearchLabelToolboxController::getImplementationName() +{ + return "com.sun.star.svx.SearchLabelToolboxController"; +} + + +sal_Bool SAL_CALL SearchLabelToolboxController::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL SearchLabelToolboxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +// XComponent +void SAL_CALL SearchLabelToolboxController::dispose() +{ + SolarMutexGuard aSolarMutexGuard; + + SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL); + + svt::ToolboxController::dispose(); + m_xSL.disposeAndClear(); +} + +// XInitialization +void SAL_CALL SearchLabelToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize( aArguments ); + SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL); +} + +// XStatusListener +void SAL_CALL SearchLabelToolboxController::statusChanged( const css::frame::FeatureStateEvent& ) +{ + if (m_xSL) + { + OUString aStr = SvxSearchDialogWrapper::GetSearchLabel(); + m_xSL->set_label(aStr); + m_xSL->SetOptimalSize(); + Size aSize(m_xSL->GetSizePixel()); + tools::Long nWidth = !aStr.isEmpty() ? aSize.getWidth() : 16; + m_xSL->SetSizePixel(Size(nWidth, aSize.Height())); + } +} + +css::uno::Reference< css::awt::XWindow > SAL_CALL SearchLabelToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + pToolBox->SetItemWindowNonInteractive(nId, true); + + m_xSL = VclPtr<LabelItemWindow>::Create(VCLUnoHelper::GetWindow(Parent), ""); + m_xSL->SetSizePixel(Size(16, m_xSL->GetSizePixel().Height())); + return VCLUnoHelper::GetInterface(m_xSL); +} + +// protocol handler for "vnd.sun.star.findbar:*" URLs +// The dispatch object will be used for shortcut commands for findbar +class FindbarDispatcher : public css::lang::XServiceInfo, + public css::lang::XInitialization, + public css::frame::XDispatchProvider, + public css::frame::XDispatch, + public ::cppu::OWeakObject +{ +public: + + FindbarDispatcher(); + virtual ~FindbarDispatcher() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XDispatchProvider + virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& aURL, const OUString& sTargetFrameName , sal_Int32 nSearchFlags ) override; + virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) override; + + // XDispatch + virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override; + virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override; + virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override; + +private: + + css::uno::Reference< css::frame::XFrame > m_xFrame; + +}; + +FindbarDispatcher::FindbarDispatcher() +{ +} + +FindbarDispatcher::~FindbarDispatcher() +{ + m_xFrame = nullptr; +} + +// XInterface +css::uno::Any SAL_CALL FindbarDispatcher::queryInterface( const css::uno::Type& aType ) +{ + css::uno::Any aReturn( ::cppu::queryInterface( aType, + static_cast< css::lang::XServiceInfo* >(this), + static_cast< css::lang::XInitialization* >(this), + static_cast< css::frame::XDispatchProvider* >(this), + static_cast< css::frame::XDispatch* >(this)) ); + + if ( aReturn.hasValue() ) + return aReturn; + + return OWeakObject::queryInterface( aType ); +} + +void SAL_CALL FindbarDispatcher::acquire() noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL FindbarDispatcher::release() noexcept +{ + OWeakObject::release(); +} + +// XServiceInfo +OUString SAL_CALL FindbarDispatcher::getImplementationName() +{ + return "com.sun.star.comp.svx.Impl.FindbarDispatcher"; +} + +sal_Bool SAL_CALL FindbarDispatcher::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FindbarDispatcher::getSupportedServiceNames() +{ + return { "com.sun.star.comp.svx.FindbarDispatcher", "com.sun.star.frame.ProtocolHandler" }; +} + +// XInitialization +void SAL_CALL FindbarDispatcher::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + if ( aArguments.hasElements() ) + aArguments[0] >>= m_xFrame; +} + +// XDispatchProvider +css::uno::Reference< css::frame::XDispatch > SAL_CALL FindbarDispatcher::queryDispatch( const css::util::URL& aURL, const OUString& /*sTargetFrameName*/, sal_Int32 /*nSearchFlags*/ ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatch; + + if ( aURL.Protocol == "vnd.sun.star.findbar:" ) + xDispatch = this; + + return xDispatch; +} + +css::uno::Sequence < css::uno::Reference< css::frame::XDispatch > > SAL_CALL FindbarDispatcher::queryDispatches( const css::uno::Sequence < css::frame::DispatchDescriptor >& seqDescripts ) +{ + sal_Int32 nCount = seqDescripts.getLength(); + css::uno::Sequence < css::uno::Reference < XDispatch > > lDispatcher( nCount ); + + std::transform(seqDescripts.begin(), seqDescripts.end(), lDispatcher.getArray(), + [this](const css::frame::DispatchDescriptor& rDescript) -> css::uno::Reference < XDispatch > { + return queryDispatch( rDescript.FeatureURL, rDescript.FrameName, rDescript.SearchFlags ); }); + + return lDispatcher; +} + +// XDispatch +void SAL_CALL FindbarDispatcher::dispatch( const css::util::URL& aURL, const css::uno::Sequence < css::beans::PropertyValue >& /*lArgs*/ ) +{ + //vnd.sun.star.findbar:FocusToFindbar - set cursor to the FindTextFieldControl of the findbar + if ( aURL.Path != "FocusToFindbar" ) + return; + + css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + css::uno::Reference< css::frame::XLayoutManager > xLayoutManager; + css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager"); + aValue >>= xLayoutManager; + if (!xLayoutManager.is()) + return; + + static constexpr OUString sResourceURL( u"private:resource/toolbar/findbar"_ustr ); + css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL); + if (!xUIElement.is()) + { + // show the findbar if necessary + xLayoutManager->createElement( sResourceURL ); + xLayoutManager->showElement( sResourceURL ); + xUIElement = xLayoutManager->getElement( sResourceURL ); + if ( !xUIElement.is() ) + return; + } + + css::uno::Reference< css::awt::XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get()); + pToolBox->set_id("FindBar"); + if ( !pToolBox ) + return; + + ToolBox::ImplToolItems::size_type nItemCount = pToolBox->GetItemCount(); + for ( ToolBox::ImplToolItems::size_type i=0; i<nItemCount; ++i ) + { + ToolBoxItemId id = pToolBox->GetItemId(i); + OUString sItemCommand = pToolBox->GetItemCommand(id); + if ( sItemCommand == COMMAND_FINDTEXT ) + { + vcl::Window* pItemWin = pToolBox->GetItemWindow( id ); + if ( pItemWin ) + { + SolarMutexGuard aSolarMutexGuard; + FindTextFieldControl* pFindTextFieldControl = dynamic_cast<FindTextFieldControl*>(pItemWin); + if ( pFindTextFieldControl ) + pFindTextFieldControl->SetTextToSelected_Impl(); + pItemWin->GrabFocus(); + return; + } + } + } +} + +void SAL_CALL FindbarDispatcher::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ ) +{ +} + +void SAL_CALL FindbarDispatcher::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ ) +{ +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_FindTextToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FindTextToolbarController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_ExitFindbarToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ExitSearchToolboxController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_UpSearchToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UpDownSearchToolboxController(context, UpDownSearchToolboxController::UP)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_DownSearchToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new UpDownSearchToolboxController(context, UpDownSearchToolboxController::DOWN)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_MatchCaseToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new MatchCaseToolboxController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_SearchFormattedToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new SearchFormattedToolboxController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_FindAllToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FindAllToolboxController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_svx_SearchLabelToolboxController_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new SearchLabelToolboxController(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_svx_Impl_FindbarDispatcher_get_implementation( + SAL_UNUSED_PARAMETER css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new FindbarDispatcher); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbxcolor.cxx b/svx/source/tbxctrls/tbxcolor.cxx new file mode 100644 index 0000000000..97e4898065 --- /dev/null +++ b/svx/source/tbxctrls/tbxcolor.cxx @@ -0,0 +1,96 @@ +/* -*- 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/tbxcolor.hxx> +#include <sfx2/viewfrm.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> + + +namespace svx +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + + ToolboxAccess::ToolboxAccess( std::u16string_view rToolboxName ) : + m_sToolboxResName ( "private:resource/toolbar/" ) + { + m_sToolboxResName += rToolboxName; + + // the layout manager + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if (!pViewFrm) + return; + + try + { + Reference< XFrame > xFrame = pViewFrm->GetFrame().GetFrameInterface(); + Reference< XPropertySet > xFrameProps( xFrame, UNO_QUERY ); + if ( xFrameProps.is() ) + xFrameProps->getPropertyValue( "LayoutManager" ) >>= m_xLayouter; + } + catch ( Exception const & ) + { + TOOLS_WARN_EXCEPTION( "svx.tbxcrtls", "ToolboxAccess::Ctor()" ); + } + } + + + void ToolboxAccess::toggleToolbox() const + { + try + { + Reference< XLayoutManager > xManager( m_xLayouter ); + OSL_ENSURE( xManager. is(), "ToolboxAccess::toggleToolbox: couldn't obtain the layout manager!" ); + if ( xManager. is() ) + { + if ( xManager->isElementVisible( m_sToolboxResName ) ) + { + xManager->hideElement( m_sToolboxResName ); + xManager->destroyElement( m_sToolboxResName ); + } + else + { + xManager->createElement( m_sToolboxResName ); + xManager->showElement( m_sToolboxResName ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "svx", "ToolboxAccess::toggleToolbox" ); + } + } + + + bool ToolboxAccess::isToolboxVisible() const + { + return ( m_xLayouter.is() && m_xLayouter->isElementVisible( m_sToolboxResName ) ); + } + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx new file mode 100644 index 0000000000..970fa40181 --- /dev/null +++ b/svx/source/tbxctrls/tbxcolorupdate.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 <sfx2/sfxbasemodel.hxx> +#include <sfx2/objsh.hxx> +#include <svx/drawitem.hxx> +#include <tbxcolorupdate.hxx> +#include <svx/svxids.hrc> +#include <svx/xdef.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlndsit.hxx> + +#include <utility> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> + +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> + +namespace svx +{ + ToolboxButtonColorUpdaterBase::ToolboxButtonColorUpdaterBase(bool bWideButton, OUString aCommandLabel, + OUString aCommandURL, sal_uInt16 nSlotId, + css::uno::Reference<css::frame::XFrame> xFrame) + : mbWideButton(bWideButton) + , mbWasHiContrastMode(Application::GetSettings().GetStyleSettings().GetHighContrastMode()) + , mnSlotId(nSlotId) + , maCurColor(COL_TRANSPARENT) + , meImageType(vcl::ImageType::Size16) + , maCommandLabel(std::move(aCommandLabel)) + , maCommandURL(std::move(aCommandURL)) + , mxFrame(std::move(xFrame)) + { + } + + void ToolboxButtonColorUpdaterBase::Init(sal_uInt16 nSlotId) + { + if (mbWideButton) + { + Update(COL_TRANSPARENT, true); + return; + } + + if (rtl::Reference xModel = dynamic_cast<SfxBaseModel*>(mxFrame->getController()->getModel().get())) + { + auto pDocSh = xModel->GetObjectShell(); + StartListening(*pDocSh); + if (auto oColor = pDocSh->GetRecentColor(nSlotId)) + { + Update(*oColor); + return; + } + } + + switch (nSlotId) + { + case SID_ATTR_CHAR_COLOR: + case SID_ATTR_CHAR_COLOR2: + Update(NamedColor(COL_DEFAULT_FONT, SvxResId(RID_SVXSTR_COLOR_DEFAULT_FONT))); + break; + case SID_FRAME_LINECOLOR: + Update(NamedColor(COL_DEFAULT_FRAMELINE, SvxResId(RID_SVXSTR_COLOR_DEFAULT_FRAMELINE))); + break; + case SID_ATTR_CHAR_COLOR_BACKGROUND: + case SID_ATTR_CHAR_BACK_COLOR: + case SID_BACKGROUND_COLOR: + case SID_TABLE_CELL_BACKGROUND_COLOR: + Update(NamedColor(COL_DEFAULT_HIGHLIGHT, SvxResId(RID_SVXSTR_COLOR_DEFAULT_HIGHLIGHT))); + break; + case SID_ATTR_LINE_COLOR: + Update(NamedColor(COL_DEFAULT_SHAPE_STROKE, SvxResId(RID_SVXSTR_COLOR_DEFAULT_SHAPE_STROKE))); + break; + case SID_ATTR_FILL_COLOR: + Update(NamedColor(COL_DEFAULT_SHAPE_FILLING, SvxResId(RID_SVXSTR_COLOR_DEFAULT_SHAPE_FILLING))); + break; + default: + Update(COL_TRANSPARENT); + } + } + + void ToolboxButtonColorUpdaterBase::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) + { + if (rHint.GetId() == SfxHintId::Dying) + { + EndListeningAll(); + } + else if (rHint.GetId() == SfxHintId::ColorsChanged) + { + if (auto oColor = static_cast<SfxObjectShell&>(rBC).GetRecentColor(mnSlotId)) + Update(*oColor); + } + } + + void ToolboxButtonColorUpdaterBase::SetRecentColor(const NamedColor &rNamedColor) + { + if (rtl::Reference xModel = dynamic_cast<SfxBaseModel*>(mxFrame->getController()->getModel().get())) + xModel->GetObjectShell()->SetRecentColor(mnSlotId, rNamedColor); + else if (!mbWideButton) + Update(rNamedColor); + } + + VclToolboxButtonColorUpdater::VclToolboxButtonColorUpdater( + sal_uInt16 nSlotId, ToolBoxItemId nTbxBtnId, ToolBox* pToolBox, bool bWideButton, + const OUString& rCommandLabel, const OUString& rCommandURL, + const css::uno::Reference<css::frame::XFrame>& rFrame) + : ToolboxButtonColorUpdaterBase(bWideButton, rCommandLabel, rCommandURL, nSlotId, rFrame) + , mnBtnId(nTbxBtnId) + , mpTbx(pToolBox) + { + Init(nSlotId); + } + + void VclToolboxButtonColorUpdater::SetQuickHelpText(const OUString& rText) + { + mpTbx->SetQuickHelpText(mnBtnId, rText); + } + + OUString VclToolboxButtonColorUpdater::GetQuickHelpText() const + { + return mpTbx->GetQuickHelpText(mnBtnId); + } + + void VclToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev) + { + GDIMetaFile* pMtf = pVirDev->GetConnectMetaFile(); + + assert(pMtf && "should have been set in ToolboxButtonColorUpdaterBase::Update"); + + pMtf->Stop(); + pMtf->WindStart(); + + Graphic aGraphic(*pMtf); + + mpTbx->SetItemImage(mnBtnId, Image(aGraphic.GetXGraphic())); + } + + VclPtr<VirtualDevice> VclToolboxButtonColorUpdater::CreateVirtualDevice() const + { + return VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev()); + } + + vcl::ImageType VclToolboxButtonColorUpdater::GetImageSize() const + { + return mpTbx->GetImageSize(); + } + + Size VclToolboxButtonColorUpdater::GetItemSize(const Size& rImageSize) const + { + if (mbWideButton) + return mpTbx->GetItemContentSize(mnBtnId); + return rImageSize; + } + + ToolboxButtonColorUpdaterBase::~ToolboxButtonColorUpdaterBase() + {} + + void ToolboxButtonColorUpdaterBase::Update(const NamedColor &rNamedColor) + { + Update(rNamedColor.m_aColor); + + // Also show the current color as QuickHelpText + OUString colorSuffix = OUString(" (%1)").replaceFirst("%1", rNamedColor.m_aName); + OUString colorHelpText = maCommandLabel + colorSuffix; + SetQuickHelpText(colorHelpText); + } + + void ToolboxButtonColorUpdaterBase::Update(const Color& rColor, bool bForceUpdate) + { + vcl::ImageType eImageType = GetImageSize(); + +#ifdef IOS // tdf#126966 + eImageType = vcl::ImageType::Size32; +#endif + + const bool bSizeChanged = (meImageType != eImageType); + meImageType = eImageType; + const bool bDisplayModeChanged = (mbWasHiContrastMode != Application::GetSettings().GetStyleSettings().GetHighContrastMode()); + Color aColor(rColor); + + // !!! #109290# Workaround for SetFillColor with COL_AUTO + if (aColor == COL_AUTO) + aColor = COL_TRANSPARENT; + + if ((maCurColor == aColor) && !bSizeChanged && !bDisplayModeChanged && !bForceUpdate) + return; + + auto xImage = vcl::CommandInfoProvider::GetXGraphicForCommand(maCommandURL, mxFrame, meImageType); + Image aImage(xImage); + + Size aItemSize = GetItemSize(aImage.GetSizePixel()); + if (!aItemSize.Width() || !aItemSize.Height()) + return; + + ScopedVclPtr<VirtualDevice> pVirDev(CreateVirtualDevice()); + pVirDev->SetOutputSizePixel(aItemSize, /*bErase*/true, /*bAlphaMaskTransparent*/true); + maBmpSize = aItemSize; + + std::unique_ptr<GDIMetaFile> xMetaFile; + if (RecordVirtualDevice()) + { + xMetaFile.reset(new GDIMetaFile); + xMetaFile->SetPrefSize(pVirDev->GetOutputSize()); + xMetaFile->SetPrefMapMode(pVirDev->GetMapMode()); + xMetaFile->Record(pVirDev.get()); + pVirDev->EnableOutput(false); + } + + if (maBmpSize.Width() == maBmpSize.Height()) + // tdf#84985 align color bar with icon bottom edge; integer arithmetic e.g. 26 - 26/4 <> 26 * 3/4 + maUpdRect = tools::Rectangle(Point( 0, maBmpSize.Height() - maBmpSize.Height() / 4), Size(maBmpSize.Width(), maBmpSize.Height() / 4)); + else + maUpdRect = tools::Rectangle(Point( maBmpSize.Height() + 2, 2), Point(maBmpSize.Width() - 3, maBmpSize.Height() - 3)); + + pVirDev->Push(vcl::PushFlags::CLIPREGION); + + // tdf#135121 don't include the part of the image which we will + // overwrite with the target color so that for the transparent color + // case the original background of the device is shown + vcl::Region aRegion(tools::Rectangle(Point(0, 0), maBmpSize)); + aRegion.Exclude(maUpdRect); + pVirDev->SetClipRegion(aRegion); + + pVirDev->DrawImage(Point(0, 0), aImage); + + pVirDev->Pop(); + + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + mbWasHiContrastMode = rStyleSettings.GetHighContrastMode(); + + if ((COL_TRANSPARENT != aColor) && (maBmpSize.Width() == maBmpSize.Height())) + pVirDev->SetLineColor(aColor); + else + pVirDev->SetLineColor(rStyleSettings.GetDisableColor()); + + // use not only COL_TRANSPARENT for detection of transparence, + // but the method/way which is designed to do that + const bool bIsFullyTransparent(aColor.IsFullyTransparent()); + maCurColor = aColor; + + if (bIsFullyTransparent) + { + pVirDev->SetFillColor(); + } + else + { + pVirDev->SetFillColor(maCurColor); + } + + pVirDev->DrawRect(maUpdRect); + + SetImage(pVirDev.get()); + } + + OUString ToolboxButtonColorUpdaterBase::GetCurrentColorName() const + { + OUString sColorName = GetQuickHelpText(); + // The obtained string is of format: color context (color name) + // Generate a substring which contains only the color name + sal_Int32 nStart = sColorName.indexOf('('); + sColorName = sColorName.copy( nStart + 1 ); + sal_Int32 nLength = sColorName.getLength(); + if(nLength > 0) + sColorName = sColorName.copy( 0, nLength - 1); + return sColorName; + } + + ToolboxButtonColorUpdater::ToolboxButtonColorUpdater(sal_uInt16 nSlotId, const OUString& rTbxBtnId, weld::Toolbar* ptrTbx, bool bWideButton, + const OUString& rCommandLabel, const css::uno::Reference<css::frame::XFrame>& rFrame) + : ToolboxButtonColorUpdaterBase(bWideButton, rCommandLabel, rTbxBtnId, nSlotId, rFrame) + , msBtnId(rTbxBtnId) + , mpTbx(ptrTbx) + { + Init(nSlotId); + } + + void ToolboxButtonColorUpdater::SetQuickHelpText(const OUString& rText) + { + mpTbx->set_item_tooltip_text(msBtnId, rText); + } + + OUString ToolboxButtonColorUpdater::GetQuickHelpText() const + { + return mpTbx->get_item_tooltip_text(msBtnId); + } + + void ToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev) + { + mpTbx->set_item_image(msBtnId, pVirDev); + } + + VclPtr<VirtualDevice> ToolboxButtonColorUpdater::CreateVirtualDevice() const + { + return mpTbx->create_virtual_device(); + } + + vcl::ImageType ToolboxButtonColorUpdater::GetImageSize() const + { + return mpTbx->get_icon_size(); + } + + Size ToolboxButtonColorUpdater::GetItemSize(const Size& rImageSize) const + { + auto nWidth = rImageSize.Width(); + if (mbWideButton) + nWidth = nWidth * 5; + return Size(nWidth, rImageSize.Height()); + } + + ToolboxButtonLineStyleUpdater::ToolboxButtonLineStyleUpdater() + : m_eXLS(css::drawing::LineStyle_NONE) + , m_nDashStyleIndex(-1) + { + } + + void ToolboxButtonLineStyleUpdater::Update(const com::sun::star::frame::FeatureStateEvent& rEvent) + { + if (rEvent.FeatureURL.Complete == ".uno:LineDash") + { + m_nDashStyleIndex = -1; + + SfxObjectShell* pSh = SfxObjectShell::Current(); + if (!pSh) + return; + const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST ); + if (!pItem) + return; + + XLineDashItem aDashItem; + aDashItem.PutValue(rEvent.State, 0); + const XDash& rDash = aDashItem.GetDashValue(); + + XDashListRef xLineStyleList = pItem->GetDashList(); + for (tools::Long i = 0; i < xLineStyleList->Count(); ++i) + { + const XDashEntry* pEntry = xLineStyleList->GetDash(i); + const XDash& rEntry = pEntry->GetDash(); + if (rDash == rEntry) + { + m_nDashStyleIndex = i; + break; + } + } + } + else if (rEvent.FeatureURL.Complete == ".uno:XLineStyle") + { + XLineStyleItem aLineStyleItem; + aLineStyleItem.PutValue(rEvent.State, 0); + + m_eXLS = aLineStyleItem.GetValue(); + } + } + + int ToolboxButtonLineStyleUpdater::GetStyleIndex() const + { + int nRet; + switch (m_eXLS) + { + case css::drawing::LineStyle_NONE: + nRet = 0; + break; + case css::drawing::LineStyle_SOLID: + nRet = 1; + break; + default: + nRet = m_nDashStyleIndex + 2; + break; + } + return nRet; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/tbxdrctl.cxx b/svx/source/tbxctrls/tbxdrctl.cxx new file mode 100644 index 0000000000..7eb1161611 --- /dev/null +++ b/svx/source/tbxctrls/tbxdrctl.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <svl/eitem.hxx> +#include <vcl/toolbox.hxx> + +#include <svx/tbxctl.hxx> + +#include <com/sun/star/frame/XLayoutManager.hpp> + +SFX_IMPL_TOOLBOX_CONTROL(SvxTbxCtlDraw, SfxBoolItem); + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; + + +SvxTbxCtlDraw::SvxTbxCtlDraw( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) : + SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + rTbx.SetItemBits( nId, ToolBoxItemBits::CHECKABLE | rTbx.GetItemBits( nId ) ); + rTbx.Invalidate(); +} + +void SAL_CALL SvxTbxCtlDraw::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + svt::ToolboxController::initialize(aArguments); + /* + * Toolbar name is defined as "private:resource/toolbar/drawbar" in writer and calc, + * "private:resource/toolbar/toolbar" in draw and impress. Control is added for this + * difference. + */ + if( m_aCommandURL==".uno:TrackChangesBar") + m_sToolboxName="private:resource/toolbar/changes"; + else if ( m_sModuleName == "com.sun.star.presentation.PresentationDocument" || m_sModuleName == "com.sun.star.drawing.DrawingDocument" ) + m_sToolboxName="private:resource/toolbar/toolbar"; + else + m_sToolboxName="private:resource/toolbar/drawbar"; +} + + +void SvxTbxCtlDraw::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, + const SfxPoolItem* pState ) +{ + GetToolBox().EnableItem( GetId(), ( eState != SfxItemState::DISABLED ) ); + SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState, pState ); + + Reference< XLayoutManager > xLayoutMgr = getLayoutManager(); + if ( xLayoutMgr.is() ) + GetToolBox().CheckItem( + GetId(), xLayoutMgr->isElementVisible( m_sToolboxName ) ); +} + + +void SvxTbxCtlDraw::toggleToolbox() +{ + Reference< XLayoutManager > xLayoutMgr = getLayoutManager(); + if ( !xLayoutMgr.is() ) + return; + + bool bCheck = false; + if ( xLayoutMgr->isElementVisible( m_sToolboxName ) ) + { + xLayoutMgr->hideElement( m_sToolboxName ); + xLayoutMgr->destroyElement( m_sToolboxName ); + } + else + { + bCheck = true; + xLayoutMgr->createElement( m_sToolboxName ); + xLayoutMgr->showElement( m_sToolboxName ); + } + + GetToolBox().CheckItem( GetId(), bCheck ); +} + + +void SvxTbxCtlDraw::Select(sal_uInt16 /*nSelectModifier*/) +{ + toggleToolbox(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/tbxctrls/verttexttbxctrl.cxx b/svx/source/tbxctrls/verttexttbxctrl.cxx new file mode 100644 index 0000000000..1f36ee6356 --- /dev/null +++ b/svx/source/tbxctrls/verttexttbxctrl.cxx @@ -0,0 +1,160 @@ +/* -*- 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 <cppuhelper/supportsservice.hxx> +#include <verttexttbxctrl.hxx> +#include <svl/cjkoptions.hxx> +#include <svl/ctloptions.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/weld.hxx> +#include <rtl/ustring.hxx> + +SvxCTLTextTbxCtrl::SvxCTLTextTbxCtrl( + const css::uno::Reference<css::uno::XComponentContext>& rContext) + : SvxVertCTLTextTbxCtrl(rContext) +{ + addStatusListener(".uno:CTLFontState"); +} + +OUString SvxCTLTextTbxCtrl::getImplementationName() +{ + return "com.sun.star.comp.svx.CTLToolBoxControl"; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_CTLToolBoxControl_get_implementation(css::uno::XComponentContext* rContext, + css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new SvxCTLTextTbxCtrl(rContext)); +} + +SvxVertTextTbxCtrl::SvxVertTextTbxCtrl( + const css::uno::Reference<css::uno::XComponentContext>& rContext) + : SvxVertCTLTextTbxCtrl(rContext) +{ + addStatusListener(".uno:VerticalTextState"); +} + +OUString SvxVertTextTbxCtrl::getImplementationName() +{ + return "com.sun.star.comp.svx.VertTextToolBoxControl"; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_svx_VertTextToolBoxControl_get_implementation( + css::uno::XComponentContext* rContext, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new SvxVertTextTbxCtrl(rContext)); +} + +SvxVertCTLTextTbxCtrl::SvxVertCTLTextTbxCtrl( + const css::uno::Reference<css::uno::XComponentContext>& rContext) + : SvxVertCTLTextTbxCtrl_Base(rContext, nullptr, OUString()) + , m_bVisible(false) +{ +} + +SvxVertCTLTextTbxCtrl::~SvxVertCTLTextTbxCtrl() {} + +void SAL_CALL SvxVertCTLTextTbxCtrl::initialize(const css::uno::Sequence<css::uno::Any>& rArguments) +{ + SvxVertCTLTextTbxCtrl_Base::initialize(rArguments); + // fdo#83320 Hide vertical text commands early + setFastPropertyValue_NoBroadcast(1, css::uno::Any(true)); + + if (m_pToolbar) + { + m_bVisible = m_pToolbar->get_item_visible(m_aCommandURL); + return; + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nItemId; + if (getToolboxId(nItemId, &pToolBox)) + m_bVisible = pToolBox->IsItemVisible(nItemId); +} + +void SAL_CALL SvxVertCTLTextTbxCtrl::statusChanged(const css::frame::FeatureStateEvent& rEvent) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nItemId; + bool bVclToolBox = getToolboxId(nItemId, &pToolBox); + + bool bEnabled = false; + if (rEvent.FeatureURL.Complete == ".uno:VerticalTextState") + { + bEnabled = m_bVisible && SvtCJKOptions::IsVerticalTextEnabled(); + } + else if (rEvent.FeatureURL.Complete == ".uno:CTLFontState") + { + bEnabled = m_bVisible && SvtCTLOptions::IsCTLFontEnabled(); + } + else + { + // normal command + bool bValue = false; + rEvent.State >>= bValue; + + if (m_pToolbar) + { + m_pToolbar->set_item_active(m_aCommandURL, bValue); + m_pToolbar->set_item_sensitive(m_aCommandURL, rEvent.IsEnabled); + } + + if (bVclToolBox) + { + pToolBox->CheckItem(nItemId, bValue); + pToolBox->EnableItem(nItemId, rEvent.IsEnabled); + } + + return; + } + + if (m_pToolbar) + { + m_pToolbar->set_item_visible(m_aCommandURL, bEnabled); + return; + } + + if (bVclToolBox) + { + pToolBox->ShowItem(nItemId, bEnabled); + + vcl::Window* pParent = pToolBox->GetParent(); + if (WindowType::FLOATINGWINDOW == pParent->GetType()) + { + Size aSize(pToolBox->CalcWindowSizePixel()); + pToolBox->SetPosSizePixel(Point(), aSize); + pParent->SetOutputSizePixel(aSize); + } + } +} + +// XServiceInfo +sal_Bool SAL_CALL SvxVertCTLTextTbxCtrl::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> SvxVertCTLTextTbxCtrl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |