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
= std::move(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
= std::move(xGlobalCfg
);
163 m_xModuleCfg
= std::move(xModuleCfg
);
164 m_xDocCfg
= std::move(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 if (sCommand
.isEmpty())
186 // SAFE -> ----------------------------------
187 std::unique_lock
aLock(m_aLock
);
189 // or for some reason m_xContext is NULL (which would crash impl_ts_getURLParser()
190 if (!m_xContext
.is())
193 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider
= m_xDispatcher
;
196 // <- SAFE ----------------------------------
198 // convert command in URL structure
199 css::uno::Reference
< css::util::XURLTransformer
> xParser
= impl_ts_getURLParser();
201 aURL
.Complete
= sCommand
;
202 xParser
->parseStrict(aURL
);
204 // ask for dispatch object
205 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= xProvider
->queryDispatch(aURL
, OUString(), 0);
206 bool bRet
= xDispatch
.is();
209 // Note: Such instance can be used one times only and destroy itself afterwards .-)
210 css::uno::Reference
<css::lang::XComponent
> xFrame(xProvider
, css::uno::UNO_QUERY
);
211 if (vcl::lok::isUnipoll())
212 { // tdf#130382 - all synchronous really.
214 xDispatch
->dispatch (aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
216 catch(const css::uno::Exception
&ev
)
218 SAL_INFO("svtools", "exception on key emission: " << ev
.Message
);
223 rtl::Reference
<AsyncAccelExec
> pExec
= AsyncAccelExec::createOneShotInstance(xFrame
, xDispatch
, aURL
);
232 css::awt::KeyEvent
AcceleratorExecute::st_VCLKey2AWTKey(const vcl::KeyCode
& aVCLKey
)
234 css::awt::KeyEvent aAWTKey
;
235 aAWTKey
.Modifiers
= 0;
236 aAWTKey
.KeyCode
= static_cast<sal_Int16
>(aVCLKey
.GetCode());
238 if (aVCLKey
.IsShift())
239 aAWTKey
.Modifiers
|= css::awt::KeyModifier::SHIFT
;
240 if (aVCLKey
.IsMod1())
241 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD1
;
242 if (aVCLKey
.IsMod2())
243 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD2
;
244 if (aVCLKey
.IsMod3())
245 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD3
;
250 vcl::KeyCode
AcceleratorExecute::st_AWTKey2VCLKey(const css::awt::KeyEvent
& aAWTKey
)
252 bool bShift
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::SHIFT
) == css::awt::KeyModifier::SHIFT
);
253 bool bMod1
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD1
) == css::awt::KeyModifier::MOD1
);
254 bool bMod2
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD2
) == css::awt::KeyModifier::MOD2
);
255 bool bMod3
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD3
) == css::awt::KeyModifier::MOD3
);
256 sal_uInt16 nKey
= static_cast<sal_uInt16
>(aAWTKey
.KeyCode
);
258 return vcl::KeyCode(nKey
, bShift
, bMod1
, bMod2
, bMod3
);
261 OUString
AcceleratorExecute::findCommand(const css::awt::KeyEvent
& aKey
)
263 return impl_ts_findCommand(aKey
);
266 OUString
AcceleratorExecute::impl_ts_findCommand(const css::awt::KeyEvent
& aKey
)
268 // SAFE -> ----------------------------------
269 std::unique_lock
aLock(m_aLock
);
271 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= m_xGlobalCfg
;
272 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xModuleCfg
= m_xModuleCfg
;
273 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xDocCfg
= m_xDocCfg
;
276 // <- SAFE ----------------------------------
283 sCommand
= xDocCfg
->getCommandByKeyEvent(aKey
);
284 if (!sCommand
.isEmpty())
287 catch(const css::container::NoSuchElementException
&)
293 sCommand
= xModuleCfg
->getCommandByKeyEvent(aKey
);
294 if (!sCommand
.isEmpty())
297 catch(const css::container::NoSuchElementException
&)
303 sCommand
= xGlobalCfg
->getCommandByKeyEvent(aKey
);
304 if (!sCommand
.isEmpty())
307 catch(const css::container::NoSuchElementException
&)
310 // fall back to functional key codes
311 if( aKey
.Modifiers
== 0 )
313 switch( aKey
.KeyCode
)
315 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
316 return u
".uno:DelToStartOfLine"_ustr
;
317 case css::awt::Key::DELETE_TO_END_OF_LINE
:
318 return u
".uno:DelToEndOfLine"_ustr
;
319 case css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH
:
320 return u
".uno:DelToStartOfPara"_ustr
;
321 case css::awt::Key::DELETE_TO_END_OF_PARAGRAPH
:
322 return u
".uno:DelToEndOfPara"_ustr
;
323 case css::awt::Key::DELETE_WORD_BACKWARD
:
324 return u
".uno:DelToStartOfWord"_ustr
;
325 case css::awt::Key::DELETE_WORD_FORWARD
:
326 return u
".uno:DelToEndOfWord"_ustr
;
327 case css::awt::Key::INSERT_LINEBREAK
:
328 return u
".uno:InsertLinebreak"_ustr
;
329 case css::awt::Key::INSERT_PARAGRAPH
:
330 return u
".uno:InsertPara"_ustr
;
331 case css::awt::Key::MOVE_WORD_BACKWARD
:
332 return u
".uno:GoToPrevWord"_ustr
;
333 case css::awt::Key::MOVE_WORD_FORWARD
:
334 return u
".uno:GoToNextWord"_ustr
;
335 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
336 return u
".uno:GoToStartOfLine"_ustr
;
337 case css::awt::Key::MOVE_TO_END_OF_LINE
:
338 return u
".uno:GoToEndOfLine"_ustr
;
339 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
340 return u
".uno:GoToStartOfPara"_ustr
;
341 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
342 return u
".uno:GoToEndOfPara"_ustr
;
343 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
344 return u
".uno:GoToStartOfDoc"_ustr
;
345 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
346 return u
".uno:GoToEndOfDoc"_ustr
;
347 case css::awt::Key::SELECT_BACKWARD
:
348 return u
".uno:CharLeftSel"_ustr
;
349 case css::awt::Key::SELECT_FORWARD
:
350 return u
".uno:CharRightSel"_ustr
;
351 case css::awt::Key::SELECT_WORD_BACKWARD
:
352 return u
".uno:WordLeftSel"_ustr
;
353 case css::awt::Key::SELECT_WORD_FORWARD
:
354 return u
".uno:WordRightSel"_ustr
;
355 case css::awt::Key::SELECT_WORD
:
356 return u
".uno:SelectWord"_ustr
;
357 case css::awt::Key::SELECT_LINE
:
359 case css::awt::Key::SELECT_PARAGRAPH
:
360 return u
".uno:SelectText"_ustr
;
361 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
362 return u
".uno:StartOfLineSel"_ustr
;
363 case css::awt::Key::SELECT_TO_END_OF_LINE
:
364 return u
".uno:EndOfLineSel"_ustr
;
365 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
366 return u
".uno:StartOfParaSel"_ustr
;
367 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
368 return u
".uno:EndOfParaSel"_ustr
;
369 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
370 return u
".uno:StartOfDocumentSel"_ustr
;
371 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
372 return u
".uno:EndOfDocumentSel"_ustr
;
373 case css::awt::Key::SELECT_ALL
:
374 return u
".uno:SelectAll"_ustr
;
384 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openModuleConfig(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
385 const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
387 css::uno::Reference
< css::frame::XModuleManager2
> xModuleDetection(
388 css::frame::ModuleManager::create(rxContext
));
393 sModule
= xModuleDetection
->identify(xFrame
);
395 catch(const css::uno::RuntimeException
&)
397 catch(const css::uno::Exception
&)
398 { return css::uno::Reference
< css::ui::XAcceleratorConfiguration
>(); }
400 css::uno::Reference
< css::ui::XModuleUIConfigurationManagerSupplier
> xUISupplier(
401 css::ui::theModuleUIConfigurationManagerSupplier::get(rxContext
) );
403 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
406 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager(sModule
);
407 xAccCfg
= xUIManager
->getShortCutManager();
409 catch(const css::container::NoSuchElementException
&)
414 css::uno::Reference
<css::ui::XAcceleratorConfiguration
> AcceleratorExecute::lok_createNewAcceleratorConfiguration(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
, const OUString
& sModule
)
416 css::uno::Reference
< css::ui::XModuleUIConfigurationManagerSupplier
> xUISupplier(css::ui::theModuleUIConfigurationManagerSupplier::get(rxContext
));
420 css::uno::Reference
<css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager(sModule
);
422 css::ui::XModuleUIConfigurationManager2
* t
= static_cast<css::ui::XModuleUIConfigurationManager2
*>(xUIManager
.get());
424 // Return new short cut manager in case current view's language is different from previous ones.
425 return t
->createShortCutManager();
427 catch(const css::container::NoSuchElementException
&)
430 return css::uno::Reference
<css::ui::XAcceleratorConfiguration
>();
433 void AcceleratorExecute::lok_setModuleConfig(const css::uno::Reference
<css::ui::XAcceleratorConfiguration
>& acceleratorConfig
)
435 this->m_xModuleCfg
= acceleratorConfig
;
438 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openDocConfig(const css::uno::Reference
< css::frame::XModel
>& xModel
)
440 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
441 css::uno::Reference
< css::ui::XUIConfigurationManagerSupplier
> xUISupplier(xModel
, css::uno::UNO_QUERY
);
442 if (xUISupplier
.is())
444 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager();
445 xAccCfg
= xUIManager
->getShortCutManager();
451 css::uno::Reference
< css::util::XURLTransformer
> AcceleratorExecute::impl_ts_getURLParser()
453 // SAFE -> ----------------------------------
454 std::unique_lock
aLock(m_aLock
);
456 if (m_xURLParser
.is())
458 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
461 // <- SAFE ----------------------------------
463 css::uno::Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create( xContext
);
465 // SAFE -> ----------------------------------
467 m_xURLParser
= xParser
;
469 // <- SAFE ----------------------------------
474 AsyncAccelExec::AsyncAccelExec(css::uno::Reference
<css::lang::XComponent
> xFrame
,
475 css::uno::Reference
<css::frame::XDispatch
> xDispatch
,
477 : m_xFrame(std::move(xFrame
))
478 , m_xDispatch(std::move(xDispatch
))
479 , m_aURL(std::move(aURL
))
480 , m_aAsyncCallback(LINK(this, AsyncAccelExec
, impl_ts_asyncCallback
))
485 rtl::Reference
<AsyncAccelExec
> AsyncAccelExec::createOneShotInstance(const css::uno::Reference
<css::lang::XComponent
> &xFrame
,
486 const css::uno::Reference
< css::frame::XDispatch
>& xDispatch
,
487 const css::util::URL
& rURL
)
489 rtl::Reference
<AsyncAccelExec
> pExec
= new AsyncAccelExec(xFrame
, xDispatch
, rURL
);
494 void AsyncAccelExec::execAsync()
497 m_xFrame
->addEventListener(this);
498 m_aAsyncCallback
.Post();
501 IMPL_LINK_NOARG(AsyncAccelExec
, impl_ts_asyncCallback
, LinkParamNone
*, void)
503 if (m_xDispatch
.is())
508 m_xFrame
->removeEventListener(this);
509 m_xDispatch
->dispatch(m_aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
511 catch(const css::uno::Exception
&)
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */