summaryrefslogtreecommitdiffstats
path: root/svx/source/tbxctrls
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/tbxctrls')
-rw-r--r--svx/source/tbxctrls/Palette.cxx383
-rw-r--r--svx/source/tbxctrls/PaletteManager.cxx472
-rw-r--r--svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx184
-rw-r--r--svx/source/tbxctrls/StylesPreviewWindow.cxx681
-rw-r--r--svx/source/tbxctrls/SvxColorChildWindow.cxx43
-rw-r--r--svx/source/tbxctrls/SvxColorValueSet.cxx166
-rw-r--r--svx/source/tbxctrls/SvxPresetListBox.cxx112
-rw-r--r--svx/source/tbxctrls/bulletsnumbering.cxx235
-rw-r--r--svx/source/tbxctrls/colrctrl.cxx423
-rw-r--r--svx/source/tbxctrls/extrusioncontrols.cxx968
-rw-r--r--svx/source/tbxctrls/extrusioncontrols.hxx224
-rw-r--r--svx/source/tbxctrls/fillctrl.cxx1097
-rw-r--r--svx/source/tbxctrls/fontworkgallery.cxx807
-rw-r--r--svx/source/tbxctrls/formatpaintbrushctrl.cxx105
-rw-r--r--svx/source/tbxctrls/grafctrl.cxx961
-rw-r--r--svx/source/tbxctrls/itemwin.cxx347
-rw-r--r--svx/source/tbxctrls/layctrl.cxx799
-rw-r--r--svx/source/tbxctrls/lboxctrl.cxx347
-rw-r--r--svx/source/tbxctrls/linectrl.cxx646
-rw-r--r--svx/source/tbxctrls/linemetricbox.hxx56
-rw-r--r--svx/source/tbxctrls/linewidthctrl.cxx101
-rw-r--r--svx/source/tbxctrls/tbcontrl.cxx4523
-rw-r--r--svx/source/tbxctrls/tbunocontroller.cxx515
-rw-r--r--svx/source/tbxctrls/tbunosearchcontrollers.cxx1491
-rw-r--r--svx/source/tbxctrls/tbxcolor.cxx96
-rw-r--r--svx/source/tbxctrls/tbxcolorupdate.cxx393
-rw-r--r--svx/source/tbxctrls/tbxdrctl.cxx99
-rw-r--r--svx/source/tbxctrls/verttexttbxctrl.cxx160
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: */