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 .
21 #include <svtools/acceleratorexecute.hxx>
23 #include <com/sun/star/frame/ModuleManager.hpp>
24 #include <com/sun/star/frame/Desktop.hpp>
25 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
26 #include <com/sun/star/ui/XUIConfigurationManager.hpp>
27 #include <com/sun/star/ui/XUIConfigurationManager2.hpp>
28 #include <com/sun/star/ui/XModuleUIConfigurationManager2.hpp>
29 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
30 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
31 #include <com/sun/star/awt/KeyModifier.hpp>
32 #include <com/sun/star/uno/Sequence.hxx>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/util/URLTransformer.hpp>
35 #include <cppuhelper/implbase.hxx>
38 #include <vcl/evntpost.hxx>
39 #include <sal/log.hxx>
40 #include <vcl/lok.hxx>
41 #include <rtl/ref.hxx>
43 #include <comphelper/lok.hxx>
50 class AsyncAccelExec
: public cppu::WeakImplHelper
<css::lang::XEventListener
>
53 css::uno::Reference
<css::lang::XComponent
> m_xFrame
;
54 css::uno::Reference
< css::frame::XDispatch
> m_xDispatch
;
55 css::util::URL m_aURL
;
56 vcl::EventPoster m_aAsyncCallback
;
59 /** creates a new instance of this class, which can be used
62 This instance can be forced to execute its internal set request
63 asynchronous. After that it deletes itself!
65 static rtl::Reference
<AsyncAccelExec
> createOneShotInstance(const css::uno::Reference
<css::lang::XComponent
>& xFrame
,
66 const css::uno::Reference
<css::frame::XDispatch
>& xDispatch
,
67 const css::util::URL
& rURL
);
72 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
74 m_xFrame
->removeEventListener(this);
79 /** @short allow creation of instances of this class
80 by using our factory only!
82 AsyncAccelExec(css::uno::Reference
<css::lang::XComponent
> xFrame
,
83 css::uno::Reference
< css::frame::XDispatch
> xDispatch
,
86 DECL_LINK(impl_ts_asyncCallback
, LinkParamNone
*, void);
91 AcceleratorExecute::AcceleratorExecute()
95 AcceleratorExecute::~AcceleratorExecute()
101 std::unique_ptr
<AcceleratorExecute
> AcceleratorExecute::createAcceleratorHelper()
103 return std::unique_ptr
<AcceleratorExecute
>(new AcceleratorExecute
);
107 void AcceleratorExecute::init(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
108 const css::uno::Reference
< css::frame::XFrame
>& xEnv
)
110 // SAFE -> ----------------------------------
111 std::unique_lock
aLock(m_aLock
);
113 // take over the uno service manager
114 m_xContext
= rxContext
;
116 // specify our internal dispatch provider
117 // frame or desktop?! => document or global config.
118 bool bDesktopIsUsed
= false;
119 m_xDispatcher
.set(xEnv
, css::uno::UNO_QUERY
);
120 if (!m_xDispatcher
.is())
123 // <- SAFE ------------------------------
125 css::uno::Reference
< css::frame::XDispatchProvider
> xDispatcher(css::frame::Desktop::create(rxContext
), css::uno::UNO_QUERY_THROW
);
127 // SAFE -> ------------------------------
130 m_xDispatcher
= xDispatcher
;
131 bDesktopIsUsed
= true;
135 // <- SAFE ----------------------------------
137 // open all needed configuration objects
138 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
;
139 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xModuleCfg
;
140 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xDocCfg
;
143 xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(rxContext
);
147 xModuleCfg
= AcceleratorExecute::st_openModuleConfig(rxContext
, xEnv
);
150 css::uno::Reference
< css::frame::XController
> xController
;
151 css::uno::Reference
< css::frame::XModel
> xModel
;
152 xController
= xEnv
->getController();
153 if (xController
.is())
154 xModel
= xController
->getModel();
156 xDocCfg
= AcceleratorExecute::st_openDocConfig(xModel
);
159 // SAFE -> ------------------------------
162 m_xGlobalCfg
= xGlobalCfg
;
163 m_xModuleCfg
= xModuleCfg
;
164 m_xDocCfg
= xDocCfg
;
167 // <- SAFE ----------------------------------
171 bool AcceleratorExecute::execute(const vcl::KeyCode
& aVCLKey
)
173 css::awt::KeyEvent aAWTKey
= AcceleratorExecute::st_VCLKey2AWTKey(aVCLKey
);
174 return execute(aAWTKey
);
178 bool AcceleratorExecute::execute(const css::awt::KeyEvent
& aAWTKey
)
180 OUString sCommand
= impl_ts_findCommand(aAWTKey
);
182 // No Command found? Do nothing! User is not interested on any error handling .-)
183 // or for some reason m_xContext is NULL (which would crash impl_ts_getURLParser()
184 if (sCommand
.isEmpty() || !m_xContext
.is())
189 // SAFE -> ----------------------------------
190 std::unique_lock
aLock(m_aLock
);
192 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider
= m_xDispatcher
;
195 // <- SAFE ----------------------------------
197 // convert command in URL structure
198 css::uno::Reference
< css::util::XURLTransformer
> xParser
= impl_ts_getURLParser();
200 aURL
.Complete
= sCommand
;
201 xParser
->parseStrict(aURL
);
203 // ask for dispatch object
204 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= xProvider
->queryDispatch(aURL
, OUString(), 0);
205 bool bRet
= xDispatch
.is();
208 // Note: Such instance can be used one times only and destroy itself afterwards .-)
209 css::uno::Reference
<css::lang::XComponent
> xFrame(xProvider
, css::uno::UNO_QUERY
);
210 if (vcl::lok::isUnipoll())
211 { // tdf#130382 - all synchronous really.
213 xDispatch
->dispatch (aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
215 catch(const css::uno::Exception
&ev
)
217 SAL_INFO("svtools", "exception on key emission: " << ev
.Message
);
222 rtl::Reference
<AsyncAccelExec
> pExec
= AsyncAccelExec::createOneShotInstance(xFrame
, xDispatch
, aURL
);
231 css::awt::KeyEvent
AcceleratorExecute::st_VCLKey2AWTKey(const vcl::KeyCode
& aVCLKey
)
233 css::awt::KeyEvent aAWTKey
;
234 aAWTKey
.Modifiers
= 0;
235 aAWTKey
.KeyCode
= static_cast<sal_Int16
>(aVCLKey
.GetCode());
237 if (aVCLKey
.IsShift())
238 aAWTKey
.Modifiers
|= css::awt::KeyModifier::SHIFT
;
239 if (aVCLKey
.IsMod1())
240 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD1
;
241 if (aVCLKey
.IsMod2())
242 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD2
;
243 if (aVCLKey
.IsMod3())
244 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD3
;
249 vcl::KeyCode
AcceleratorExecute::st_AWTKey2VCLKey(const css::awt::KeyEvent
& aAWTKey
)
251 bool bShift
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::SHIFT
) == css::awt::KeyModifier::SHIFT
);
252 bool bMod1
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD1
) == css::awt::KeyModifier::MOD1
);
253 bool bMod2
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD2
) == css::awt::KeyModifier::MOD2
);
254 bool bMod3
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD3
) == css::awt::KeyModifier::MOD3
);
255 sal_uInt16 nKey
= static_cast<sal_uInt16
>(aAWTKey
.KeyCode
);
257 return vcl::KeyCode(nKey
, bShift
, bMod1
, bMod2
, bMod3
);
260 OUString
AcceleratorExecute::findCommand(const css::awt::KeyEvent
& aKey
)
262 return impl_ts_findCommand(aKey
);
265 OUString
AcceleratorExecute::impl_ts_findCommand(const css::awt::KeyEvent
& aKey
)
267 // SAFE -> ----------------------------------
268 std::unique_lock
aLock(m_aLock
);
270 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= m_xGlobalCfg
;
271 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xModuleCfg
= m_xModuleCfg
;
272 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xDocCfg
= m_xDocCfg
;
275 // <- SAFE ----------------------------------
282 sCommand
= xDocCfg
->getCommandByKeyEvent(aKey
);
283 if (!sCommand
.isEmpty())
286 catch(const css::container::NoSuchElementException
&)
292 sCommand
= xModuleCfg
->getCommandByKeyEvent(aKey
);
293 if (!sCommand
.isEmpty())
296 catch(const css::container::NoSuchElementException
&)
302 sCommand
= xGlobalCfg
->getCommandByKeyEvent(aKey
);
303 if (!sCommand
.isEmpty())
306 catch(const css::container::NoSuchElementException
&)
309 // fall back to functional key codes
310 if( aKey
.Modifiers
== 0 )
312 switch( aKey
.KeyCode
)
314 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
315 return ".uno:DelToStartOfLine";
316 case css::awt::Key::DELETE_TO_END_OF_LINE
:
317 return ".uno:DelToEndOfLine";
318 case css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH
:
319 return ".uno:DelToStartOfPara";
320 case css::awt::Key::DELETE_TO_END_OF_PARAGRAPH
:
321 return ".uno:DelToEndOfPara";
322 case css::awt::Key::DELETE_WORD_BACKWARD
:
323 return ".uno:DelToStartOfWord";
324 case css::awt::Key::DELETE_WORD_FORWARD
:
325 return ".uno:DelToEndOfWord";
326 case css::awt::Key::INSERT_LINEBREAK
:
327 return ".uno:InsertLinebreak";
328 case css::awt::Key::INSERT_PARAGRAPH
:
329 return ".uno:InsertPara";
330 case css::awt::Key::MOVE_WORD_BACKWARD
:
331 return ".uno:GoToPrevWord";
332 case css::awt::Key::MOVE_WORD_FORWARD
:
333 return ".uno:GoToNextWord";
334 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
335 return ".uno:GoToStartOfLine";
336 case css::awt::Key::MOVE_TO_END_OF_LINE
:
337 return ".uno:GoToEndOfLine";
338 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
339 return ".uno:GoToStartOfPara";
340 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
341 return ".uno:GoToEndOfPara";
342 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
343 return ".uno:GoToStartOfDoc";
344 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
345 return ".uno:GoToEndOfDoc";
346 case css::awt::Key::SELECT_BACKWARD
:
347 return ".uno:CharLeftSel";
348 case css::awt::Key::SELECT_FORWARD
:
349 return ".uno:CharRightSel";
350 case css::awt::Key::SELECT_WORD_BACKWARD
:
351 return ".uno:WordLeftSel";
352 case css::awt::Key::SELECT_WORD_FORWARD
:
353 return ".uno:WordRightSel";
354 case css::awt::Key::SELECT_WORD
:
355 return ".uno:SelectWord";
356 case css::awt::Key::SELECT_LINE
:
358 case css::awt::Key::SELECT_PARAGRAPH
:
359 return ".uno:SelectText";
360 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
361 return ".uno:StartOfLineSel";
362 case css::awt::Key::SELECT_TO_END_OF_LINE
:
363 return ".uno:EndOfLineSel";
364 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
365 return ".uno:StartOfParaSel";
366 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
367 return ".uno:EndOfParaSel";
368 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
369 return ".uno:StartOfDocumentSel";
370 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
371 return ".uno:EndOfDocumentSel";
372 case css::awt::Key::SELECT_ALL
:
373 return ".uno:SelectAll";
383 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openModuleConfig(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
384 const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
386 css::uno::Reference
< css::frame::XModuleManager2
> xModuleDetection(
387 css::frame::ModuleManager::create(rxContext
));
392 sModule
= xModuleDetection
->identify(xFrame
);
394 catch(const css::uno::RuntimeException
&)
396 catch(const css::uno::Exception
&)
397 { return css::uno::Reference
< css::ui::XAcceleratorConfiguration
>(); }
399 css::uno::Reference
< css::ui::XModuleUIConfigurationManagerSupplier
> xUISupplier(
400 css::ui::theModuleUIConfigurationManagerSupplier::get(rxContext
) );
402 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
405 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager(sModule
);
406 xAccCfg
= xUIManager
->getShortCutManager();
408 catch(const css::container::NoSuchElementException
&)
413 css::uno::Reference
<css::ui::XAcceleratorConfiguration
> AcceleratorExecute::lok_createNewAcceleratorConfiguration(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
, OUString sModule
)
415 css::uno::Reference
< css::ui::XModuleUIConfigurationManagerSupplier
> xUISupplier(css::ui::theModuleUIConfigurationManagerSupplier::get(rxContext
));
419 css::uno::Reference
<css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager(sModule
);
421 css::ui::XModuleUIConfigurationManager2
* t
= static_cast<css::ui::XModuleUIConfigurationManager2
*>(xUIManager
.get());
423 // Return new short cut manager in case current view's language is different from previous ones.
424 return t
->createShortCutManager();
426 catch(const css::container::NoSuchElementException
&)
429 return css::uno::Reference
<css::ui::XAcceleratorConfiguration
>();
432 void AcceleratorExecute::lok_setModuleConfig(css::uno::Reference
<css::ui::XAcceleratorConfiguration
> acceleratorConfig
)
434 this->m_xModuleCfg
= acceleratorConfig
;
437 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openDocConfig(const css::uno::Reference
< css::frame::XModel
>& xModel
)
439 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
440 css::uno::Reference
< css::ui::XUIConfigurationManagerSupplier
> xUISupplier(xModel
, css::uno::UNO_QUERY
);
441 if (xUISupplier
.is())
443 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager();
444 xAccCfg
= xUIManager
->getShortCutManager();
450 css::uno::Reference
< css::util::XURLTransformer
> AcceleratorExecute::impl_ts_getURLParser()
452 // SAFE -> ----------------------------------
453 std::unique_lock
aLock(m_aLock
);
455 if (m_xURLParser
.is())
457 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
460 // <- SAFE ----------------------------------
462 css::uno::Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create( xContext
);
464 // SAFE -> ----------------------------------
466 m_xURLParser
= xParser
;
468 // <- SAFE ----------------------------------
473 AsyncAccelExec::AsyncAccelExec(css::uno::Reference
<css::lang::XComponent
> xFrame
,
474 css::uno::Reference
<css::frame::XDispatch
> xDispatch
,
476 : m_xFrame(std::move(xFrame
))
477 , m_xDispatch(std::move(xDispatch
))
478 , m_aURL(std::move(aURL
))
479 , m_aAsyncCallback(LINK(this, AsyncAccelExec
, impl_ts_asyncCallback
))
484 rtl::Reference
<AsyncAccelExec
> AsyncAccelExec::createOneShotInstance(const css::uno::Reference
<css::lang::XComponent
> &xFrame
,
485 const css::uno::Reference
< css::frame::XDispatch
>& xDispatch
,
486 const css::util::URL
& rURL
)
488 rtl::Reference
<AsyncAccelExec
> pExec
= new AsyncAccelExec(xFrame
, xDispatch
, rURL
);
493 void AsyncAccelExec::execAsync()
496 m_xFrame
->addEventListener(this);
497 m_aAsyncCallback
.Post();
500 IMPL_LINK_NOARG(AsyncAccelExec
, impl_ts_asyncCallback
, LinkParamNone
*, void)
502 if (m_xDispatch
.is())
507 m_xFrame
->removeEventListener(this);
508 m_xDispatch
->dispatch(m_aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
510 catch(const css::uno::Exception
&)
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */