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>
21 #include <svx/PaletteManager.hxx>
22 
24 #include <tools/urlobj.hxx>
25 #include <osl/file.hxx>
26 #include <unotools/pathoptions.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>
35 #include <comphelper/sequence.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 
47 namespace
48 {
49 // Luminance modulation for the 6 effect presets.
50 // 10000 is the default.
51 sal_Int16 g_aLumMods[] = { 10000, 2000, 4000, 6000, 7500, 5000 };
52 
53 // Luminance offset for the 6 effect presets.
54 // 0 is the default.
55 sal_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())
75  LoadPalettes();
76  mnNumOfPalettes += m_Palettes.size();
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 
145 void 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, 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 
257 std::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 
273 void PaletteManager::SetPalette( sal_Int32 nPos )
274 {
275  mnCurrentPalette = nPos;
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 
302 sal_Int32 PaletteManager::GetPalette() const
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 
341 void 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 
381 void 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 
402 void 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 
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 
428  URL aTargetURL;
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  {
436  xDispatch->dispatch(aTargetURL, comphelper::containerToSequence(aArgs));
437  if (xFrame->getContainerWindow().is())
438  xFrame->getContainerWindow()->setFocus();
439  }
440 }
441 
442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString AsRGBHexString() const
std::pair< Color, OUString > NamedColor
Definition: Palette.hxx:30
void ReloadColorSet(SvxColorValueSet &rColorSet)
sal_Int32 nIndex
static NamedThemedColor FromNamedColor(const NamedColor &rNamedColor)
Definition: Palette.cxx:368
A color with an optional name and other theming-related properties.
Definition: Palette.hxx:37
sal_Int16 m_nLumOff
Definition: Palette.hxx:43
virtual std::vector< Color > GetThemeColors()
static std::shared_ptr< ConfigurationChanges > create()
XColorListRef pColorList
static XColorListRef CreateStdColorList()
Definition: xtabcolr.cxx:31
OUString GetURLPath(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
long Long
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
Reference< XFrame > xFrame
svx::ToolboxButtonColorUpdaterBase * mpBtnUpdater
tools::Long mnColorCount
static SfxObjectShell * Current()
sal_Int32 GetPalette() const
void PutItem(const SfxPoolItem &rItem)
OUString GetSelectedPalettePath()
tools::Long GetColorCount() const
const OUString & GetPalettePath() const
void Clear()
tools::Long GetRecentColorCount() const
OUString GetBase() const
void addEntriesForColorSet(const std::set< Color > &rColorSet, const OUString &rNamePrefix)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
static void GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16 &rThemeIndex, sal_Int16 &rLumMod, sal_Int16 &rLumOff)
void SetBtnUpdater(svx::ToolboxButtonColorUpdaterBase *pBtnUpdater)
static XColorListRef AsColorList(rtl::Reference< XPropertyList > const &plist)
Definition: xtable.hxx:376
const SfxPoolItem * GetItem(sal_uInt16 nSlotId) const
const sal_uInt16 mnMaxRecentColors
void SetPalette(sal_Int32 nPos)
int i
std::vector< OUString > GetPaletteList()
uno_Any a
void ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff)
OUString GetPaletteName()
void InsertItem(sal_uInt16 nItemId, const Image &rImage)
bool IsThemePaletteSelected() const
void ReloadRecentColorSet(SvxColorValueSet &rColorSet)
ColorSelectFunction maColorSelectFunction
ColorTransparency
std::deque< NamedColor > maRecentColors
void PopupColorPicker(weld::Window *pParent, const OUString &aCommand, const Color &rInitialColor)
virtual OUString GetPath() const override
virtual std::set< Color > GetDocColors()
Reference< XDispatch > xDispatch
static void DispatchColorCommand(const OUString &aCommand, const svx::NamedThemedColor &rColor)
size_t GetItemCount() const
helper class to update a color in a toolbox button image
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
static XPropertyListRef CreatePropertyListFromURL(XPropertyListType t, std::u16string_view rUrl)
Definition: xtable.cxx:353
RET_OK
sal_uInt16 mnCurrentPalette
Reference< XComponentContext > getProcessComponentContext()
const char * name
void SetColorSelectFunction(const ColorSelectFunction &aColorSelectFunction)
std::vector< std::unique_ptr< Palette > > m_Palettes
OUString aTargetURL
sal_uInt16 mnNumOfPalettes
void AddRecentColor(const Color &rRecentColor, const OUString &rColorName, bool bFront=true)
std::unique_ptr< SvColorDialog > m_pColorDlg
std::function< void(const OUString &, const svx::NamedThemedColor &)> ColorSelectFunction
Definition: Palette.hxx:51
sal_Int16 m_nLumMod
Definition: Palette.hxx:42
sal_Int16 m_nThemeIndex
Definition: Palette.hxx:41
void Update(const NamedColor &rNamedColor)