Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / svtools / source / config / extcolorcfg.cxx
blob11a8a0bdca06026e03306e5f1d2138094da578de
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 <sal/config.h>
22 #include <map>
23 #include <string_view>
25 #include <svtools/extcolorcfg.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <tools/color.hxx>
30 #include <unotools/configitem.hxx>
31 #include <com/sun/star/uno/Sequence.h>
32 #include <comphelper/sequence.hxx>
33 #include <svl/hint.hxx>
34 #include <mutex>
35 #include <sal/log.hxx>
36 #include <osl/diagnose.h>
37 #include <o3tl/string_view.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/settings.hxx>
41 #include <vcl/event.hxx>
44 using namespace utl;
45 using namespace com::sun::star;
48 namespace svtools
51 static sal_Int32 nExtendedColorRefCount_Impl = 0;
52 namespace
54 std::mutex& ColorMutex_Impl()
56 static std::mutex SINGLETON;
57 return SINGLETON;
61 ExtendedColorConfig_Impl* ExtendedColorConfig::m_pImpl = nullptr;
63 class ExtendedColorConfig_Impl : public utl::ConfigItem, public SfxBroadcaster
65 typedef std::map<OUString, OUString> TDisplayNames;
66 typedef std::map<OUString, ExtendedColorConfigValue> TConfigValues;
67 typedef ::std::vector<TConfigValues::iterator> TMapPos;
68 typedef ::std::pair< TConfigValues, TMapPos > TComponentMapping;
69 typedef std::map<OUString, TComponentMapping> TComponents;
70 TComponents m_aConfigValues;
71 TDisplayNames m_aComponentDisplayNames;
72 ::std::vector<TComponents::iterator> m_aConfigValuesPos;
74 OUString m_sLoadedScheme;
75 bool m_bIsBroadcastEnabled;
76 static bool m_bLockBroadcast;
77 static bool m_bBroadcastWhenUnlocked;
79 uno::Sequence< OUString> GetPropertyNames(const OUString& rScheme);
80 void FillComponentColors(const uno::Sequence < OUString >& _rComponents,const TDisplayNames& _rDisplayNames);
82 virtual void ImplCommit() override;
84 public:
85 explicit ExtendedColorConfig_Impl();
86 virtual ~ExtendedColorConfig_Impl() override;
88 void Load(const OUString& rScheme);
89 void CommitCurrentSchemeName();
90 //changes the name of the current scheme but doesn't load it!
91 void SetCurrentSchemeName(const OUString& rSchemeName) {m_sLoadedScheme = rSchemeName;}
92 bool ExistsScheme(std::u16string_view _sSchemeName);
93 virtual void Notify( const uno::Sequence<OUString>& aPropertyNames) override;
95 sal_Int32 GetComponentCount() const;
96 OUString GetComponentName(sal_uInt32 _nPos) const;
97 OUString GetComponentDisplayName(const OUString& _sComponentName) const;
98 sal_Int32 GetComponentColorCount(const OUString& _sName) const;
99 ExtendedColorConfigValue GetComponentColorConfigValue(const OUString& _sName,sal_uInt32 _nPos) const;
101 ExtendedColorConfigValue GetColorConfigValue(const OUString& _sComponentName,const OUString& _sName)
103 TComponents::iterator aFind = m_aConfigValues.find(_sComponentName);
104 if ( aFind != m_aConfigValues.end() )
106 TConfigValues::iterator aFind2 = aFind->second.first.find(_sName);
107 if ( aFind2 != aFind->second.first.end() )
108 return aFind2->second;
110 #if OSL_DEBUG_LEVEL > 0
111 SAL_WARN( "svtools", "Could find the required config:\n"
112 "component: " << _sComponentName
113 << "\nname: " << _sName );
114 #endif
115 return ExtendedColorConfigValue();
117 void SetColorConfigValue(const OUString& _sName,
118 const ExtendedColorConfigValue& rValue );
120 void AddScheme(const OUString& rNode);
121 void RemoveScheme(const OUString& rNode);
122 using ConfigItem::SetModified;
123 using ConfigItem::ClearModified;
124 void SettingsChanged();
126 static void DisableBroadcast();
127 static void EnableBroadcast();
129 static void LockBroadcast();
130 static void UnlockBroadcast();
132 DECL_LINK( DataChangedEventListener, VclSimpleEvent&, void );
135 uno::Sequence< OUString> ExtendedColorConfig_Impl::GetPropertyNames(const OUString& rScheme)
137 uno::Sequence< OUString> aNames(GetNodeNames(rScheme));
138 for(OUString & i : asNonConstRange(aNames))
140 i = rScheme + "/" + i;
142 return aNames;
145 sal_Int32 ExtendedColorConfig_Impl::GetComponentCount() const
147 return m_aConfigValues.size();
150 sal_Int32 ExtendedColorConfig_Impl::GetComponentColorCount(const OUString& _sName) const
152 sal_Int32 nSize = 0;
153 TComponents::const_iterator aFind = m_aConfigValues.find(_sName);
154 if ( aFind != m_aConfigValues.end() )
156 nSize = aFind->second.first.size();
158 return nSize;
161 ExtendedColorConfigValue ExtendedColorConfig_Impl::GetComponentColorConfigValue(const OUString& _sName,sal_uInt32 _nPos) const
163 TComponents::const_iterator aFind = m_aConfigValues.find(_sName);
164 if ( aFind != m_aConfigValues.end() )
166 if ( _nPos < aFind->second.second.size() )
168 return aFind->second.second[_nPos]->second;
171 return ExtendedColorConfigValue();
174 OUString ExtendedColorConfig_Impl::GetComponentDisplayName(const OUString& _sComponentName) const
176 OUString sRet;
177 TDisplayNames::const_iterator aFind = m_aComponentDisplayNames.find(_sComponentName);
178 if ( aFind != m_aComponentDisplayNames.end() )
179 sRet = aFind->second;
180 return sRet;
183 OUString ExtendedColorConfig_Impl::GetComponentName(sal_uInt32 _nPos) const
185 OUString sRet;
186 if ( _nPos < m_aConfigValuesPos.size() )
187 sRet = m_aConfigValuesPos[_nPos]->first;
188 return sRet;
191 bool ExtendedColorConfig_Impl::m_bLockBroadcast = false;
192 bool ExtendedColorConfig_Impl::m_bBroadcastWhenUnlocked = false;
193 ExtendedColorConfig_Impl::ExtendedColorConfig_Impl() :
194 ConfigItem(u"Office.ExtendedColorScheme"_ustr),
195 m_bIsBroadcastEnabled(true)
197 //try to register on the root node - if possible
198 uno::Sequence < OUString > aNames(1);
199 EnableNotification( aNames );
200 Load(OUString());
202 ::Application::AddEventListener( LINK(this, ExtendedColorConfig_Impl, DataChangedEventListener) );
206 ExtendedColorConfig_Impl::~ExtendedColorConfig_Impl()
208 ::Application::RemoveEventListener( LINK(this, ExtendedColorConfig_Impl, DataChangedEventListener) );
211 void ExtendedColorConfig_Impl::DisableBroadcast()
213 if ( ExtendedColorConfig::m_pImpl )
214 ExtendedColorConfig::m_pImpl->m_bIsBroadcastEnabled = false;
217 void ExtendedColorConfig_Impl::EnableBroadcast()
219 if ( ExtendedColorConfig::m_pImpl )
220 ExtendedColorConfig::m_pImpl->m_bIsBroadcastEnabled = true;
223 static void lcl_addString(uno::Sequence < OUString >& _rSeq,std::u16string_view _sAdd)
225 for(OUString & i : asNonConstRange(_rSeq))
226 i += _sAdd;
229 void ExtendedColorConfig_Impl::Load(const OUString& rScheme)
231 m_aComponentDisplayNames.clear();
232 m_aConfigValuesPos.clear();
233 m_aConfigValues.clear();
235 // fill display names
236 TDisplayNames aDisplayNameMap;
237 uno::Sequence < OUString > aComponentNames = GetPropertyNames(u"EntryNames"_ustr);
238 OUString sDisplayName(u"/DisplayName"_ustr);
239 for(OUString & componentName : asNonConstRange(aComponentNames))
241 uno::Sequence< uno::Any > aComponentDisplayNamesValue = GetProperties( { componentName + sDisplayName } );
242 OUString sComponentDisplayName;
243 if ( aComponentDisplayNamesValue.hasElements() && (aComponentDisplayNamesValue[0] >>= sComponentDisplayName) )
245 m_aComponentDisplayNames.emplace(componentName.getToken(1, '/'),sComponentDisplayName);
248 componentName += "/Entries";
249 uno::Sequence < OUString > aDisplayNames = GetPropertyNames(componentName);
250 lcl_addString(aDisplayNames,sDisplayName);
252 uno::Sequence< uno::Any > aDisplayNamesValue = GetProperties( aDisplayNames );
254 const OUString* pDispIter = aDisplayNames.getConstArray();
255 const OUString* pDispEnd = pDispIter + aDisplayNames.getLength();
256 for(sal_Int32 j = 0;pDispIter != pDispEnd;++pDispIter,++j)
258 sal_Int32 nIndex = 0;
259 o3tl::getToken(*pDispIter, 0, '/', nIndex);
260 std::u16string_view sName = pDispIter->subView(nIndex);
261 sName = sName.substr(0, sName.rfind(sDisplayName));
262 OUString sCurrentDisplayName;
263 aDisplayNamesValue[j] >>= sCurrentDisplayName;
264 aDisplayNameMap.emplace(OUString(sName),sCurrentDisplayName);
268 // load color settings
269 OUString sScheme(rScheme);
271 if(sScheme.isEmpty())
273 //detect current scheme name
274 uno::Sequence < OUString > aCurrent { u"ExtendedColorScheme/CurrentColorScheme"_ustr };
275 uno::Sequence< uno::Any > aCurrentVal = GetProperties( aCurrent );
276 aCurrentVal.getConstArray()[0] >>= sScheme;
277 } // if(!sScheme.getLength())
279 m_sLoadedScheme = sScheme;
280 OUString sBase = "ExtendedColorScheme/ColorSchemes/"
281 + sScheme;
283 bool bFound = ExistsScheme(sScheme);
284 if ( bFound )
286 aComponentNames = GetPropertyNames(sBase);
287 FillComponentColors(aComponentNames,aDisplayNameMap);
290 if ( m_sLoadedScheme.isEmpty() )
291 m_sLoadedScheme = "default";
293 if ( sScheme != "default" )
295 if ( ExistsScheme(u"default") )
297 aComponentNames = GetPropertyNames(u"ExtendedColorScheme/ColorSchemes/default"_ustr);
298 FillComponentColors(aComponentNames,aDisplayNameMap);
301 if ( !bFound && !sScheme.isEmpty() )
303 AddScheme(sScheme);
304 CommitCurrentSchemeName();
308 void ExtendedColorConfig_Impl::FillComponentColors(const uno::Sequence < OUString >& _rComponents,const TDisplayNames& _rDisplayNames)
310 static constexpr OUStringLiteral sColorEntries(u"/Entries");
311 for(OUString const & component : _rComponents)
313 OUString sComponentName = component.copy(component.lastIndexOf('/')+1);
314 if ( m_aConfigValues.find(sComponentName) == m_aConfigValues.end() )
316 OUString sEntry = component + sColorEntries;
318 uno::Sequence < OUString > aColorNames = GetPropertyNames(sEntry);
319 uno::Sequence < OUString > aDefaultColorNames = aColorNames;
321 static constexpr OUString sColor(u"/Color"_ustr);
322 lcl_addString(aColorNames,sColor);
323 lcl_addString(aDefaultColorNames,u"/DefaultColor");
324 uno::Sequence< uno::Any > aColors = GetProperties( aColorNames );
325 const uno::Any* pColors = aColors.getConstArray();
327 uno::Sequence< uno::Any > aDefaultColors = GetProperties( aDefaultColorNames );
328 bool bDefaultColorFound = aDefaultColors.hasElements();
329 const uno::Any* pDefaultColors = aDefaultColors.getConstArray();
331 OUString* pColorIter = aColorNames.getArray();
332 OUString* pColorEnd = pColorIter + aColorNames.getLength();
334 m_aConfigValuesPos.push_back(m_aConfigValues.emplace(sComponentName,TComponentMapping(TConfigValues(),TMapPos())).first);
335 TConfigValues& aConfigValues = (*m_aConfigValuesPos.rbegin())->second.first;
336 TMapPos& aConfigValuesPos = (*m_aConfigValuesPos.rbegin())->second.second;
337 for(int i = 0; pColorIter != pColorEnd; ++pColorIter ,++i)
339 if ( aConfigValues.find(*pColorIter) == aConfigValues.end() )
341 sal_Int32 nIndex = 0;
342 o3tl::getToken(*pColorIter, 2, '/', nIndex);
343 OUString sName(pColorIter->copy(nIndex)),sDisplayName;
344 OUString sTemp = sName.copy(0,sName.lastIndexOf(sColor));
346 TDisplayNames::const_iterator aFind = _rDisplayNames.find(sTemp);
347 sName = sName.getToken(2, '/');
348 OSL_ENSURE(aFind != _rDisplayNames.end(),"DisplayName is not in EntryNames config list!");
349 if ( aFind != _rDisplayNames.end() )
350 sDisplayName = aFind->second;
352 OSL_ENSURE(pColors[i].hasValue(),"Color config entry has NIL as color value set!");
353 OSL_ENSURE(pDefaultColors[i].hasValue(),"Color config entry has NIL as color value set!");
354 Color nColor, nDefaultColor;
355 pColors[i] >>= nColor;
356 if ( bDefaultColorFound )
357 pDefaultColors[i] >>= nDefaultColor;
358 else
359 nDefaultColor = nColor;
360 ExtendedColorConfigValue aValue(sName,sDisplayName,nColor,nDefaultColor);
361 aConfigValuesPos.push_back(aConfigValues.emplace(sName,aValue).first);
363 } // for(int i = 0; pColorIter != pColorEnd; ++pColorIter ,++i)
368 void ExtendedColorConfig_Impl::Notify( const uno::Sequence<OUString>& /*rPropertyNames*/)
370 //loading via notification always uses the default setting
371 Load(OUString());
373 SolarMutexGuard aVclGuard;
375 if(m_bLockBroadcast)
377 m_bBroadcastWhenUnlocked = true;
379 else
380 Broadcast(SfxHint(SfxHintId::ColorsChanged));
383 void ExtendedColorConfig_Impl::ImplCommit()
385 if ( m_sLoadedScheme.isEmpty() )
386 return;
387 static constexpr OUStringLiteral sColorEntries(u"Entries");
388 static constexpr OUStringLiteral sColor(u"/Color");
389 OUString sBase = "ExtendedColorScheme/ColorSchemes/"
390 + m_sLoadedScheme;
391 static constexpr OUString s_sSep(u"/"_ustr);
393 for (auto const& configValue : m_aConfigValues)
395 if ( ConfigItem::AddNode(sBase, configValue.first) )
397 OUString sNode = sBase
398 + s_sSep
399 + configValue.first
400 //ConfigItem::AddNode(sNode, sColorEntries);
401 + s_sSep
402 + sColorEntries;
404 uno::Sequence < beans::PropertyValue > aPropValues(configValue.second.first.size());
405 beans::PropertyValue* pPropValues = aPropValues.getArray();
406 for (auto const& elem : configValue.second.first)
408 pPropValues->Name = sNode + s_sSep + elem.first;
409 ConfigItem::AddNode(sNode, elem.first);
410 pPropValues->Name += sColor;
411 pPropValues->Value <<= elem.second.getColor();
412 // the default color will never be changed
413 ++pPropValues;
415 SetSetProperties(u"ExtendedColorScheme/ColorSchemes"_ustr, aPropValues);
419 CommitCurrentSchemeName();
422 void ExtendedColorConfig_Impl::CommitCurrentSchemeName()
424 //save current scheme name
425 uno::Sequence < OUString > aCurrent { u"ExtendedColorScheme/CurrentColorScheme"_ustr };
426 uno::Sequence< uno::Any > aCurrentVal(1);
427 aCurrentVal.getArray()[0] <<= m_sLoadedScheme;
428 PutProperties(aCurrent, aCurrentVal);
431 bool ExtendedColorConfig_Impl::ExistsScheme(std::u16string_view _sSchemeName)
433 OUString sBase(u"ExtendedColorScheme/ColorSchemes"_ustr);
435 uno::Sequence < OUString > aComponentNames = GetPropertyNames(sBase);
436 sBase += OUString::Concat("/") + _sSchemeName;
437 return comphelper::findValue(aComponentNames, sBase) != -1;
440 void ExtendedColorConfig_Impl::SetColorConfigValue(const OUString& _sName, const ExtendedColorConfigValue& rValue )
442 TComponents::iterator aFind = m_aConfigValues.find(_sName);
443 if ( aFind != m_aConfigValues.end() )
445 TConfigValues::iterator aFind2 = aFind->second.first.find(rValue.getName());
446 if ( aFind2 != aFind->second.first.end() )
447 aFind2->second = rValue;
448 SetModified();
452 void ExtendedColorConfig_Impl::AddScheme(const OUString& rScheme)
454 if(ConfigItem::AddNode(u"ExtendedColorScheme/ColorSchemes"_ustr, rScheme))
456 m_sLoadedScheme = rScheme;
457 Commit();
461 void ExtendedColorConfig_Impl::RemoveScheme(const OUString& rScheme)
463 uno::Sequence< OUString > aElements { rScheme };
464 ClearNodeElements(u"ExtendedColorScheme/ColorSchemes"_ustr, aElements);
467 void ExtendedColorConfig_Impl::SettingsChanged()
469 SolarMutexGuard aVclGuard;
471 Broadcast( SfxHint( SfxHintId::ColorsChanged ) );
474 void ExtendedColorConfig_Impl::LockBroadcast()
476 m_bLockBroadcast = true;
479 void ExtendedColorConfig_Impl::UnlockBroadcast()
481 if ( m_bBroadcastWhenUnlocked )
483 m_bBroadcastWhenUnlocked = ExtendedColorConfig::m_pImpl != nullptr;
484 if ( m_bBroadcastWhenUnlocked )
486 if (ExtendedColorConfig::m_pImpl->m_bIsBroadcastEnabled)
488 m_bBroadcastWhenUnlocked = false;
489 ExtendedColorConfig::m_pImpl->Broadcast(SfxHint(SfxHintId::ColorsChanged));
493 m_bLockBroadcast = false;
496 IMPL_LINK( ExtendedColorConfig_Impl, DataChangedEventListener, VclSimpleEvent&, rEvent, void )
498 if ( rEvent.GetId() == VclEventId::ApplicationDataChanged )
500 DataChangedEvent* pData = static_cast<DataChangedEvent*>(static_cast<VclWindowEvent&>(rEvent).GetData());
501 if ( (pData->GetType() == DataChangedEventType::SETTINGS) &&
502 (pData->GetFlags() & AllSettingsFlags::STYLE) )
504 SettingsChanged();
510 ExtendedColorConfig::ExtendedColorConfig()
512 std::unique_lock aGuard( ColorMutex_Impl() );
513 if ( !m_pImpl )
514 m_pImpl = new ExtendedColorConfig_Impl;
515 ++nExtendedColorRefCount_Impl;
516 StartListening( *m_pImpl);
519 ExtendedColorConfig::~ExtendedColorConfig()
521 std::unique_lock aGuard( ColorMutex_Impl() );
522 EndListening( *m_pImpl);
523 if(!--nExtendedColorRefCount_Impl)
525 delete m_pImpl;
526 m_pImpl = nullptr;
530 ExtendedColorConfigValue ExtendedColorConfig::GetColorValue(const OUString& _sComponentName,const OUString& _sName)const
532 return m_pImpl->GetColorConfigValue(_sComponentName,_sName);
535 sal_Int32 ExtendedColorConfig::GetComponentCount() const
537 return m_pImpl->GetComponentCount();
540 sal_Int32 ExtendedColorConfig::GetComponentColorCount(const OUString& _sName) const
542 return m_pImpl->GetComponentColorCount(_sName);
545 ExtendedColorConfigValue ExtendedColorConfig::GetComponentColorConfigValue(const OUString& _sName,sal_uInt32 _nPos) const
547 return m_pImpl->GetComponentColorConfigValue(_sName,_nPos);
550 OUString ExtendedColorConfig::GetComponentName(sal_uInt32 _nPos) const
552 return m_pImpl->GetComponentName(_nPos);
555 OUString ExtendedColorConfig::GetComponentDisplayName(const OUString& _sComponentName) const
557 return m_pImpl->GetComponentDisplayName(_sComponentName);
560 void ExtendedColorConfig::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
562 SolarMutexGuard aVclGuard;
564 Broadcast( rHint );
567 EditableExtendedColorConfig::EditableExtendedColorConfig() :
568 m_pImpl(new ExtendedColorConfig_Impl),
569 m_bModified(false)
571 ExtendedColorConfig_Impl::LockBroadcast();
574 EditableExtendedColorConfig::~EditableExtendedColorConfig()
576 ExtendedColorConfig_Impl::UnlockBroadcast();
577 if(m_bModified)
578 m_pImpl->SetModified();
579 if(m_pImpl->IsModified())
580 m_pImpl->Commit();
583 void EditableExtendedColorConfig::DeleteScheme(const OUString& rScheme )
585 m_pImpl->RemoveScheme(rScheme);
588 void EditableExtendedColorConfig::AddScheme(const OUString& rScheme )
590 m_pImpl->AddScheme(rScheme);
593 void EditableExtendedColorConfig::LoadScheme(const OUString& rScheme )
595 if(m_bModified)
596 m_pImpl->SetModified();
597 if(m_pImpl->IsModified())
598 m_pImpl->Commit();
599 m_bModified = false;
600 m_pImpl->Load(rScheme);
601 //the name of the loaded scheme has to be committed separately
602 m_pImpl->CommitCurrentSchemeName();
605 // Changes the name of the current scheme but doesn't load it!
606 void EditableExtendedColorConfig::SetCurrentSchemeName(const OUString& rScheme)
608 m_pImpl->SetCurrentSchemeName(rScheme);
609 m_pImpl->CommitCurrentSchemeName();
612 void EditableExtendedColorConfig::SetColorValue(
613 const OUString& _sName, const ExtendedColorConfigValue& rValue)
615 m_pImpl->SetColorConfigValue(_sName, rValue);
616 m_pImpl->ClearModified();
617 m_bModified = true;
620 void EditableExtendedColorConfig::SetModified()
622 m_bModified = true;
625 void EditableExtendedColorConfig::Commit()
627 if(m_bModified)
628 m_pImpl->SetModified();
629 if(m_pImpl->IsModified())
630 m_pImpl->Commit();
631 m_bModified = false;
634 void EditableExtendedColorConfig::DisableBroadcast()
636 ExtendedColorConfig_Impl::DisableBroadcast();
639 void EditableExtendedColorConfig::EnableBroadcast()
641 ExtendedColorConfig_Impl::EnableBroadcast();
644 sal_Int32 EditableExtendedColorConfig::GetComponentCount() const
646 return m_pImpl->GetComponentCount();
649 sal_Int32 EditableExtendedColorConfig::GetComponentColorCount(const OUString& _sName) const
651 return m_pImpl->GetComponentColorCount(_sName);
654 ExtendedColorConfigValue EditableExtendedColorConfig::GetComponentColorConfigValue(const OUString& _sName,sal_uInt32 _nPos) const
656 return m_pImpl->GetComponentColorConfigValue(_sName,_nPos);
659 OUString EditableExtendedColorConfig::GetComponentName(sal_uInt32 _nPos) const
661 return m_pImpl->GetComponentName(_nPos);
663 }//namespace svtools
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */