1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/config.h>
21
22 #include <sal/log.hxx>
23 #include <unotools/cmdoptions.hxx>
24 #include <unotools/configitem.hxx>
25 #include <tools/debug.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <com/sun/star/frame/XFrame.hpp>
29 #include <cppuhelper/weakref.hxx>
30 #include <rtl/instance.hxx>
31
32 #include "itemholder1.hxx"
33
34 #include <algorithm>
35 #include <unordered_map>
36
37 using namespace ::std;
38 using namespace ::utl;
39 using namespace ::osl;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::beans;
42
43 #define ROOTNODE_CMDOPTIONS "Office.Commands/Execute"
44 #define PATHDELIMITER "/"
45
46 #define SETNODE_DISABLED "Disabled"
47
48 #define PROPERTYNAME_CMD "Command"
49
50 namespace {
51
52 /*-****************************************************************************************************************
53 @descr support simple command option structures and operations on it
54 ****************************************************************************************************************-*/
55 class SvtCmdOptions
56 {
57 public:
58
59 // the only way to free memory!
Clear()60 void Clear()
61 {
62 m_aCommandHashMap.clear();
63 }
64
HasEntries() const65 bool HasEntries() const
66 {
67 return ( !m_aCommandHashMap.empty() );
68 }
69
Lookup(const OUString & aCmd) const70 bool Lookup( const OUString& aCmd ) const
71 {
72 CommandHashMap::const_iterator pEntry = m_aCommandHashMap.find( aCmd );
73 return ( pEntry != m_aCommandHashMap.end() );
74 }
75
AddCommand(const OUString & aCmd)76 void AddCommand( const OUString& aCmd )
77 {
78 m_aCommandHashMap.emplace( aCmd, 0 );
79 }
80
81 private:
82 typedef std::unordered_map<OUString, sal_Int32>
83 CommandHashMap;
84
85 CommandHashMap m_aCommandHashMap;
86 };
87
88 }
89
90 typedef ::std::vector< css::uno::WeakReference< css::frame::XFrame > > SvtFrameVector;
91
92 class SvtCommandOptions_Impl : public ConfigItem
93 {
94 public:
95
96 SvtCommandOptions_Impl();
97 virtual ~SvtCommandOptions_Impl() override;
98
99 /*-****************************************************************************************************
100 @short called for notify of configmanager
101 @descr This method is called from the ConfigManager before the application ends or from the
102 PropertyChangeListener if the sub tree broadcasts changes. You must update your
103 internal values.
104
105 @seealso baseclass ConfigItem
106
107 @param "lPropertyNames" is the list of properties which should be updated.
108 *//*-*****************************************************************************************************/
109
110 virtual void Notify( const Sequence< OUString >& lPropertyNames ) override;
111
112 /*-****************************************************************************************************
113 @short base implementation of public interface for "SvtDynamicMenuOptions"!
114 @descr These class is used as static member of "SvtDynamicMenuOptions" ...
115 => The code exist only for one time and isn't duplicated for every instance!
116 *//*-*****************************************************************************************************/
117
118 bool HasEntries ( SvtCommandOptions::CmdOption eOption ) const;
119 bool Lookup ( SvtCommandOptions::CmdOption eCmdOption, const OUString& ) const;
120 void EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame);
121
122 private:
123
124 virtual void ImplCommit() override;
125
126 /*-****************************************************************************************************
127 @short return list of key names of our configuration management which represent our module tree
128 @descr This method returns the current list of key names! We need it to get needed values from our
129 configuration management and support dynamical menu item lists!
130 @param "nDisabledCount", returns count of menu entries for "new"
131 @return A list of configuration key names is returned.
132 *//*-*****************************************************************************************************/
133
134 Sequence< OUString > impl_GetPropertyNames();
135
136 private:
137 SvtCmdOptions m_aDisabledCommands;
138 SvtFrameVector m_lFrames;
139 };
140
141 // constructor
142
SvtCommandOptions_Impl()143 SvtCommandOptions_Impl::SvtCommandOptions_Impl()
144 // Init baseclasses first
145 : ConfigItem( ROOTNODE_CMDOPTIONS )
146 // Init member then...
147 {
148 // Get names and values of all accessible menu entries and fill internal structures.
149 // See impl_GetPropertyNames() for further information.
150 Sequence< OUString > lNames = impl_GetPropertyNames ();
151 Sequence< Any > lValues = GetProperties ( lNames );
152
153 // Safe impossible cases.
154 // We need values from ALL configuration keys.
155 // Follow assignment use order of values in relation to our list of key names!
156 DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::SvtCommandOptions_Impl()\nI miss some values of configuration keys!\n" );
157
158 // Copy values from list in right order to our internal member.
159 // Attention: List for names and values have an internal construction pattern!
160 sal_Int32 nItem = 0;
161 OUString sCmd;
162
163 // Get names/values for disabled commands.
164 for( nItem=0; nItem < lNames.getLength(); ++nItem )
165 {
166 // Currently only one value
167 lValues[nItem] >>= sCmd;
168 m_aDisabledCommands.AddCommand( sCmd );
169 }
170
171 /*TODO: Not used in the moment! see Notify() ...
172 // Enable notification mechanism of our baseclass.
173 // We need it to get information about changes outside these class on our used configuration keys! */
174 Sequence<OUString> aNotifySeq { "Disabled" };
175 EnableNotification( aNotifySeq, true );
176 }
177
178 // destructor
179
~SvtCommandOptions_Impl()180 SvtCommandOptions_Impl::~SvtCommandOptions_Impl()
181 {
182 assert(!IsModified()); // should have been committed
183 }
184
185 // public method
186
Notify(const Sequence<OUString> &)187 void SvtCommandOptions_Impl::Notify( const Sequence< OUString >& )
188 {
189 MutexGuard aGuard( SvtCommandOptions::GetOwnStaticMutex() );
190
191 Sequence< OUString > lNames = impl_GetPropertyNames ();
192 Sequence< Any > lValues = GetProperties ( lNames );
193
194 // Safe impossible cases.
195 // We need values from ALL configuration keys.
196 // Follow assignment use order of values in relation to our list of key names!
197 DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::Notify()\nI miss some values of configuration keys!\n" );
198
199 // Copy values from list in right order to our internal member.
200 // Attention: List for names and values have an internal construction pattern!
201 sal_Int32 nItem = 0;
202 OUString sCmd;
203
204 m_aDisabledCommands.Clear();
205
206 // Get names/values for disabled commands.
207 for( nItem=0; nItem < lNames.getLength(); ++nItem )
208 {
209 // Currently only one value
210 lValues[nItem] >>= sCmd;
211 m_aDisabledCommands.AddCommand( sCmd );
212 }
213
214 // don't forget to update all existing frames and her might cached dispatch objects!
215 // But look for already killed frames. We hold weak references instead of hard ones ...
216 for (SvtFrameVector::iterator pIt = m_lFrames.begin(); pIt != m_lFrames.end(); )
217 {
218 css::uno::Reference< css::frame::XFrame > xFrame(pIt->get(), css::uno::UNO_QUERY);
219 if (xFrame.is())
220 {
221 xFrame->contextChanged();
222 ++pIt;
223 }
224 else
225 pIt = m_lFrames.erase(pIt);
226 }
227 }
228
229 // public method
230
ImplCommit()231 void SvtCommandOptions_Impl::ImplCommit()
232 {
233 SAL_WARN("unotools.config","SvtCommandOptions_Impl::ImplCommit(): Not implemented yet!");
234 }
235
236 // public method
237
HasEntries(SvtCommandOptions::CmdOption eOption) const238 bool SvtCommandOptions_Impl::HasEntries( SvtCommandOptions::CmdOption eOption ) const
239 {
240 if ( eOption == SvtCommandOptions::CMDOPTION_DISABLED )
241 return m_aDisabledCommands.HasEntries();
242 else
243 return false;
244 }
245
246 // public method
247
Lookup(SvtCommandOptions::CmdOption eCmdOption,const OUString & aCommand) const248 bool SvtCommandOptions_Impl::Lookup( SvtCommandOptions::CmdOption eCmdOption, const OUString& aCommand ) const
249 {
250 switch( eCmdOption )
251 {
252 case SvtCommandOptions::CMDOPTION_DISABLED:
253 {
254 return m_aDisabledCommands.Lookup( aCommand );
255 }
256 default:
257 SAL_WARN( "unotools.config", "SvtCommandOptions_Impl::Lookup() Unknown option type given!" );
258 }
259
260 return false;
261 }
262
263 // public method
264
EstablishFrameCallback(const css::uno::Reference<css::frame::XFrame> & xFrame)265 void SvtCommandOptions_Impl::EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame)
266 {
267 // check if frame already exists inside list
268 // ignore double registrations
269 // every frame must be notified one times only!
270 css::uno::WeakReference< css::frame::XFrame > xWeak(xFrame);
271 SvtFrameVector::const_iterator pIt = ::std::find(m_lFrames.begin(), m_lFrames.end(), xWeak);
272 if (pIt == m_lFrames.end())
273 m_lFrames.push_back(xWeak);
274 }
275
276 // private method
277
impl_GetPropertyNames()278 Sequence< OUString > SvtCommandOptions_Impl::impl_GetPropertyNames()
279 {
280 // First get ALL names of current existing list items in configuration!
281 Sequence< OUString > lDisabledItems = GetNodeNames( SETNODE_DISABLED, utl::ConfigNameFormat::LocalPath );
282
283 // Expand all keys
284 std::transform(lDisabledItems.begin(), lDisabledItems.end(), lDisabledItems.begin(),
285 [](const OUString& rItem) -> OUString {
286 return SETNODE_DISABLED PATHDELIMITER + rItem + PATHDELIMITER PROPERTYNAME_CMD; });
287
288 // Return result.
289 return lDisabledItems;
290 }
291
292 namespace {
293
294 std::weak_ptr<SvtCommandOptions_Impl> g_pCommandOptions;
295
296 }
297
SvtCommandOptions()298 SvtCommandOptions::SvtCommandOptions()
299 {
300 // Global access, must be guarded (multithreading!).
301 MutexGuard aGuard( GetOwnStaticMutex() );
302
303 m_pImpl = g_pCommandOptions.lock();
304 if( !m_pImpl )
305 {
306 m_pImpl = std::make_shared<SvtCommandOptions_Impl>();
307 g_pCommandOptions = m_pImpl;
308 ItemHolder1::holdConfigItem(EItem::CmdOptions);
309 }
310 }
311
~SvtCommandOptions()312 SvtCommandOptions::~SvtCommandOptions()
313 {
314 // Global access, must be guarded (multithreading!)
315 MutexGuard aGuard( GetOwnStaticMutex() );
316
317 m_pImpl.reset();
318 }
319
320 // public method
321
HasEntries(CmdOption eOption) const322 bool SvtCommandOptions::HasEntries( CmdOption eOption ) const
323 {
324 MutexGuard aGuard( GetOwnStaticMutex() );
325 return m_pImpl->HasEntries( eOption );
326 }
327
328 // public method
329
Lookup(CmdOption eCmdOption,const OUString & aCommandURL) const330 bool SvtCommandOptions::Lookup( CmdOption eCmdOption, const OUString& aCommandURL ) const
331 {
332 MutexGuard aGuard( GetOwnStaticMutex() );
333 return m_pImpl->Lookup( eCmdOption, aCommandURL );
334 }
335
336 // public method
337
EstablishFrameCallback(const css::uno::Reference<css::frame::XFrame> & xFrame)338 void SvtCommandOptions::EstablishFrameCallback(const css::uno::Reference< css::frame::XFrame >& xFrame)
339 {
340 MutexGuard aGuard( GetOwnStaticMutex() );
341 m_pImpl->EstablishFrameCallback(xFrame);
342 }
343
344 namespace
345 {
346 class theCommandOptionsMutex : public rtl::Static<osl::Mutex, theCommandOptionsMutex>{};
347 }
348
349 // private method
350
GetOwnStaticMutex()351 Mutex& SvtCommandOptions::GetOwnStaticMutex()
352 {
353 return theCommandOptionsMutex::get();
354 }
355
356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
357