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>
22 #include <comphelper/configuration.hxx>
23 #include <comphelper/propertyvalue.hxx>
24 #include <unotools/eventcfg.hxx>
25 #include <unotools/configmgr.hxx>
26 #include <unotools/configitem.hxx>
27 #include <com/sun/star/uno/Any.hxx>
28 #include <com/sun/star/uno/Sequence.hxx>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <o3tl/enumarray.hxx>
31 #include <o3tl/enumrange.hxx>
32 #include <rtl/ref.hxx>
33 #include <sal/log.hxx>
35 #include "itemholder1.hxx"
38 #include <unordered_map>
40 using namespace ::utl
;
41 using namespace ::osl
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star
;
45 #define PATHDELIMITER "/"
46 #define SETNODE_BINDINGS "Bindings"
47 #define PROPERTYNAME_BINDINGURL "BindingURL"
49 static o3tl::enumarray
<GlobalEventId
, const char*> pEventAsciiNames
=
72 "OnPrepareViewClosing",
81 typedef std::unordered_map
< OUString
, OUString
> EventBindingHash
;
82 typedef o3tl::enumarray
< GlobalEventId
, OUString
> SupportedEventsVector
;
84 static std::mutex
& GetOwnStaticMutex()
86 static std::mutex INSTANCE
;
90 class GlobalEventConfig_Impl
: public utl::ConfigItem
93 EventBindingHash m_eventBindingHash
;
94 SupportedEventsVector m_supportedEvents
;
96 void initBindingInfo();
98 virtual void ImplCommit() override
;
101 GlobalEventConfig_Impl( );
102 virtual ~GlobalEventConfig_Impl( ) override
;
104 void Notify( const css::uno::Sequence
<OUString
>& aPropertyNames
) override
;
106 /// @throws css::lang::IllegalArgumentException
107 /// @throws css::container::NoSuchElementException
108 /// @throws css::lang::WrappedTargetException
109 /// @throws css::uno::RuntimeException
110 void replaceByName( const OUString
& aName
, const css::uno::Any
& aElement
);
111 /// @throws css::container::NoSuchElementException
112 /// @throws css::lang::WrappedTargetException
113 /// @throws css::uno::RuntimeException
114 css::uno::Sequence
< css::beans::PropertyValue
> getByName( const OUString
& aName
);
115 /// @throws css::uno::RuntimeException
116 css::uno::Sequence
< OUString
> getElementNames( );
117 /// @throws css::uno::RuntimeException
118 bool hasByName( const OUString
& aName
);
119 /// @throws css::uno::RuntimeException
120 static css::uno::Type
const & getElementType( );
121 /// @throws css::uno::RuntimeException
122 bool hasElements() const;
123 OUString
const & GetEventName( GlobalEventId nID
) const;
127 GlobalEventConfig_Impl::GlobalEventConfig_Impl()
128 : ConfigItem( "Office.Events/ApplicationEvents", ConfigItemMode::NONE
)
130 // the supported event names
131 for (const GlobalEventId id
: o3tl::enumrange
<GlobalEventId
>())
132 m_supportedEvents
[id
] = OUString::createFromAscii( pEventAsciiNames
[id
] );
136 /*TODO: Not used in the moment! see Notify() ...
137 // Enable notification mechanism of our baseclass.
138 // We need it to get information about changes outside these class on our used configuration keys! */
139 Sequence
<OUString
> aNotifySeq
{ "Events" };
140 EnableNotification( aNotifySeq
, true );
145 GlobalEventConfig_Impl::~GlobalEventConfig_Impl()
147 assert(!IsModified()); // should have been committed
150 OUString
const & GlobalEventConfig_Impl::GetEventName( GlobalEventId nIndex
) const
152 return m_supportedEvents
[nIndex
];
157 void GlobalEventConfig_Impl::Notify( const Sequence
< OUString
>& )
159 std::unique_lock
aGuard( GetOwnStaticMutex() );
166 void GlobalEventConfig_Impl::ImplCommit()
168 //DF need to check it this is correct??
169 SAL_INFO("unotools", "In GlobalEventConfig_Impl::ImplCommit");
170 // clear the existing nodes
171 ClearNodeSet( SETNODE_BINDINGS
);
173 //step through the list of events
174 for(const auto& rEntry
: m_eventBindingHash
)
176 //no point in writing out empty bindings!
177 if(rEntry
.second
.isEmpty() )
179 sNode
= SETNODE_BINDINGS PATHDELIMITER
"BindingType['" +
181 "']" PATHDELIMITER PROPERTYNAME_BINDINGURL
;
182 SAL_INFO("unotools", "writing binding for: " << sNode
);
183 //write the data to the registry
184 SetSetProperties(SETNODE_BINDINGS
,{ comphelper::makePropertyValue(sNode
, rEntry
.second
) });
190 void GlobalEventConfig_Impl::initBindingInfo()
192 // Get ALL names of current existing list items in configuration!
193 const Sequence
< OUString
> lEventNames
= GetNodeNames( SETNODE_BINDINGS
, utl::ConfigNameFormat::LocalPath
);
195 OUString aSetNode
= SETNODE_BINDINGS PATHDELIMITER
;
196 OUString aCommandKey
= PATHDELIMITER PROPERTYNAME_BINDINGURL
;
199 Sequence
< OUString
> lMacros(1);
200 auto plMacros
= lMacros
.getArray();
201 for (const auto& rEventName
: lEventNames
)
203 plMacros
[0] = aSetNode
+ rEventName
+ aCommandKey
;
204 SAL_INFO("unotools", "reading binding for: " << lMacros
[0]);
205 Sequence
< Any
> lValues
= GetProperties( lMacros
);
206 if( lValues
.hasElements() )
209 lValues
[0] >>= sMacroURL
;
210 sal_Int32 startIndex
= rEventName
.indexOf('\'');
211 sal_Int32 endIndex
= rEventName
.lastIndexOf('\'');
212 if( startIndex
>=0 && endIndex
> 0 )
215 OUString eventName
= rEventName
.copy(startIndex
,endIndex
-startIndex
);
216 m_eventBindingHash
[ eventName
] = sMacroURL
;
222 void GlobalEventConfig_Impl::replaceByName( const OUString
& aName
, const Any
& aElement
)
224 Sequence
< beans::PropertyValue
> props
;
225 //DF should we prepopulate the hash with a list of valid event Names?
226 if( !( aElement
>>= props
) )
228 throw lang::IllegalArgumentException( OUString(),
229 Reference
< XInterface
> (), 2);
232 for (const auto& rProp
: props
)
234 if ( rProp
.Name
== "Script" )
235 rProp
.Value
>>= macroURL
;
237 m_eventBindingHash
[ aName
] = macroURL
;
241 css::uno::Sequence
< css::beans::PropertyValue
> GlobalEventConfig_Impl::getByName( const OUString
& aName
)
243 static constexpr OUStringLiteral sEventType
= u
"EventType";
244 static constexpr OUString sScript
= u
"Script"_ustr
;
245 Sequence
< beans::PropertyValue
> props(2);
246 auto pProps
= props
.getArray();
247 pProps
[0].Name
= sEventType
;
248 pProps
[0].Value
<<= sScript
;
249 pProps
[1].Name
= sScript
;
250 EventBindingHash::const_iterator it
= m_eventBindingHash
.find( aName
);
251 if( it
!= m_eventBindingHash
.end() )
253 pProps
[1].Value
<<= it
->second
;
257 // not yet accessed - is it a supported name?
258 SupportedEventsVector::iterator pos
= ::std::find(
259 m_supportedEvents
.begin(), m_supportedEvents
.end(), aName
);
260 if ( pos
== m_supportedEvents
.end() )
261 throw container::NoSuchElementException( aName
);
263 pProps
[1].Value
<<= OUString();
268 Sequence
< OUString
> GlobalEventConfig_Impl::getElementNames( )
270 return uno::Sequence
< OUString
>(m_supportedEvents
.data(), SupportedEventsVector::size());
273 bool GlobalEventConfig_Impl::hasByName( const OUString
& aName
)
275 if ( m_eventBindingHash
.find( aName
) != m_eventBindingHash
.end() )
278 // never accessed before - is it supported in general?
279 SupportedEventsVector::iterator pos
= ::std::find(
280 m_supportedEvents
.begin(), m_supportedEvents
.end(), aName
);
281 return pos
!= m_supportedEvents
.end();
284 Type
const & GlobalEventConfig_Impl::getElementType( )
286 //DF definitely not sure about this??
287 return cppu::UnoType
<Sequence
<beans::PropertyValue
>>::get();
290 bool GlobalEventConfig_Impl::hasElements() const
292 return !m_eventBindingHash
.empty();
295 // and now the wrapper
297 //initialize static member
298 GlobalEventConfig_Impl
* GlobalEventConfig::m_pImpl
= nullptr;
299 sal_Int32
GlobalEventConfig::m_nRefCount
= 0;
301 GlobalEventConfig::GlobalEventConfig()
303 // Global access, must be guarded (multithreading!).
304 std::unique_lock
aGuard( GetOwnStaticMutex() );
305 // Increase our refcount ...
307 // ... and initialize our data container only if it not already exist!
308 if( m_pImpl
== nullptr )
310 m_pImpl
= new GlobalEventConfig_Impl
;
312 ItemHolder1::holdConfigItem(EItem::EventConfig
);
316 GlobalEventConfig::~GlobalEventConfig()
318 // Global access, must be guarded (multithreading!)
319 std::unique_lock
aGuard( GetOwnStaticMutex() );
320 // Decrease our refcount.
322 // If last instance was deleted ...
323 // we must destroy our static data container!
324 if( m_nRefCount
<= 0 )
331 Reference
< container::XNameReplace
> SAL_CALL
GlobalEventConfig::getEvents()
333 std::unique_lock
aGuard( GetOwnStaticMutex() );
334 Reference
< container::XNameReplace
> ret(this);
338 void SAL_CALL
GlobalEventConfig::replaceByName( const OUString
& aName
, const Any
& aElement
)
340 std::unique_lock
aGuard( GetOwnStaticMutex() );
341 m_pImpl
->replaceByName( aName
, aElement
);
343 Any SAL_CALL
GlobalEventConfig::getByName( const OUString
& aName
)
345 return Any(getByName2(aName
));
347 css::uno::Sequence
< css::beans::PropertyValue
> GlobalEventConfig::getByName2( const OUString
& aName
)
349 std::unique_lock
aGuard( GetOwnStaticMutex() );
350 return m_pImpl
->getByName( aName
);
352 Sequence
< OUString
> SAL_CALL
GlobalEventConfig::getElementNames( )
354 std::unique_lock
aGuard( GetOwnStaticMutex() );
355 return m_pImpl
->getElementNames( );
357 sal_Bool SAL_CALL
GlobalEventConfig::hasByName( const OUString
& aName
)
359 std::unique_lock
aGuard( GetOwnStaticMutex() );
360 return m_pImpl
->hasByName( aName
);
362 Type SAL_CALL
GlobalEventConfig::getElementType( )
364 std::unique_lock
aGuard( GetOwnStaticMutex() );
365 return GlobalEventConfig_Impl::getElementType( );
367 sal_Bool SAL_CALL
GlobalEventConfig::hasElements( )
369 std::unique_lock
aGuard( GetOwnStaticMutex() );
370 return m_pImpl
->hasElements( );
373 OUString
GlobalEventConfig::GetEventName( GlobalEventId nIndex
)
375 if (comphelper::IsFuzzing())
377 static rtl::Reference
<GlobalEventConfig
> createImpl(new GlobalEventConfig
);
378 return GlobalEventConfig::m_pImpl
->GetEventName( nIndex
);
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */