1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
55 PaletteManager::PaletteManager() :
56 mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
60 mpBtnUpdater(nullptr),
61 maColorSelectFunction(PaletteManager::DispatchColorCommand
)
64 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
67 const SfxPoolItem
* pItem
= nullptr;
68 if( nullptr != ( pItem
= pDocSh
->GetItem(SID_COLOR_TABLE
) ) )
69 pColorList
= static_cast<const SvxColorListItem
*>(pItem
)->GetColorList();
72 pColorList
= XColorList::CreateStdColorList();
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()
104 OUString aPalPaths
= SvtPathOptions().GetPalettePath();
106 std::stack
<OUString
> aDirs
;
107 sal_Int32 nIndex
= 0;
110 aDirs
.push(aPalPaths
.getToken(0, ';', nIndex
));
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();
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
168 // Each column is the same color with different effects.
169 rThemeIndex
= nItemId
% 12;
171 rEffectIndex
= nItemId
/ 12;
172 if (rEffectIndex
> 5)
177 bool PaletteManager::GetLumModOff(sal_uInt16 nThemeIndex
, sal_uInt16 nEffect
, sal_Int16
& rLumMod
, sal_Int16
& rLumOff
)
179 if (!moThemePaletteCollection
)
182 auto const& aThemeColorData
= moThemePaletteCollection
->maColors
[nThemeIndex
];
184 rLumMod
= aThemeColorData
.getLumMod(nEffect
);
185 rLumOff
= aThemeColorData
.getLumOff(nEffect
);
190 void PaletteManager::ReloadColorSet(SvxColorValueSet
&rColorSet
)
192 moThemePaletteCollection
.reset();
193 if( mnCurrentPalette
== 0)
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() );
199 for (int i
= 0; i
< CustomColorList
.getLength(); ++i
)
201 Color
aColor(ColorTransparency
, CustomColorList
[i
]);
202 rColorSet
.InsertItem(nIx
, aColor
, CustomColorNameList
[i
]);
206 else if (IsThemePaletteSelected())
208 SfxObjectShell
* pObjectShell
= SfxObjectShell::Current();
211 auto pColorSet
= pObjectShell
->GetThemeColors();
214 sal_uInt16 nItemId
= 1;
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();
240 std::set
<Color
> aColors
= pDocSh
->GetDocColors();
241 mnColorCount
= aColors
.size();
243 rColorSet
.addEntriesForColorSet(aColors
, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX
) + " ") );
248 m_Palettes
[mnCurrentPalette
- 1]->LoadColorSet( rColorSet
);
249 mnColorCount
= rColorSet
.GetItemCount();
253 void PaletteManager::ReloadRecentColorSet(SvxColorValueSet
& rColorSet
)
255 maRecentColors
.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());
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
);
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
);
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();
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();
345 tools::Long
PaletteManager::GetColorCount() const
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();
367 maRecentColors
.emplace_front(rRecentColor
, rName
);
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
);
385 void PaletteManager::SetSplitButtonColor(const NamedColor
& rColor
)
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
)
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())
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
});
452 aAny
<<= OStringToOUString(model::color::convertToJSON(aComplexColor
), RTL_TEXTENCODING_UTF8
);
454 aArgs
.push_back(comphelper::makePropertyValue(aObj
.GetURLPath() + ".ComplexColorJSON", aAny
));
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);
465 xDispatch
->dispatch(aTargetURL
, comphelper::containerToSequence(aArgs
));
466 if (xFrame
->getContainerWindow().is())
467 xFrame
->getContainerWindow()->setFocus();
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */