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