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 <sal/config.h>
24 #include <svtools/extcolorcfg.hxx>
25 #include <com/sun/star/uno/Any.hxx>
26 #include <com/sun/star/uno/Sequence.hxx>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <tools/color.hxx>
29 #include <unotools/configitem.hxx>
30 #include <com/sun/star/uno/Sequence.h>
31 #include <comphelper/sequence.hxx>
32 #include <svl/hint.hxx>
33 #include <osl/mutex.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
37 #include <vcl/svapp.hxx>
38 #include <vcl/settings.hxx>
39 #include <vcl/event.hxx>
40 #include <rtl/instance.hxx>
44 using namespace com::sun::star
;
50 static sal_Int32 nExtendedColorRefCount_Impl
= 0;
53 struct ColorMutex_Impl
54 : public rtl::Static
< ::osl::Mutex
, ColorMutex_Impl
> {};
57 ExtendedColorConfig_Impl
* ExtendedColorConfig::m_pImpl
= nullptr;
59 class ExtendedColorConfig_Impl
: public utl::ConfigItem
, public SfxBroadcaster
61 typedef std::map
<OUString
, OUString
> TDisplayNames
;
62 typedef std::map
<OUString
, ExtendedColorConfigValue
> TConfigValues
;
63 typedef ::std::vector
<TConfigValues::iterator
> TMapPos
;
64 typedef ::std::pair
< TConfigValues
, TMapPos
> TComponentMapping
;
65 typedef std::map
<OUString
, TComponentMapping
> TComponents
;
66 TComponents m_aConfigValues
;
67 TDisplayNames m_aComponentDisplayNames
;
68 ::std::vector
<TComponents::iterator
> m_aConfigValuesPos
;
70 OUString m_sLoadedScheme
;
71 bool m_bIsBroadcastEnabled
;
72 static bool m_bLockBroadcast
;
73 static bool m_bBroadcastWhenUnlocked
;
75 uno::Sequence
< OUString
> GetPropertyNames(const OUString
& rScheme
);
76 void FillComponentColors(const uno::Sequence
< OUString
>& _rComponents
,const TDisplayNames
& _rDisplayNames
);
78 virtual void ImplCommit() override
;
81 explicit ExtendedColorConfig_Impl();
82 virtual ~ExtendedColorConfig_Impl() override
;
84 void Load(const OUString
& rScheme
);
85 void CommitCurrentSchemeName();
86 //changes the name of the current scheme but doesn't load it!
87 void SetCurrentSchemeName(const OUString
& rSchemeName
) {m_sLoadedScheme
= rSchemeName
;}
88 bool ExistsScheme(const OUString
& _sSchemeName
);
89 virtual void Notify( const uno::Sequence
<OUString
>& aPropertyNames
) override
;
91 sal_Int32
GetComponentCount() const;
92 OUString
GetComponentName(sal_uInt32 _nPos
) const;
93 OUString
GetComponentDisplayName(const OUString
& _sComponentName
) const;
94 sal_Int32
GetComponentColorCount(const OUString
& _sName
) const;
95 ExtendedColorConfigValue
GetComponentColorConfigValue(const OUString
& _sName
,sal_uInt32 _nPos
) const;
97 ExtendedColorConfigValue
GetColorConfigValue(const OUString
& _sComponentName
,const OUString
& _sName
)
99 TComponents::iterator aFind
= m_aConfigValues
.find(_sComponentName
);
100 if ( aFind
!= m_aConfigValues
.end() )
102 TConfigValues::iterator aFind2
= aFind
->second
.first
.find(_sName
);
103 if ( aFind2
!= aFind
->second
.first
.end() )
104 return aFind2
->second
;
106 #if OSL_DEBUG_LEVEL > 0
107 SAL_WARN( "svtools", "Could find the required config:\n"
108 "component: " << _sComponentName
109 << "\nname: " << _sName
);
111 return ExtendedColorConfigValue();
113 void SetColorConfigValue(const OUString
& _sName
,
114 const ExtendedColorConfigValue
& rValue
);
116 void AddScheme(const OUString
& rNode
);
117 void RemoveScheme(const OUString
& rNode
);
118 using ConfigItem::SetModified
;
119 using ConfigItem::ClearModified
;
120 void SettingsChanged();
122 static void DisableBroadcast();
123 static void EnableBroadcast();
125 static void LockBroadcast();
126 static void UnlockBroadcast();
128 DECL_LINK( DataChangedEventListener
, VclSimpleEvent
&, void );
131 uno::Sequence
< OUString
> ExtendedColorConfig_Impl::GetPropertyNames(const OUString
& rScheme
)
133 uno::Sequence
< OUString
> aNames(GetNodeNames(rScheme
));
134 for(OUString
& i
: aNames
)
136 i
= rScheme
+ "/" + i
;
141 sal_Int32
ExtendedColorConfig_Impl::GetComponentCount() const
143 return m_aConfigValues
.size();
146 sal_Int32
ExtendedColorConfig_Impl::GetComponentColorCount(const OUString
& _sName
) const
149 TComponents::const_iterator aFind
= m_aConfigValues
.find(_sName
);
150 if ( aFind
!= m_aConfigValues
.end() )
152 nSize
= aFind
->second
.first
.size();
157 ExtendedColorConfigValue
ExtendedColorConfig_Impl::GetComponentColorConfigValue(const OUString
& _sName
,sal_uInt32 _nPos
) const
159 TComponents::const_iterator aFind
= m_aConfigValues
.find(_sName
);
160 if ( aFind
!= m_aConfigValues
.end() )
162 if ( _nPos
< aFind
->second
.second
.size() )
164 return aFind
->second
.second
[_nPos
]->second
;
167 return ExtendedColorConfigValue();
170 OUString
ExtendedColorConfig_Impl::GetComponentDisplayName(const OUString
& _sComponentName
) const
173 TDisplayNames::const_iterator aFind
= m_aComponentDisplayNames
.find(_sComponentName
);
174 if ( aFind
!= m_aComponentDisplayNames
.end() )
175 sRet
= aFind
->second
;
179 OUString
ExtendedColorConfig_Impl::GetComponentName(sal_uInt32 _nPos
) const
182 if ( _nPos
< m_aConfigValuesPos
.size() )
183 sRet
= m_aConfigValuesPos
[_nPos
]->first
;
187 bool ExtendedColorConfig_Impl::m_bLockBroadcast
= false;
188 bool ExtendedColorConfig_Impl::m_bBroadcastWhenUnlocked
= false;
189 ExtendedColorConfig_Impl::ExtendedColorConfig_Impl() :
190 ConfigItem("Office.ExtendedColorScheme"),
191 m_bIsBroadcastEnabled(true)
193 //try to register on the root node - if possible
194 uno::Sequence
< OUString
> aNames(1);
195 EnableNotification( aNames
);
198 ::Application::AddEventListener( LINK(this, ExtendedColorConfig_Impl
, DataChangedEventListener
) );
202 ExtendedColorConfig_Impl::~ExtendedColorConfig_Impl()
204 ::Application::RemoveEventListener( LINK(this, ExtendedColorConfig_Impl
, DataChangedEventListener
) );
207 void ExtendedColorConfig_Impl::DisableBroadcast()
209 if ( ExtendedColorConfig::m_pImpl
)
210 ExtendedColorConfig::m_pImpl
->m_bIsBroadcastEnabled
= false;
213 void ExtendedColorConfig_Impl::EnableBroadcast()
215 if ( ExtendedColorConfig::m_pImpl
)
216 ExtendedColorConfig::m_pImpl
->m_bIsBroadcastEnabled
= true;
219 static void lcl_addString(uno::Sequence
< OUString
>& _rSeq
,const OUString
& _sAdd
)
221 for(OUString
& i
: _rSeq
)
225 void ExtendedColorConfig_Impl::Load(const OUString
& rScheme
)
227 m_aComponentDisplayNames
.clear();
228 m_aConfigValuesPos
.clear();
229 m_aConfigValues
.clear();
231 // fill display names
232 TDisplayNames aDisplayNameMap
;
233 uno::Sequence
< OUString
> aComponentNames
= GetPropertyNames("EntryNames");
234 OUString
sDisplayName("/DisplayName");
235 for(OUString
& componentName
: aComponentNames
)
237 uno::Sequence
< OUString
> aComponentDisplayNames(1);
238 aComponentDisplayNames
[0] = componentName
+ sDisplayName
;
239 uno::Sequence
< uno::Any
> aComponentDisplayNamesValue
= GetProperties( aComponentDisplayNames
);
240 OUString sComponentDisplayName
;
241 if ( aComponentDisplayNamesValue
.hasElements() && (aComponentDisplayNamesValue
[0] >>= sComponentDisplayName
) )
243 m_aComponentDisplayNames
.emplace(componentName
.getToken(1, '/'),sComponentDisplayName
);
246 componentName
+= "/Entries";
247 uno::Sequence
< OUString
> aDisplayNames
= GetPropertyNames(componentName
);
248 lcl_addString(aDisplayNames
,sDisplayName
);
250 uno::Sequence
< uno::Any
> aDisplayNamesValue
= GetProperties( aDisplayNames
);
252 const OUString
* pDispIter
= aDisplayNames
.getConstArray();
253 const OUString
* pDispEnd
= pDispIter
+ aDisplayNames
.getLength();
254 for(sal_Int32 j
= 0;pDispIter
!= pDispEnd
;++pDispIter
,++j
)
256 sal_Int32 nIndex
= 0;
257 pDispIter
->getToken(0,'/',nIndex
);
258 OUString sName
= pDispIter
->copy(nIndex
);
259 sName
= sName
.copy(0,sName
.lastIndexOf(sDisplayName
));
260 OUString sCurrentDisplayName
;
261 aDisplayNamesValue
[j
] >>= sCurrentDisplayName
;
262 aDisplayNameMap
.emplace(sName
,sCurrentDisplayName
);
266 // load color settings
267 OUString
sScheme(rScheme
);
269 if(sScheme
.isEmpty())
271 //detect current scheme name
272 uno::Sequence
< OUString
> aCurrent
{ "ExtendedColorScheme/CurrentColorScheme" };
273 uno::Sequence
< uno::Any
> aCurrentVal
= GetProperties( aCurrent
);
274 aCurrentVal
.getConstArray()[0] >>= sScheme
;
275 } // if(!sScheme.getLength())
277 m_sLoadedScheme
= sScheme
;
278 OUString sBase
= "ExtendedColorScheme/ColorSchemes/"
281 bool bFound
= ExistsScheme(sScheme
);
284 aComponentNames
= GetPropertyNames(sBase
);
285 FillComponentColors(aComponentNames
,aDisplayNameMap
);
288 if ( m_sLoadedScheme
.isEmpty() )
289 m_sLoadedScheme
= "default";
291 if ( sScheme
!= "default" )
293 if ( ExistsScheme("default") )
295 aComponentNames
= GetPropertyNames("ExtendedColorScheme/ColorSchemes/default");
296 FillComponentColors(aComponentNames
,aDisplayNameMap
);
299 if ( !bFound
&& !sScheme
.isEmpty() )
302 CommitCurrentSchemeName();
306 void ExtendedColorConfig_Impl::FillComponentColors(const uno::Sequence
< OUString
>& _rComponents
,const TDisplayNames
& _rDisplayNames
)
308 const OUString
sColorEntries("/Entries");
309 for(OUString
const & component
: _rComponents
)
311 OUString sComponentName
= component
.copy(component
.lastIndexOf('/')+1);
312 if ( m_aConfigValues
.find(sComponentName
) == m_aConfigValues
.end() )
314 OUString sEntry
= component
+ sColorEntries
;
316 uno::Sequence
< OUString
> aColorNames
= GetPropertyNames(sEntry
);
317 uno::Sequence
< OUString
> aDefaultColorNames
= aColorNames
;
319 const OUString
sColor("/Color");
320 lcl_addString(aColorNames
,sColor
);
321 lcl_addString(aDefaultColorNames
,"/DefaultColor");
322 uno::Sequence
< uno::Any
> aColors
= GetProperties( aColorNames
);
323 const uno::Any
* pColors
= aColors
.getConstArray();
325 uno::Sequence
< uno::Any
> aDefaultColors
= GetProperties( aDefaultColorNames
);
326 bool bDefaultColorFound
= aDefaultColors
.hasElements();
327 const uno::Any
* pDefaultColors
= aDefaultColors
.getConstArray();
329 OUString
* pColorIter
= aColorNames
.getArray();
330 OUString
* pColorEnd
= pColorIter
+ aColorNames
.getLength();
332 m_aConfigValuesPos
.push_back(m_aConfigValues
.emplace(sComponentName
,TComponentMapping(TConfigValues(),TMapPos())).first
);
333 TConfigValues
& aConfigValues
= (*m_aConfigValuesPos
.rbegin())->second
.first
;
334 TMapPos
& aConfigValuesPos
= (*m_aConfigValuesPos
.rbegin())->second
.second
;
335 for(int i
= 0; pColorIter
!= pColorEnd
; ++pColorIter
,++i
)
337 if ( aConfigValues
.find(*pColorIter
) == aConfigValues
.end() )
339 sal_Int32 nIndex
= 0;
340 pColorIter
->getToken(2,'/',nIndex
);
341 OUString
sName(pColorIter
->copy(nIndex
)),sDisplayName
;
342 OUString sTemp
= sName
.copy(0,sName
.lastIndexOf(sColor
));
344 TDisplayNames::const_iterator aFind
= _rDisplayNames
.find(sTemp
);
345 sName
= sName
.getToken(2, '/');
346 OSL_ENSURE(aFind
!= _rDisplayNames
.end(),"DisplayName is not in EntryNames config list!");
347 if ( aFind
!= _rDisplayNames
.end() )
348 sDisplayName
= aFind
->second
;
350 OSL_ENSURE(pColors
[i
].hasValue(),"Color config entry has NIL as color value set!");
351 OSL_ENSURE(pDefaultColors
[i
].hasValue(),"Color config entry has NIL as color value set!");
352 Color nColor
, nDefaultColor
;
353 pColors
[i
] >>= nColor
;
354 if ( bDefaultColorFound
)
355 pDefaultColors
[i
] >>= nDefaultColor
;
357 nDefaultColor
= nColor
;
358 ExtendedColorConfigValue
aValue(sName
,sDisplayName
,nColor
,nDefaultColor
);
359 aConfigValuesPos
.push_back(aConfigValues
.emplace(sName
,aValue
).first
);
361 } // for(int i = 0; pColorIter != pColorEnd; ++pColorIter ,++i)
366 void ExtendedColorConfig_Impl::Notify( const uno::Sequence
<OUString
>& /*rPropertyNames*/)
368 //loading via notification always uses the default setting
371 SolarMutexGuard aVclGuard
;
375 m_bBroadcastWhenUnlocked
= true;
378 Broadcast(SfxHint(SfxHintId::ColorsChanged
));
381 void ExtendedColorConfig_Impl::ImplCommit()
383 if ( m_sLoadedScheme
.isEmpty() )
385 const OUString
sColorEntries("Entries");
386 const OUString
sColor("/Color");
387 OUString sBase
= "ExtendedColorScheme/ColorSchemes/"
389 const OUString
s_sSep("/");
391 for (auto const& configValue
: m_aConfigValues
)
393 if ( ConfigItem::AddNode(sBase
, configValue
.first
) )
395 OUString sNode
= sBase
398 //ConfigItem::AddNode(sNode, sColorEntries);
402 uno::Sequence
< beans::PropertyValue
> aPropValues(configValue
.second
.first
.size());
403 beans::PropertyValue
* pPropValues
= aPropValues
.getArray();
404 for (auto const& elem
: configValue
.second
.first
)
406 pPropValues
->Name
= sNode
+ s_sSep
+ elem
.first
;
407 ConfigItem::AddNode(sNode
, elem
.first
);
408 pPropValues
->Name
+= sColor
;
409 pPropValues
->Value
<<= elem
.second
.getColor();
410 // the default color will never be changed
413 SetSetProperties("ExtendedColorScheme/ColorSchemes", aPropValues
);
417 CommitCurrentSchemeName();
420 void ExtendedColorConfig_Impl::CommitCurrentSchemeName()
422 //save current scheme name
423 uno::Sequence
< OUString
> aCurrent
{ "ExtendedColorScheme/CurrentColorScheme" };
424 uno::Sequence
< uno::Any
> aCurrentVal(1);
425 aCurrentVal
.getArray()[0] <<= m_sLoadedScheme
;
426 PutProperties(aCurrent
, aCurrentVal
);
429 bool ExtendedColorConfig_Impl::ExistsScheme(const OUString
& _sSchemeName
)
431 OUString
sBase("ExtendedColorScheme/ColorSchemes");
433 uno::Sequence
< OUString
> aComponentNames
= GetPropertyNames(sBase
);
434 sBase
+= "/" + _sSchemeName
;
435 return comphelper::findValue(aComponentNames
, sBase
) != -1;
438 void ExtendedColorConfig_Impl::SetColorConfigValue(const OUString
& _sName
, const ExtendedColorConfigValue
& rValue
)
440 TComponents::iterator aFind
= m_aConfigValues
.find(_sName
);
441 if ( aFind
!= m_aConfigValues
.end() )
443 TConfigValues::iterator aFind2
= aFind
->second
.first
.find(rValue
.getName());
444 if ( aFind2
!= aFind
->second
.first
.end() )
445 aFind2
->second
= rValue
;
450 void ExtendedColorConfig_Impl::AddScheme(const OUString
& rScheme
)
452 if(ConfigItem::AddNode("ExtendedColorScheme/ColorSchemes", rScheme
))
454 m_sLoadedScheme
= rScheme
;
459 void ExtendedColorConfig_Impl::RemoveScheme(const OUString
& rScheme
)
461 uno::Sequence
< OUString
> aElements
{ rScheme
};
462 ClearNodeElements("ExtendedColorScheme/ColorSchemes", aElements
);
465 void ExtendedColorConfig_Impl::SettingsChanged()
467 SolarMutexGuard aVclGuard
;
469 Broadcast( SfxHint( SfxHintId::ColorsChanged
) );
472 void ExtendedColorConfig_Impl::LockBroadcast()
474 m_bLockBroadcast
= true;
477 void ExtendedColorConfig_Impl::UnlockBroadcast()
479 if ( m_bBroadcastWhenUnlocked
)
481 m_bBroadcastWhenUnlocked
= ExtendedColorConfig::m_pImpl
!= nullptr;
482 if ( m_bBroadcastWhenUnlocked
)
484 if (ExtendedColorConfig::m_pImpl
->m_bIsBroadcastEnabled
)
486 m_bBroadcastWhenUnlocked
= false;
487 ExtendedColorConfig::m_pImpl
->Broadcast(SfxHint(SfxHintId::ColorsChanged
));
491 m_bLockBroadcast
= false;
494 IMPL_LINK( ExtendedColorConfig_Impl
, DataChangedEventListener
, VclSimpleEvent
&, rEvent
, void )
496 if ( rEvent
.GetId() == VclEventId::ApplicationDataChanged
)
498 DataChangedEvent
* pData
= static_cast<DataChangedEvent
*>(static_cast<VclWindowEvent
&>(rEvent
).GetData());
499 if ( (pData
->GetType() == DataChangedEventType::SETTINGS
) &&
500 (pData
->GetFlags() & AllSettingsFlags::STYLE
) )
508 ExtendedColorConfig::ExtendedColorConfig()
510 ::osl::MutexGuard
aGuard( ColorMutex_Impl::get() );
512 m_pImpl
= new ExtendedColorConfig_Impl
;
513 ++nExtendedColorRefCount_Impl
;
514 StartListening( *m_pImpl
);
517 ExtendedColorConfig::~ExtendedColorConfig()
519 ::osl::MutexGuard
aGuard( ColorMutex_Impl::get() );
520 EndListening( *m_pImpl
);
521 if(!--nExtendedColorRefCount_Impl
)
528 ExtendedColorConfigValue
ExtendedColorConfig::GetColorValue(const OUString
& _sComponentName
,const OUString
& _sName
)const
530 return m_pImpl
->GetColorConfigValue(_sComponentName
,_sName
);
533 sal_Int32
ExtendedColorConfig::GetComponentCount() const
535 return m_pImpl
->GetComponentCount();
538 sal_Int32
ExtendedColorConfig::GetComponentColorCount(const OUString
& _sName
) const
540 return m_pImpl
->GetComponentColorCount(_sName
);
543 ExtendedColorConfigValue
ExtendedColorConfig::GetComponentColorConfigValue(const OUString
& _sName
,sal_uInt32 _nPos
) const
545 return m_pImpl
->GetComponentColorConfigValue(_sName
,_nPos
);
548 OUString
ExtendedColorConfig::GetComponentName(sal_uInt32 _nPos
) const
550 return m_pImpl
->GetComponentName(_nPos
);
553 OUString
ExtendedColorConfig::GetComponentDisplayName(const OUString
& _sComponentName
) const
555 return m_pImpl
->GetComponentDisplayName(_sComponentName
);
558 void ExtendedColorConfig::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
560 SolarMutexGuard aVclGuard
;
565 EditableExtendedColorConfig::EditableExtendedColorConfig() :
566 m_pImpl(new ExtendedColorConfig_Impl
),
569 ExtendedColorConfig_Impl::LockBroadcast();
572 EditableExtendedColorConfig::~EditableExtendedColorConfig()
574 ExtendedColorConfig_Impl::UnlockBroadcast();
576 m_pImpl
->SetModified();
577 if(m_pImpl
->IsModified())
581 void EditableExtendedColorConfig::DeleteScheme(const OUString
& rScheme
)
583 m_pImpl
->RemoveScheme(rScheme
);
586 void EditableExtendedColorConfig::AddScheme(const OUString
& rScheme
)
588 m_pImpl
->AddScheme(rScheme
);
591 void EditableExtendedColorConfig::LoadScheme(const OUString
& rScheme
)
594 m_pImpl
->SetModified();
595 if(m_pImpl
->IsModified())
598 m_pImpl
->Load(rScheme
);
599 //the name of the loaded scheme has to be committed separately
600 m_pImpl
->CommitCurrentSchemeName();
603 // Changes the name of the current scheme but doesn't load it!
604 void EditableExtendedColorConfig::SetCurrentSchemeName(const OUString
& rScheme
)
606 m_pImpl
->SetCurrentSchemeName(rScheme
);
607 m_pImpl
->CommitCurrentSchemeName();
610 void EditableExtendedColorConfig::SetColorValue(
611 const OUString
& _sName
, const ExtendedColorConfigValue
& rValue
)
613 m_pImpl
->SetColorConfigValue(_sName
, rValue
);
614 m_pImpl
->ClearModified();
618 void EditableExtendedColorConfig::SetModified()
623 void EditableExtendedColorConfig::Commit()
626 m_pImpl
->SetModified();
627 if(m_pImpl
->IsModified())
632 void EditableExtendedColorConfig::DisableBroadcast()
634 ExtendedColorConfig_Impl::DisableBroadcast();
637 void EditableExtendedColorConfig::EnableBroadcast()
639 ExtendedColorConfig_Impl::EnableBroadcast();
642 sal_Int32
EditableExtendedColorConfig::GetComponentCount() const
644 return m_pImpl
->GetComponentCount();
647 sal_Int32
EditableExtendedColorConfig::GetComponentColorCount(const OUString
& _sName
) const
649 return m_pImpl
->GetComponentColorCount(_sName
);
652 ExtendedColorConfigValue
EditableExtendedColorConfig::GetComponentColorConfigValue(const OUString
& _sName
,sal_uInt32 _nPos
) const
654 return m_pImpl
->GetComponentColorConfigValue(_sName
,_nPos
);
657 OUString
EditableExtendedColorConfig::GetComponentName(sal_uInt32 _nPos
) const
659 return m_pImpl
->GetComponentName(_nPos
);
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */