Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / tbxctrls / PaletteManager.cxx
blob1a48c403feb2ea65d476e7633a125151b55926b8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svx/PaletteManager.hxx>
22 #include <basegfx/color/bcolortools.hxx>
23 #include <comphelper/propertyvalue.hxx>
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>
33 #include <tbxcolorupdate.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/settings.hxx>
36 #include <comphelper/sequence.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>
43 #include <docmodel/color/ComplexColor.hxx>
44 #include <docmodel/color/ComplexColorJSON.hxx>
45 #include <editeng/colritem.hxx>
46 #include <editeng/memberids.h>
48 #include <palettes.hxx>
50 #include <memory>
51 #include <array>
52 #include <stack>
53 #include <set>
55 PaletteManager::PaletteManager() :
56 mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
57 mnNumOfPalettes(3),
58 mnCurrentPalette(0),
59 mnColorCount(0),
60 mpBtnUpdater(nullptr),
61 maColorSelectFunction(PaletteManager::DispatchColorCommand)
64 SfxObjectShell* pDocSh = SfxObjectShell::Current();
65 if(pDocSh)
67 const SfxPoolItem* pItem = nullptr;
68 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
69 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
71 if(!pColorList.is())
72 pColorList = XColorList::CreateStdColorList();
73 LoadPalettes();
74 mnNumOfPalettes += m_Palettes.size();
78 PaletteManager::PaletteManager(const PaletteManager* pClone)
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)
88 for (const auto& a : pClone->m_Palettes)
89 m_Palettes.emplace_back(a->Clone());
92 PaletteManager* PaletteManager::Clone() const
94 return new PaletteManager(this);
97 PaletteManager::~PaletteManager()
101 void PaletteManager::LoadPalettes()
103 m_Palettes.clear();
104 OUString aPalPaths = SvtPathOptions().GetPalettePath();
106 std::stack<OUString> aDirs;
107 sal_Int32 nIndex = 0;
110 aDirs.push(aPalPaths.getToken(0, ';', nIndex));
112 while (nIndex >= 0);
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())
119 OUString aPalPath = aDirs.top();
120 aDirs.pop();
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 )
129 while( aDir.getNextItem(aDirItem) == osl::FileBase::E_None )
131 aDirItem.getFileStatus(aFileStat);
132 if(aFileStat.isRegular() || aFileStat.isLink())
134 OUString aFName = aFileStat.getFileName();
135 INetURLObject aURLObj( aFileStat.getFileURL() );
136 OUString aFNameWithoutExt = aURLObj.GetBase();
137 if (aNames.find(aFName) == aNames.end())
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));
147 if( pPalette && pPalette->IsValid() )
148 m_Palettes.push_back( std::move(pPalette) );
149 aNames.insert(aFNameWithoutExt);
157 bool PaletteManager::IsThemePaletteSelected() const
159 return mnCurrentPalette == mnNumOfPalettes - 2;
162 bool PaletteManager::GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& rThemeIndex, sal_uInt16& rEffectIndex)
164 // tdf#157034, nItemId begins with 1 but list of themes begin with 0
165 // so decrement nItemId
166 --nItemId;
168 // Each column is the same color with different effects.
169 rThemeIndex = nItemId % 12;
171 rEffectIndex = nItemId / 12;
172 if (rEffectIndex > 5)
173 return false;
174 return true;
177 bool PaletteManager::GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16& rLumMod, sal_Int16& rLumOff)
179 if (!moThemePaletteCollection)
180 return false;
182 auto const& aThemeColorData = moThemePaletteCollection->maColors[nThemeIndex];
184 rLumMod = aThemeColorData.getLumMod(nEffect);
185 rLumOff = aThemeColorData.getLumOff(nEffect);
187 return true;
190 void PaletteManager::ReloadColorSet(SvxColorValueSet &rColorSet)
192 moThemePaletteCollection.reset();
193 if( mnCurrentPalette == 0)
195 rColorSet.Clear();
196 css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() );
197 css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() );
198 int nIx = 1;
199 for (int i = 0; i < CustomColorList.getLength(); ++i)
201 Color aColor(ColorTransparency, CustomColorList[i]);
202 rColorSet.InsertItem(nIx, aColor, CustomColorNameList[i]);
203 ++nIx;
206 else if (IsThemePaletteSelected())
208 SfxObjectShell* pObjectShell = SfxObjectShell::Current();
209 if (pObjectShell)
211 auto pColorSet = pObjectShell->GetThemeColors();
212 mnColorCount = 12;
213 rColorSet.Clear();
214 sal_uInt16 nItemId = 1;
216 if (!pColorSet)
217 return;
219 svx::ThemeColorPaletteManager aThemeColorManager(pColorSet);
220 moThemePaletteCollection = aThemeColorManager.generate();
222 // Each row is one effect type (no effect + each type).
223 for (size_t nEffect : {0, 1, 2, 3, 4, 5})
225 // Each column is one color type.
226 for (auto const& rColorData : moThemePaletteCollection->maColors)
228 auto const& rEffect = rColorData.maEffects[nEffect];
229 rColorSet.InsertItem(nItemId++, rEffect.maColor, rEffect.maColorName);
234 else if( mnCurrentPalette == mnNumOfPalettes - 1 )
236 // Add doc colors to palette
237 SfxObjectShell* pDocSh = SfxObjectShell::Current();
238 if (pDocSh)
240 std::set<Color> aColors = pDocSh->GetDocColors();
241 mnColorCount = aColors.size();
242 rColorSet.Clear();
243 rColorSet.addEntriesForColorSet(aColors, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " ") );
246 else
248 m_Palettes[mnCurrentPalette - 1]->LoadColorSet( rColorSet );
249 mnColorCount = rColorSet.GetItemCount();
253 void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet)
255 maRecentColors.clear();
256 rColorSet.Clear();
257 css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get());
258 css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get());
259 int nIx = 1;
260 const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength();
261 for (int i = 0; i < Colorlist.getLength(); ++i)
263 Color aColor(ColorTransparency, Colorlist[i]);
264 OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase());
265 maRecentColors.emplace_back(aColor, sColorName);
266 rColorSet.InsertItem(nIx, aColor, sColorName);
267 ++nIx;
271 std::vector<OUString> PaletteManager::GetPaletteList()
273 std::vector<OUString> aPaletteNames
275 SvxResId( RID_SVXSTR_CUSTOM_PAL )
277 for (auto const& it : m_Palettes)
279 aPaletteNames.push_back( (*it).GetName() );
281 aPaletteNames.push_back(SvxResId(RID_SVXSTR_THEME_COLORS));
282 aPaletteNames.push_back( SvxResId ( RID_SVXSTR_DOC_COLORS ) );
284 return aPaletteNames;
287 void PaletteManager::SetPalette( sal_Int32 nPos )
289 mnCurrentPalette = nPos;
290 if( nPos != mnNumOfPalettes - 1 && nPos != 0)
292 pColorList = XPropertyList::AsColorList(
293 XPropertyList::CreatePropertyListFromURL(
294 XPropertyListType::Color, GetSelectedPalettePath()));
295 auto name = GetPaletteName(); // may change pColorList
296 pColorList->SetName(name);
297 if(pColorList->Load())
299 SfxObjectShell* pShell = SfxObjectShell::Current();
300 if (pShell != nullptr)
302 SvxColorListItem aColorItem(pColorList, SID_COLOR_TABLE);
303 pShell->PutItem( aColorItem );
307 OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
308 if (aPaletteName != GetPaletteName())
310 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
311 officecfg::Office::Common::UserColors::PaletteName::set(GetPaletteName(), batch);
312 batch->commit();
316 sal_Int32 PaletteManager::GetPalette() const
318 return mnCurrentPalette;
321 OUString PaletteManager::GetPaletteName()
323 std::vector<OUString> aNames(GetPaletteList());
324 if(mnCurrentPalette != mnNumOfPalettes - 1 && mnCurrentPalette != 0)
326 SfxObjectShell* pDocSh = SfxObjectShell::Current();
327 if(pDocSh)
329 const SfxPoolItem* pItem = nullptr;
330 if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
331 pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
334 return aNames[mnCurrentPalette];
337 OUString PaletteManager::GetSelectedPalettePath()
339 if (mnCurrentPalette < m_Palettes.size() && mnCurrentPalette != 0)
340 return m_Palettes[mnCurrentPalette - 1]->GetPath();
341 else
342 return OUString();
345 tools::Long PaletteManager::GetColorCount() const
347 return mnColorCount;
350 tools::Long PaletteManager::GetRecentColorCount() const
352 return maRecentColors.size();
355 void PaletteManager::AddRecentColor(const Color& rRecentColor, const OUString& rName, bool bFront)
357 auto itColor = std::find_if(maRecentColors.begin(),
358 maRecentColors.end(),
359 [rRecentColor] (const NamedColor &aColor) { return aColor.m_aColor == rRecentColor; });
360 // if recent color to be added is already in list, remove it
361 if( itColor != maRecentColors.end() )
362 maRecentColors.erase( itColor );
364 if (maRecentColors.size() == mnMaxRecentColors)
365 maRecentColors.pop_back();
366 if (bFront)
367 maRecentColors.emplace_front(rRecentColor, rName);
368 else
369 maRecentColors.emplace_back(rRecentColor, rName);
370 css::uno::Sequence< sal_Int32 > aColorList(maRecentColors.size());
371 auto aColorListRange = asNonConstRange(aColorList);
372 css::uno::Sequence< OUString > aColorNameList(maRecentColors.size());
373 auto aColorNameListRange = asNonConstRange(aColorNameList);
374 for (size_t i = 0; i < maRecentColors.size(); ++i)
376 aColorListRange[i] = static_cast<sal_Int32>(maRecentColors[i].m_aColor);
377 aColorNameListRange[i] = maRecentColors[i].m_aName;
379 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
380 officecfg::Office::Common::UserColors::RecentColor::set(aColorList, batch);
381 officecfg::Office::Common::UserColors::RecentColorName::set(aColorNameList, batch);
382 batch->commit();
385 void PaletteManager::SetSplitButtonColor(const NamedColor& rColor)
387 if (mpBtnUpdater)
388 mpBtnUpdater->SetRecentColor(rColor);
391 void PaletteManager::SetBtnUpdater(svx::ToolboxButtonColorUpdaterBase* pBtnUpdater)
393 mpBtnUpdater = pBtnUpdater;
396 void PaletteManager::SetColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
398 maColorSelectFunction = aColorSelectFunction;
401 void PaletteManager::PopupColorPicker(weld::Window* pParent, const OUString& aCommand, const Color& rInitialColor)
403 // The calling object goes away during aColorDlg.Execute(), so we must copy this
404 OUString aCommandCopy = aCommand;
405 m_pColorDlg = std::make_unique<SvColorDialog>();
406 m_pColorDlg->SetColor(rInitialColor);
407 m_pColorDlg->SetMode(svtools::ColorPickerMode::Modify);
408 m_pColorDlg->ExecuteAsync(pParent, [this, aCommandCopy] (sal_Int32 nResult) {
409 if (nResult == RET_OK)
411 Color aLastColor = m_pColorDlg->GetColor();
412 OUString sColorName = "#" + aLastColor.AsRGBHexString().toAsciiUpperCase();
413 NamedColor aNamedColor(aLastColor, sColorName);
414 SetSplitButtonColor(aNamedColor);
415 AddRecentColor(aLastColor, sColorName);
416 maColorSelectFunction(aCommandCopy, aNamedColor);
421 void PaletteManager::DispatchColorCommand(const OUString& aCommand, const NamedColor& rColor)
423 using namespace css;
424 using namespace css::uno;
425 using namespace css::frame;
426 using namespace css::beans;
427 using namespace css::util;
429 Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
430 Reference<XDesktop2> xDesktop = Desktop::create(xContext);
431 Reference<XFrame> xFrame(xDesktop->getCurrentFrame());
432 Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY);
433 if (!xDispatchProvider.is())
434 return;
436 INetURLObject aObj( aCommand );
438 std::vector<PropertyValue> aArgs{
439 comphelper::makePropertyValue(aObj.GetURLPath()+ ".Color", sal_Int32(rColor.m_aColor)),
442 if (rColor.m_nThemeIndex != -1)
444 model::ComplexColor aComplexColor;
445 aComplexColor.setSchemeColor(model::convertToThemeColorType(rColor.m_nThemeIndex));
446 if (rColor.m_nLumMod != 10000)
447 aComplexColor.addTransformation({model::TransformationType::LumMod, rColor.m_nLumMod});
448 if (rColor.m_nLumMod != 0)
449 aComplexColor.addTransformation({model::TransformationType::LumOff, rColor.m_nLumOff});
451 uno::Any aAny;
452 aAny <<= OStringToOUString(model::color::convertToJSON(aComplexColor), RTL_TEXTENCODING_UTF8);
454 aArgs.push_back(comphelper::makePropertyValue(aObj.GetURLPath() + ".ComplexColorJSON", aAny));
457 URL aTargetURL;
458 aTargetURL.Complete = aCommand;
459 Reference<XURLTransformer> xURLTransformer(URLTransformer::create(comphelper::getProcessComponentContext()));
460 xURLTransformer->parseStrict(aTargetURL);
462 Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0);
463 if (xDispatch.is())
465 xDispatch->dispatch(aTargetURL, comphelper::containerToSequence(aArgs));
466 if (xFrame->getContainerWindow().is())
467 xFrame->getContainerWindow()->setFocus();
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */