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
20#include <memory>
22
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#include <tbxcolorupdate.hxx>
33#include <vcl/svapp.hxx>
34#include <vcl/settings.hxx>
36#include <stack>
37#include <set>
38#include <officecfg/Office/Common.hxx>
39#include <com/sun/star/frame/XDispatchProvider.hpp>
40#include <com/sun/star/frame/XDispatch.hpp>
41#include <com/sun/star/frame/Desktop.hpp>
42#include <com/sun/star/util/XURLTransformer.hpp>
43#include <com/sun/star/util/URLTransformer.hpp>
44
45#include <palettes.hxx>
46
47namespace
48{
49// Luminance modulation for the 6 effect presets.
50// 10000 is the default.
51sal_Int16 g_aLumMods[] = { 10000, 2000, 4000, 6000, 7500, 5000 };
52
53// Luminance offset for the 6 effect presets.
54// 0 is the default.
55sal_Int16 g_aLumOffs[] = { 0, 8000, 6000, 4000, 0, 0 };
56}
57
59 mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
60 mnNumOfPalettes(3),
61 mnCurrentPalette(0),
62 mnColorCount(0),
63 mpBtnUpdater(nullptr),
64 maColorSelectFunction(PaletteManager::DispatchColorCommand)
65{
67 if(pDocSh)
68 {
69 const SfxPoolItem* pItem = nullptr;
70 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
71 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
72 }
73 if(!pColorList.is())
77
78}
79
81{
82}
83
85{
86 m_Palettes.clear();
87 OUString aPalPaths = SvtPathOptions().GetPalettePath();
88
89 std::stack<OUString> aDirs;
90 sal_Int32 nIndex = 0;
91 do
92 {
93 aDirs.push(aPalPaths.getToken(0, ';', nIndex));
94 }
95 while (nIndex >= 0);
96
97 std::set<OUString> aNames;
98 //try all entries palette path list user first, then
99 //system, ignoring duplicate file names
100 while (!aDirs.empty())
101 {
102 OUString aPalPath = aDirs.top();
103 aDirs.pop();
104
105 osl::Directory aDir(aPalPath);
106 osl::DirectoryItem aDirItem;
107 osl::FileStatus aFileStat( osl_FileStatus_Mask_FileName |
108 osl_FileStatus_Mask_FileURL |
109 osl_FileStatus_Mask_Type );
110 if( aDir.open() == osl::FileBase::E_None )
111 {
112 while( aDir.getNextItem(aDirItem) == osl::FileBase::E_None )
113 {
114 aDirItem.getFileStatus(aFileStat);
115 if(aFileStat.isRegular() || aFileStat.isLink())
116 {
117 OUString aFName = aFileStat.getFileName();
118 INetURLObject aURLObj( aFileStat.getFileURL() );
119 OUString aFNameWithoutExt = aURLObj.GetBase();
120 if (aNames.find(aFName) == aNames.end())
121 {
122 std::unique_ptr<Palette> pPalette;
123 if( aFName.endsWithIgnoreAsciiCase(".gpl") )
124 pPalette.reset(new PaletteGPL(aFileStat.getFileURL(), aFNameWithoutExt));
125 else if( aFName.endsWithIgnoreAsciiCase(".soc") )
126 pPalette.reset(new PaletteSOC(aFileStat.getFileURL(), aFNameWithoutExt));
127 else if ( aFName.endsWithIgnoreAsciiCase(".ase") )
128 pPalette.reset(new PaletteASE(aFileStat.getFileURL(), aFNameWithoutExt));
129
130 if( pPalette && pPalette->IsValid() )
131 m_Palettes.push_back( std::move(pPalette) );
132 aNames.insert(aFNameWithoutExt);
133 }
134 }
135 }
136 }
137 }
138}
139
141{
142 return mnCurrentPalette == mnNumOfPalettes - 2;
143}
144
145void PaletteManager::GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16& rThemeIndex,
146 sal_Int16& rLumMod, sal_Int16& rLumOff)
147{
148 // Each column is the same color with different effects.
149 rThemeIndex = nItemId % 12;
150
151 // Each row is the same effect with different colors.
152 rLumMod = g_aLumMods[nItemId / 12];
153 rLumOff = g_aLumOffs[nItemId / 12];
154}
155
157{
158 if( mnCurrentPalette == 0)
159 {
160 rColorSet.Clear();
161 css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() );
162 css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() );
163 int nIx = 1;
164 for (int i = 0; i < CustomColorList.getLength(); ++i)
165 {
166 Color aColor(ColorTransparency, CustomColorList[i]);
167 rColorSet.InsertItem(nIx, aColor, CustomColorNameList[i]);
168 ++nIx;
169 }
170 }
171 else if (IsThemePaletteSelected())
172 {
173 SfxObjectShell* pObjectShell = SfxObjectShell::Current();
174 if (pObjectShell)
175 {
176 std::vector<Color> aColors = pObjectShell->GetThemeColors();
177 mnColorCount = aColors.size();
178 rColorSet.Clear();
179 if (aColors.size() >= 12)
180 {
181 std::vector<OUString> aEffectNames = {
182 SvxResId(RID_SVXSTR_THEME_EFFECT1), SvxResId(RID_SVXSTR_THEME_EFFECT2),
183 SvxResId(RID_SVXSTR_THEME_EFFECT3), SvxResId(RID_SVXSTR_THEME_EFFECT4),
184 SvxResId(RID_SVXSTR_THEME_EFFECT5),
185 };
186
187 std::vector<OUString> aColorNames = {
188 SvxResId(RID_SVXSTR_THEME_COLOR1), SvxResId(RID_SVXSTR_THEME_COLOR2),
189 SvxResId(RID_SVXSTR_THEME_COLOR3), SvxResId(RID_SVXSTR_THEME_COLOR4),
190 SvxResId(RID_SVXSTR_THEME_COLOR5), SvxResId(RID_SVXSTR_THEME_COLOR6),
191 SvxResId(RID_SVXSTR_THEME_COLOR7), SvxResId(RID_SVXSTR_THEME_COLOR8),
192 SvxResId(RID_SVXSTR_THEME_COLOR9), SvxResId(RID_SVXSTR_THEME_COLOR10),
193 SvxResId(RID_SVXSTR_THEME_COLOR11), SvxResId(RID_SVXSTR_THEME_COLOR12),
194 };
195
196 sal_uInt16 nItemId = 0;
197 // Each row is one effect type (no effect + each type).
198 for (size_t nEffect = 0; nEffect < aEffectNames.size() + 1; ++nEffect)
199 {
200 // Each column is one color type.
201 for (size_t nColor = 0; nColor < aColorNames.size(); ++nColor)
202 {
203 Color aColor = aColors[nColor];
204 aColor.ApplyLumModOff(g_aLumMods[nEffect], g_aLumOffs[nEffect]);
205 OUString aColorName;
206 if (nEffect == 0)
207 {
208 aColorName = aColorNames[nColor];
209 }
210 else
211 {
212 aColorName = aEffectNames[nEffect - 1].replaceAll("%1", aColorNames[nColor]);
213 }
214 rColorSet.InsertItem(nItemId++, aColor, aColorName);
215 }
216 }
217 }
218 }
219 }
220 else if( mnCurrentPalette == mnNumOfPalettes - 1 )
221 {
222 // Add doc colors to palette
224 if (pDocSh)
225 {
226 std::set<Color> aColors = pDocSh->GetDocColors();
227 mnColorCount = aColors.size();
228 rColorSet.Clear();
229 rColorSet.addEntriesForColorSet(aColors, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " ") );
230 }
231 }
232 else
233 {
234 m_Palettes[mnCurrentPalette - 1]->LoadColorSet( rColorSet );
235 mnColorCount = rColorSet.GetItemCount();
236 }
237}
238
240{
241 maRecentColors.clear();
242 rColorSet.Clear();
243 css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get());
244 css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get());
245 int nIx = 1;
246 const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength();
247 for (int i = 0; i < Colorlist.getLength(); ++i)
248 {
249 Color aColor(ColorTransparency, Colorlist[i]);
250 OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase());
251 maRecentColors.emplace_back(aColor, sColorName);
252 rColorSet.InsertItem(nIx, aColor, sColorName);
253 ++nIx;
254 }
255}
256
257std::vector<OUString> PaletteManager::GetPaletteList()
258{
259 std::vector<OUString> aPaletteNames
260 {
261 SvxResId( RID_SVXSTR_CUSTOM_PAL )
262 };
263 for (auto const& it : m_Palettes)
264 {
265 aPaletteNames.push_back( (*it).GetName() );
266 }
267 aPaletteNames.push_back(SvxResId(RID_SVXSTR_THEME_COLORS));
268 aPaletteNames.push_back( SvxResId ( RID_SVXSTR_DOC_COLORS ) );
269
270 return aPaletteNames;
271}
272
273void PaletteManager::SetPalette( sal_Int32 nPos )
274{
276 if( nPos != mnNumOfPalettes - 1 && nPos != 0)
277 {
281 auto name = GetPaletteName(); // may change pColorList
282 pColorList->SetName(name);
283 if(pColorList->Load())
284 {
286 if (pShell != nullptr)
287 {
288 SvxColorListItem aColorItem(pColorList, SID_COLOR_TABLE);
289 pShell->PutItem( aColorItem );
290 }
291 }
292 }
293 OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
294 if (aPaletteName != GetPaletteName())
295 {
296 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
297 officecfg::Office::Common::UserColors::PaletteName::set(GetPaletteName(), batch);
298 batch->commit();
299 }
300}
301
303{
304 return mnCurrentPalette;
305}
306
308{
309 std::vector<OUString> aNames(GetPaletteList());
311 {
313 if(pDocSh)
314 {
315 const SfxPoolItem* pItem = nullptr;
316 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
317 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
318 }
319 }
320 return aNames[mnCurrentPalette];
321}
322
324{
325 if (mnCurrentPalette < m_Palettes.size() && mnCurrentPalette != 0)
326 return m_Palettes[mnCurrentPalette - 1]->GetPath();
327 else
328 return OUString();
329}
330
332{
333 return mnColorCount;
334}
335
337{
338 return maRecentColors.size();
339}
340
341void PaletteManager::AddRecentColor(const Color& rRecentColor, const OUString& rName, bool bFront)
342{
343 auto itColor = std::find_if(maRecentColors.begin(),
344 maRecentColors.end(),
345 [rRecentColor] (const NamedColor &a) { return a.first == rRecentColor; });
346 // if recent color to be added is already in list, remove it
347 if( itColor != maRecentColors.end() )
348 maRecentColors.erase( itColor );
349
350 if (maRecentColors.size() == mnMaxRecentColors)
351 maRecentColors.pop_back();
352 if (bFront)
353 maRecentColors.push_front(std::make_pair(rRecentColor, rName));
354 else
355 maRecentColors.emplace_back(rRecentColor, rName);
356 css::uno::Sequence< sal_Int32 > aColorList(maRecentColors.size());
357 auto aColorListRange = asNonConstRange(aColorList);
358 css::uno::Sequence< OUString > aColorNameList(maRecentColors.size());
359 auto aColorNameListRange = asNonConstRange(aColorNameList);
360 for (size_t i = 0; i < maRecentColors.size(); ++i)
361 {
362 aColorListRange[i] = static_cast<sal_Int32>(maRecentColors[i].first);
363 aColorNameListRange[i] = maRecentColors[i].second;
364 }
365 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
366 officecfg::Office::Common::UserColors::RecentColor::set(aColorList, batch);
367 officecfg::Office::Common::UserColors::RecentColorName::set(aColorNameList, batch);
368 batch->commit();
369}
370
372{
373 mpBtnUpdater = pBtnUpdater;
374}
375
377{
378 maColorSelectFunction = aColorSelectFunction;
379}
380
381void PaletteManager::PopupColorPicker(weld::Window* pParent, const OUString& aCommand, const Color& rInitialColor)
382{
383 // The calling object goes away during aColorDlg.Execute(), so we must copy this
384 OUString aCommandCopy = aCommand;
385 m_pColorDlg = std::make_unique<SvColorDialog>();
386 m_pColorDlg->SetColor(rInitialColor);
388 m_pColorDlg->ExecuteAsync(pParent, [this, aCommandCopy] (sal_Int32 nResult) {
389 if (nResult == RET_OK)
390 {
391 Color aLastColor = m_pColorDlg->GetColor();
392 OUString sColorName = "#" + aLastColor.AsRGBHexString().toAsciiUpperCase();
393 NamedColor aNamedColor = std::make_pair(aLastColor, sColorName);
394 if (mpBtnUpdater)
395 mpBtnUpdater->Update(aNamedColor);
396 AddRecentColor(aLastColor, sColorName);
398 }
399 });
400}
401
402void PaletteManager::DispatchColorCommand(const OUString& aCommand, const svx::NamedThemedColor& rColor)
403{
404 using namespace css::uno;
405 using namespace css::frame;
406 using namespace css::beans;
407 using namespace css::util;
408
409 Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
410 Reference<XDesktop2> xDesktop = Desktop::create(xContext);
411 Reference<XFrame> xFrame(xDesktop->getCurrentFrame());
412 Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY);
413 if (!xDispatchProvider.is())
414 return;
415
416 INetURLObject aObj( aCommand );
417
418 std::vector<PropertyValue> aArgs{
419 comphelper::makePropertyValue(aObj.GetURLPath(), sal_Int32(rColor.m_aColor)),
420 };
421 if (rColor.m_nThemeIndex != -1)
422 {
423 aArgs.push_back(comphelper::makePropertyValue("ColorThemeIndex", rColor.m_nThemeIndex));
424 aArgs.push_back(comphelper::makePropertyValue("ColorLumMod", rColor.m_nLumMod));
425 aArgs.push_back(comphelper::makePropertyValue("ColorLumOff", rColor.m_nLumOff));
426 }
427
429 aTargetURL.Complete = aCommand;
430 Reference<XURLTransformer> xURLTransformer(URLTransformer::create(comphelper::getProcessComponentContext()));
431 xURLTransformer->parseStrict(aTargetURL);
432
433 Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0);
434 if (xDispatch.is())
435 {
437 if (xFrame->getContainerWindow().is())
438 xFrame->getContainerWindow()->setFocus();
439 }
440}
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::function< void(const OUString &, const svx::NamedThemedColor &)> ColorSelectFunction
Definition: Palette.hxx:51
std::pair< Color, OUString > NamedColor
Definition: Palette.hxx:30
OUString AsRGBHexString() const
void ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff)
OUString GetURLPath(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetBase() const
tools::Long GetColorCount() const
const sal_uInt16 mnMaxRecentColors
void SetColorSelectFunction(const ColorSelectFunction &aColorSelectFunction)
void PopupColorPicker(weld::Window *pParent, const OUString &aCommand, const Color &rInitialColor)
std::vector< OUString > GetPaletteList()
svx::ToolboxButtonColorUpdaterBase * mpBtnUpdater
static void GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16 &rThemeIndex, sal_Int16 &rLumMod, sal_Int16 &rLumOff)
void ReloadColorSet(SvxColorValueSet &rColorSet)
tools::Long mnColorCount
tools::Long GetRecentColorCount() const
std::deque< NamedColor > maRecentColors
sal_uInt16 mnNumOfPalettes
XColorListRef pColorList
void ReloadRecentColorSet(SvxColorValueSet &rColorSet)
sal_uInt16 mnCurrentPalette
ColorSelectFunction maColorSelectFunction
std::vector< std::unique_ptr< Palette > > m_Palettes
static void DispatchColorCommand(const OUString &aCommand, const svx::NamedThemedColor &rColor)
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::vector< Color > GetThemeColors()
virtual std::set< Color > GetDocColors()
static 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:376
static XPropertyListRef CreatePropertyListFromURL(XPropertyListType t, std::u16string_view rUrl)
Definition: xtable.cxx:354
static std::shared_ptr< ConfigurationChanges > create()
helper class to update a color in a toolbox button image
void Update(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
long Long
A color with an optional name and other theming-related properties.
Definition: Palette.hxx:38
static NamedThemedColor FromNamedColor(const NamedColor &rNamedColor)
Definition: Palette.cxx:369
sal_Int16 m_nLumMod
Definition: Palette.hxx:42
sal_Int16 m_nThemeIndex
Definition: Palette.hxx:41
sal_Int16 m_nLumOff
Definition: Palette.hxx:43
Reference< XFrame > xFrame
OUString aCommand
OUString aTargetURL
RET_OK