LibreOffice Module svx (master) 1
PaletteManager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
24#include <tools/urlobj.hxx>
25#include <osl/file.hxx>
27#include <sfx2/objsh.hxx>
28#include <svx/drawitem.hxx>
29#include <svx/strings.hrc>
30#include <svx/svxids.hrc>
31#include <svx/dialmgr.hxx>
32
33#include <tbxcolorupdate.hxx>
34#include <vcl/svapp.hxx>
35#include <vcl/settings.hxx>
37#include <officecfg/Office/Common.hxx>
38#include <com/sun/star/frame/XDispatchProvider.hpp>
39#include <com/sun/star/frame/XDispatch.hpp>
40#include <com/sun/star/frame/Desktop.hpp>
41#include <com/sun/star/util/XURLTransformer.hpp>
42#include <com/sun/star/util/URLTransformer.hpp>
45#include <editeng/colritem.hxx>
46#include <editeng/memberids.h>
47
48#include <palettes.hxx>
49
50#include <memory>
51#include <array>
52#include <stack>
53#include <set>
54
56 mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
57 mnNumOfPalettes(3),
58 mnCurrentPalette(0),
59 mnColorCount(0),
60 mpBtnUpdater(nullptr),
61 maColorSelectFunction(PaletteManager::DispatchColorCommand)
62
63{
65 if(pDocSh)
66 {
67 const SfxPoolItem* pItem = nullptr;
68 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
69 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
70 }
71 if(!pColorList.is())
75
76}
77
79 : mnMaxRecentColors(pClone->mnMaxRecentColors)
80 , mnNumOfPalettes(pClone->mnNumOfPalettes)
81 , mnCurrentPalette(pClone->mnCurrentPalette)
82 , mnColorCount(pClone->mnColorCount)
83 , mpBtnUpdater(nullptr)
84 , pColorList(pClone->pColorList)
85 , maRecentColors(pClone->maRecentColors)
86 , maColorSelectFunction(PaletteManager::DispatchColorCommand)
87{
88 for (const auto& a : pClone->m_Palettes)
89 m_Palettes.emplace_back(a->Clone());
90}
91
93{
94 return new PaletteManager(this);
95}
96
98{
99}
100
102{
103 m_Palettes.clear();
104 OUString aPalPaths = SvtPathOptions().GetPalettePath();
105
106 std::stack<OUString> aDirs;
107 sal_Int32 nIndex = 0;
108 do
109 {
110 aDirs.push(aPalPaths.getToken(0, ';', nIndex));
111 }
112 while (nIndex >= 0);
113
114 std::set<OUString> aNames;
115 //try all entries palette path list user first, then
116 //system, ignoring duplicate file names
117 while (!aDirs.empty())
118 {
119 OUString aPalPath = aDirs.top();
120 aDirs.pop();
121
122 osl::Directory aDir(aPalPath);
123 osl::DirectoryItem aDirItem;
124 osl::FileStatus aFileStat( osl_FileStatus_Mask_FileName |
125 osl_FileStatus_Mask_FileURL |
126 osl_FileStatus_Mask_Type );
127 if( aDir.open() == osl::FileBase::E_None )
128 {
129 while( aDir.getNextItem(aDirItem) == osl::FileBase::E_None )
130 {
131 aDirItem.getFileStatus(aFileStat);
132 if(aFileStat.isRegular() || aFileStat.isLink())
133 {
134 OUString aFName = aFileStat.getFileName();
135 INetURLObject aURLObj( aFileStat.getFileURL() );
136 OUString aFNameWithoutExt = aURLObj.GetBase();
137 if (aNames.find(aFName) == aNames.end())
138 {
139 std::unique_ptr<Palette> pPalette;
140 if( aFName.endsWithIgnoreAsciiCase(".gpl") )
141 pPalette.reset(new PaletteGPL(aFileStat.getFileURL(), aFNameWithoutExt));
142 else if( aFName.endsWithIgnoreAsciiCase(".soc") )
143 pPalette.reset(new PaletteSOC(aFileStat.getFileURL(), aFNameWithoutExt));
144 else if ( aFName.endsWithIgnoreAsciiCase(".ase") )
145 pPalette.reset(new PaletteASE(aFileStat.getFileURL(), aFNameWithoutExt));
146
147 if( pPalette && pPalette->IsValid() )
148 m_Palettes.push_back( std::move(pPalette) );
149 aNames.insert(aFNameWithoutExt);
150 }
151 }
152 }
153 }
154 }
155}
156
158{
159 return mnCurrentPalette == mnNumOfPalettes - 2;
160}
161
162bool PaletteManager::GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& rThemeIndex, sal_uInt16& rEffectIndex)
163{
164 // Each column is the same color with different effects.
165 rThemeIndex = nItemId % 12;
166
167 rEffectIndex = nItemId / 12;
168 if (rEffectIndex > 5)
169 return false;
170 return true;
171}
172
173bool PaletteManager::GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16& rLumMod, sal_Int16& rLumOff)
174{
176 return false;
177
178 auto const& aThemeColorData = moThemePaletteCollection->maColors[nThemeIndex];
179
180 rLumMod = aThemeColorData.getLumMod(nEffect);
181 rLumOff = aThemeColorData.getLumOff(nEffect);
182
183 return true;
184}
185
187{
189 if( mnCurrentPalette == 0)
190 {
191 rColorSet.Clear();
192 css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() );
193 css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() );
194 int nIx = 1;
195 for (int i = 0; i < CustomColorList.getLength(); ++i)
196 {
197 Color aColor(ColorTransparency, CustomColorList[i]);
198 rColorSet.InsertItem(nIx, aColor, CustomColorNameList[i]);
199 ++nIx;
200 }
201 }
202 else if (IsThemePaletteSelected())
203 {
204 SfxObjectShell* pObjectShell = SfxObjectShell::Current();
205 if (pObjectShell)
206 {
207 auto pColorSet = pObjectShell->GetThemeColors();
208 mnColorCount = 12;
209 rColorSet.Clear();
210 sal_uInt16 nItemId = 1;
211
212 if (!pColorSet)
213 return;
214
215 svx::ThemeColorPaletteManager aThemeColorManager(pColorSet);
216 moThemePaletteCollection = aThemeColorManager.generate();
217
218 // Each row is one effect type (no effect + each type).
219 for (size_t nEffect : {0, 1, 2, 3, 4, 5})
220 {
221 // Each column is one color type.
222 for (auto const& rColorData : moThemePaletteCollection->maColors)
223 {
224 auto const& rEffect = rColorData.maEffects[nEffect];
225 rColorSet.InsertItem(nItemId++, rEffect.maColor, rEffect.maColorName);
226 }
227 }
228 }
229 }
230 else if( mnCurrentPalette == mnNumOfPalettes - 1 )
231 {
232 // Add doc colors to palette
234 if (pDocSh)
235 {
236 std::set<Color> aColors = pDocSh->GetDocColors();
237 mnColorCount = aColors.size();
238 rColorSet.Clear();
239 rColorSet.addEntriesForColorSet(aColors, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " ") );
240 }
241 }
242 else
243 {
244 m_Palettes[mnCurrentPalette - 1]->LoadColorSet( rColorSet );
245 mnColorCount = rColorSet.GetItemCount();
246 }
247}
248
250{
251 maRecentColors.clear();
252 rColorSet.Clear();
253 css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get());
254 css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get());
255 int nIx = 1;
256 const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength();
257 for (int i = 0; i < Colorlist.getLength(); ++i)
258 {
259 Color aColor(ColorTransparency, Colorlist[i]);
260 OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase());
261 maRecentColors.emplace_back(aColor, sColorName);
262 rColorSet.InsertItem(nIx, aColor, sColorName);
263 ++nIx;
264 }
265}
266
267std::vector<OUString> PaletteManager::GetPaletteList()
268{
269 std::vector<OUString> aPaletteNames
270 {
271 SvxResId( RID_SVXSTR_CUSTOM_PAL )
272 };
273 for (auto const& it : m_Palettes)
274 {
275 aPaletteNames.push_back( (*it).GetName() );
276 }
277 aPaletteNames.push_back(SvxResId(RID_SVXSTR_THEME_COLORS));
278 aPaletteNames.push_back( SvxResId ( RID_SVXSTR_DOC_COLORS ) );
279
280 return aPaletteNames;
281}
282
283void PaletteManager::SetPalette( sal_Int32 nPos )
284{
286 if( nPos != mnNumOfPalettes - 1 && nPos != 0)
287 {
291 auto name = GetPaletteName(); // may change pColorList
292 pColorList->SetName(name);
293 if(pColorList->Load())
294 {
296 if (pShell != nullptr)
297 {
298 SvxColorListItem aColorItem(pColorList, SID_COLOR_TABLE);
299 pShell->PutItem( aColorItem );
300 }
301 }
302 }
303 OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
304 if (aPaletteName != GetPaletteName())
305 {
306 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
307 officecfg::Office::Common::UserColors::PaletteName::set(GetPaletteName(), batch);
308 batch->commit();
309 }
310}
311
313{
314 return mnCurrentPalette;
315}
316
318{
319 std::vector<OUString> aNames(GetPaletteList());
321 {
323 if(pDocSh)
324 {
325 const SfxPoolItem* pItem = nullptr;
326 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
327 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
328 }
329 }
330 return aNames[mnCurrentPalette];
331}
332
334{
335 if (mnCurrentPalette < m_Palettes.size() && mnCurrentPalette != 0)
336 return m_Palettes[mnCurrentPalette - 1]->GetPath();
337 else
338 return OUString();
339}
340
342{
343 return mnColorCount;
344}
345
347{
348 return maRecentColors.size();
349}
350
351void PaletteManager::AddRecentColor(const Color& rRecentColor, const OUString& rName, bool bFront)
352{
353 auto itColor = std::find_if(maRecentColors.begin(),
354 maRecentColors.end(),
355 [rRecentColor] (const NamedColor &aColor) { return aColor.m_aColor == rRecentColor; });
356 // if recent color to be added is already in list, remove it
357 if( itColor != maRecentColors.end() )
358 maRecentColors.erase( itColor );
359
360 if (maRecentColors.size() == mnMaxRecentColors)
361 maRecentColors.pop_back();
362 if (bFront)
363 maRecentColors.emplace_front(rRecentColor, rName);
364 else
365 maRecentColors.emplace_back(rRecentColor, rName);
366 css::uno::Sequence< sal_Int32 > aColorList(maRecentColors.size());
367 auto aColorListRange = asNonConstRange(aColorList);
368 css::uno::Sequence< OUString > aColorNameList(maRecentColors.size());
369 auto aColorNameListRange = asNonConstRange(aColorNameList);
370 for (size_t i = 0; i < maRecentColors.size(); ++i)
371 {
372 aColorListRange[i] = static_cast<sal_Int32>(maRecentColors[i].m_aColor);
373 aColorNameListRange[i] = maRecentColors[i].m_aName;
374 }
375 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
376 officecfg::Office::Common::UserColors::RecentColor::set(aColorList, batch);
377 officecfg::Office::Common::UserColors::RecentColorName::set(aColorNameList, batch);
378 batch->commit();
379}
380
382{
383 if (mpBtnUpdater)
385}
386
388{
389 mpBtnUpdater = pBtnUpdater;
390}
391
393{
394 maColorSelectFunction = aColorSelectFunction;
395}
396
397void PaletteManager::PopupColorPicker(weld::Window* pParent, const OUString& aCommand, const Color& rInitialColor)
398{
399 // The calling object goes away during aColorDlg.Execute(), so we must copy this
400 OUString aCommandCopy = aCommand;
401 m_pColorDlg = std::make_unique<SvColorDialog>();
402 m_pColorDlg->SetColor(rInitialColor);
404 m_pColorDlg->ExecuteAsync(pParent, [this, aCommandCopy] (sal_Int32 nResult) {
405 if (nResult == RET_OK)
406 {
407 Color aLastColor = m_pColorDlg->GetColor();
408 OUString sColorName = "#" + aLastColor.AsRGBHexString().toAsciiUpperCase();
409 NamedColor aNamedColor(aLastColor, sColorName);
410 SetSplitButtonColor(aNamedColor);
411 AddRecentColor(aLastColor, sColorName);
412 maColorSelectFunction(aCommandCopy, aNamedColor);
413 }
414 });
415}
416
417void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedColor& rColor)
418{
419 using namespace css;
420 using namespace css::uno;
421 using namespace css::frame;
422 using namespace css::beans;
423 using namespace css::util;
424
425 Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
426 Reference<XDesktop2> xDesktop = Desktop::create(xContext);
427 Reference<XFrame> xFrame(xDesktop->getCurrentFrame());
428 Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY);
429 if (!xDispatchProvider.is())
430 return;
431
432 INetURLObject aObj( aCommand );
433
434 std::vector<PropertyValue> aArgs{
435 comphelper::makePropertyValue(aObj.GetURLPath()+ ".Color", sal_Int32(rColor.m_aColor)),
436 };
437
438 if (rColor.m_nThemeIndex != -1)
439 {
440 model::ComplexColor aComplexColor;
442 if (rColor.m_nLumMod != 10000)
444 if (rColor.m_nLumMod != 0)
446
447 uno::Any aAny;
448 aAny <<= OStringToOUString(model::color::convertToJSON(aComplexColor), RTL_TEXTENCODING_UTF8);
449
450 aArgs.push_back(comphelper::makePropertyValue(aObj.GetURLPath() + ".ComplexColorJSON", aAny));
451 }
452
454 aTargetURL.Complete = aCommand;
455 Reference<XURLTransformer> xURLTransformer(URLTransformer::create(comphelper::getProcessComponentContext()));
456 xURLTransformer->parseStrict(aTargetURL);
457
458 Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0);
459 if (xDispatch.is())
460 {
462 if (xFrame->getContainerWindow().is())
463 xFrame->getContainerWindow()->setFocus();
464 }
465}
466
467/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::function< void(const OUString &, const NamedColor &)> ColorSelectFunction
Definition: Palette.hxx:27
OUString AsRGBHexString() const
OUString GetURLPath(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetBase() const
tools::Long GetColorCount() const
const sal_uInt16 mnMaxRecentColors
bool GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16 &rLumMod, sal_Int16 &rLumOff)
void SetColorSelectFunction(const ColorSelectFunction &aColorSelectFunction)
void PopupColorPicker(weld::Window *pParent, const OUString &aCommand, const Color &rInitialColor)
std::vector< OUString > GetPaletteList()
svx::ToolboxButtonColorUpdaterBase * mpBtnUpdater
PaletteManager * Clone() const
void ReloadColorSet(SvxColorValueSet &rColorSet)
static bool GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16 &rThemeIndex, sal_uInt16 &rEffectIndex)
tools::Long mnColorCount
void SetSplitButtonColor(const NamedColor &rColor)
tools::Long GetRecentColorCount() const
std::deque< NamedColor > maRecentColors
std::optional< svx::ThemePaletteCollection > moThemePaletteCollection
sal_uInt16 mnNumOfPalettes
static void DispatchColorCommand(const OUString &aCommand, const NamedColor &rColor)
XColorListRef pColorList
void ReloadRecentColorSet(SvxColorValueSet &rColorSet)
sal_uInt16 mnCurrentPalette
ColorSelectFunction maColorSelectFunction
std::vector< std::unique_ptr< Palette > > m_Palettes
std::unique_ptr< SvColorDialog > m_pColorDlg
void SetPalette(sal_Int32 nPos)
OUString GetPaletteName()
bool IsThemePaletteSelected() const
OUString GetSelectedPalettePath()
void SetBtnUpdater(svx::ToolboxButtonColorUpdaterBase *pBtnUpdater)
sal_Int32 GetPalette() const
void AddRecentColor(const Color &rRecentColor, const OUString &rColorName, bool bFront=true)
virtual std::shared_ptr< model::ColorSet > GetThemeColors()
virtual std::set< Color > GetDocColors()
static SAL_WARN_UNUSED_RESULT SfxObjectShell * Current()
void PutItem(const SfxPoolItem &rItem)
const SfxPoolItem * GetItem(sal_uInt16 nSlotId) const
const OUString & GetPalettePath() const
void addEntriesForColorSet(const std::set< Color > &rColorSet, std::u16string_view rNamePrefix)
void InsertItem(sal_uInt16 nItemId, const Image &rImage)
size_t GetItemCount() const
void Clear()
static XColorListRef CreateStdColorList()
Definition: xtabcolr.cxx:31
static XColorListRef AsColorList(rtl::Reference< XPropertyList > const &plist)
Definition: xtable.hxx:378
static XPropertyListRef CreatePropertyListFromURL(XPropertyListType t, std::u16string_view rUrl)
Definition: xtable.cxx:354
static std::shared_ptr< ConfigurationChanges > create()
void setSchemeColor(ThemeColorType eType)
void addTransformation(Transformation const &rTransform)
helper class to update a color in a toolbox button image
void SetRecentColor(const NamedColor &rNamedColor)
ColorTransparency
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
Reference< XDispatch > xDispatch
const char * name
sal_Int32 nIndex
uno_Any a
sal_uInt16 nPos
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
OString convertToJSON(model::ComplexColor const &rComplexColor)
constexpr ThemeColorType convertToThemeColorType(sal_Int32 nIndex)
long Long
Color m_aColor
sal_Int16 m_nLumOff
sal_Int16 m_nLumMod
sal_Int16 m_nThemeIndex
Reference< XFrame > xFrame
OUString aCommand
OUString aTargetURL
RET_OK