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/theModuleUIConfigurationManagerSupplier.hpp>
28 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
29 #include <com/sun/star/awt/KeyModifier.hpp>
30 #include <com/sun/star/uno/Sequence.hxx>
31 #include <com/sun/star/beans/PropertyValue.hpp>
32 #include <com/sun/star/util/URLTransformer.hpp>
33 #include <cppuhelper/implbase.hxx>
35 #include <vcl/evntpost.hxx>
36 #include <sal/log.hxx>
37 #include <vcl/lok.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/svapp.hxx>
40 #include <osl/mutex.hxx>
47 class AsyncAccelExec
: public cppu::WeakImplHelper
<css::lang::XEventListener
>
50 css::uno::Reference
<css::lang::XComponent
> m_xFrame
;
51 css::uno::Reference
< css::frame::XDispatch
> m_xDispatch
;
52 css::util::URL m_aURL
;
53 vcl::EventPoster m_aAsyncCallback
;
56 /** creates a new instance of this class, which can be used
59 This instance can be forced to execute its internal set request
60 asynchronous. After that it deletes itself!
62 static AsyncAccelExec
* createOneShotInstance(const css::uno::Reference
<css::lang::XComponent
>& xFrame
,
63 const css::uno::Reference
<css::frame::XDispatch
>& xDispatch
,
64 const css::util::URL
& rURL
);
69 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
71 m_xFrame
->removeEventListener(this);
76 /** @short allow creation of instances of this class
77 by using our factory only!
79 AsyncAccelExec(const css::uno::Reference
<css::lang::XComponent
>& xFrame
,
80 const css::uno::Reference
< css::frame::XDispatch
>& xDispatch
,
81 const css::util::URL
& rURL
);
83 DECL_LINK(impl_ts_asyncCallback
, LinkParamNone
*, void);
88 AcceleratorExecute::AcceleratorExecute()
93 AcceleratorExecute::~AcceleratorExecute()
99 std::unique_ptr
<AcceleratorExecute
> AcceleratorExecute::createAcceleratorHelper()
101 return std::unique_ptr
<AcceleratorExecute
>(new AcceleratorExecute
);
105 void AcceleratorExecute::init(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
106 const css::uno::Reference
< css::frame::XFrame
>& xEnv
)
108 // SAFE -> ----------------------------------
109 ::osl::ResettableMutexGuard
aLock(m_aLock
);
111 // take over the uno service manager
112 m_xContext
= rxContext
;
114 // specify our internal dispatch provider
115 // frame or desktop?! => document or global config.
116 bool bDesktopIsUsed
= false;
117 m_xDispatcher
.set(xEnv
, css::uno::UNO_QUERY
);
118 if (!m_xDispatcher
.is())
121 // <- SAFE ------------------------------
123 css::uno::Reference
< css::frame::XDispatchProvider
> xDispatcher(css::frame::Desktop::create(rxContext
), css::uno::UNO_QUERY_THROW
);
125 // SAFE -> ------------------------------
128 m_xDispatcher
= xDispatcher
;
129 bDesktopIsUsed
= true;
133 // <- SAFE ----------------------------------
135 // open all needed configuration objects
136 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
;
137 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xModuleCfg
;
138 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xDocCfg
;
141 xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(rxContext
);
145 xModuleCfg
= AcceleratorExecute::st_openModuleConfig(rxContext
, xEnv
);
148 css::uno::Reference
< css::frame::XController
> xController
;
149 css::uno::Reference
< css::frame::XModel
> xModel
;
150 xController
= xEnv
->getController();
151 if (xController
.is())
152 xModel
= xController
->getModel();
154 xDocCfg
= AcceleratorExecute::st_openDocConfig(xModel
);
157 // SAFE -> ------------------------------
160 m_xGlobalCfg
= xGlobalCfg
;
161 m_xModuleCfg
= xModuleCfg
;
162 m_xDocCfg
= xDocCfg
;
165 // <- SAFE ----------------------------------
169 bool AcceleratorExecute::execute(const vcl::KeyCode
& aVCLKey
)
171 css::awt::KeyEvent aAWTKey
= AcceleratorExecute::st_VCLKey2AWTKey(aVCLKey
);
172 return execute(aAWTKey
);
176 bool AcceleratorExecute::execute(const css::awt::KeyEvent
& aAWTKey
)
178 OUString sCommand
= impl_ts_findCommand(aAWTKey
);
180 // No Command found? Do nothing! User is not interested on any error handling .-)
181 // or for some reason m_xContext is NULL (which would crash impl_ts_getURLParser()
182 if (sCommand
.isEmpty() || !m_xContext
.is())
187 // SAFE -> ----------------------------------
188 osl::ClearableMutexGuard
aLock(m_aLock
);
190 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider
= m_xDispatcher
;
193 // <- SAFE ----------------------------------
195 // convert command in URL structure
196 css::uno::Reference
< css::util::XURLTransformer
> xParser
= impl_ts_getURLParser();
198 aURL
.Complete
= sCommand
;
199 xParser
->parseStrict(aURL
);
201 // ask for dispatch object
202 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= xProvider
->queryDispatch(aURL
, OUString(), 0);
203 bool bRet
= xDispatch
.is();
206 // Note: Such instance can be used one times only and destroy itself afterwards .-)
207 css::uno::Reference
<css::lang::XComponent
> xFrame(xProvider
, css::uno::UNO_QUERY
);
208 if (vcl::lok::isUnipoll())
209 { // tdf#130382 - all synchronous really.
211 xDispatch
->dispatch (aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
213 catch(const css::uno::Exception
&ev
)
215 SAL_INFO("svtools", "exception on key emission: " << ev
.Message
);
220 AsyncAccelExec
* pExec
= AsyncAccelExec::createOneShotInstance(xFrame
, xDispatch
, aURL
);
229 css::awt::KeyEvent
AcceleratorExecute::st_VCLKey2AWTKey(const vcl::KeyCode
& aVCLKey
)
231 css::awt::KeyEvent aAWTKey
;
232 aAWTKey
.Modifiers
= 0;
233 aAWTKey
.KeyCode
= static_cast<sal_Int16
>(aVCLKey
.GetCode());
235 if (aVCLKey
.IsShift())
236 aAWTKey
.Modifiers
|= css::awt::KeyModifier::SHIFT
;
237 if (aVCLKey
.IsMod1())
238 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD1
;
239 if (aVCLKey
.IsMod2())
240 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD2
;
241 if (aVCLKey
.IsMod3())
242 aAWTKey
.Modifiers
|= css::awt::KeyModifier::MOD3
;
247 vcl::KeyCode
AcceleratorExecute::st_AWTKey2VCLKey(const css::awt::KeyEvent
& aAWTKey
)
249 bool bShift
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::SHIFT
) == css::awt::KeyModifier::SHIFT
);
250 bool bMod1
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD1
) == css::awt::KeyModifier::MOD1
);
251 bool bMod2
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD2
) == css::awt::KeyModifier::MOD2
);
252 bool bMod3
= ((aAWTKey
.Modifiers
& css::awt::KeyModifier::MOD3
) == css::awt::KeyModifier::MOD3
);
253 sal_uInt16 nKey
= static_cast<sal_uInt16
>(aAWTKey
.KeyCode
);
255 return vcl::KeyCode(nKey
, bShift
, bMod1
, bMod2
, bMod3
);
258 OUString
AcceleratorExecute::findCommand(const css::awt::KeyEvent
& aKey
)
260 return impl_ts_findCommand(aKey
);
263 OUString
AcceleratorExecute::impl_ts_findCommand(const css::awt::KeyEvent
& aKey
)
265 // SAFE -> ----------------------------------
266 osl::ClearableMutexGuard
aLock(m_aLock
);
268 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= m_xGlobalCfg
;
269 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xModuleCfg
= m_xModuleCfg
;
270 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xDocCfg
= m_xDocCfg
;
273 // <- SAFE ----------------------------------
280 sCommand
= xDocCfg
->getCommandByKeyEvent(aKey
);
281 if (!sCommand
.isEmpty())
284 catch(const css::container::NoSuchElementException
&)
290 sCommand
= xModuleCfg
->getCommandByKeyEvent(aKey
);
291 if (!sCommand
.isEmpty())
294 catch(const css::container::NoSuchElementException
&)
300 sCommand
= xGlobalCfg
->getCommandByKeyEvent(aKey
);
301 if (!sCommand
.isEmpty())
304 catch(const css::container::NoSuchElementException
&)
307 // fall back to functional key codes
308 if( aKey
.Modifiers
== 0 )
310 switch( aKey
.KeyCode
)
312 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
313 return ".uno:DelToStartOfLine";
314 case css::awt::Key::DELETE_TO_END_OF_LINE
:
315 return ".uno:DelToEndOfLine";
316 case css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH
:
317 return ".uno:DelToStartOfPara";
318 case css::awt::Key::DELETE_TO_END_OF_PARAGRAPH
:
319 return ".uno:DelToEndOfPara";
320 case css::awt::Key::DELETE_WORD_BACKWARD
:
321 return ".uno:DelToStartOfWord";
322 case css::awt::Key::DELETE_WORD_FORWARD
:
323 return ".uno:DelToEndOfWord";
324 case css::awt::Key::INSERT_LINEBREAK
:
325 return ".uno:InsertLinebreak";
326 case css::awt::Key::INSERT_PARAGRAPH
:
327 return ".uno:InsertPara";
328 case css::awt::Key::MOVE_WORD_BACKWARD
:
329 return ".uno:GoToPrevWord";
330 case css::awt::Key::MOVE_WORD_FORWARD
:
331 return ".uno:GoToNextWord";
332 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
333 return ".uno:GoToStartOfLine";
334 case css::awt::Key::MOVE_TO_END_OF_LINE
:
335 return ".uno:GoToEndOfLine";
336 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
337 return ".uno:GoToStartOfPara";
338 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
339 return ".uno:GoToEndOfPara";
340 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
341 return ".uno:GoToStartOfDoc";
342 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
343 return ".uno:GoToEndOfDoc";
344 case css::awt::Key::SELECT_BACKWARD
:
345 return ".uno:CharLeftSel";
346 case css::awt::Key::SELECT_FORWARD
:
347 return ".uno:CharRightSel";
348 case css::awt::Key::SELECT_WORD_BACKWARD
:
349 return ".uno:WordLeftSel";
350 case css::awt::Key::SELECT_WORD_FORWARD
:
351 return ".uno:WordRightSel";
352 case css::awt::Key::SELECT_WORD
:
353 return ".uno:SelectWord";
354 case css::awt::Key::SELECT_LINE
:
356 case css::awt::Key::SELECT_PARAGRAPH
:
357 return ".uno:SelectText";
358 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
359 return ".uno:StartOfLineSel";
360 case css::awt::Key::SELECT_TO_END_OF_LINE
:
361 return ".uno:EndOfLineSel";
362 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
363 return ".uno:StartOfParaSel";
364 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
365 return ".uno:EndOfParaSel";
366 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
367 return ".uno:StartOfDocumentSel";
368 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
369 return ".uno:EndOfDocumentSel";
370 case css::awt::Key::SELECT_ALL
:
371 return ".uno:SelectAll";
381 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openModuleConfig(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
382 const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
384 css::uno::Reference
< css::frame::XModuleManager2
> xModuleDetection(
385 css::frame::ModuleManager::create(rxContext
));
390 sModule
= xModuleDetection
->identify(xFrame
);
392 catch(const css::uno::RuntimeException
&)
394 catch(const css::uno::Exception
&)
395 { return css::uno::Reference
< css::ui::XAcceleratorConfiguration
>(); }
397 css::uno::Reference
< css::ui::XModuleUIConfigurationManagerSupplier
> xUISupplier(
398 css::ui::theModuleUIConfigurationManagerSupplier::get(rxContext
) );
400 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
403 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager(sModule
);
404 xAccCfg
= xUIManager
->getShortCutManager();
406 catch(const css::container::NoSuchElementException
&)
412 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> AcceleratorExecute::st_openDocConfig(const css::uno::Reference
< css::frame::XModel
>& xModel
)
414 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xAccCfg
;
415 css::uno::Reference
< css::ui::XUIConfigurationManagerSupplier
> xUISupplier(xModel
, css::uno::UNO_QUERY
);
416 if (xUISupplier
.is())
418 css::uno::Reference
< css::ui::XUIConfigurationManager
> xUIManager
= xUISupplier
->getUIConfigurationManager();
419 xAccCfg
= xUIManager
->getShortCutManager();
425 css::uno::Reference
< css::util::XURLTransformer
> AcceleratorExecute::impl_ts_getURLParser()
427 // SAFE -> ----------------------------------
428 ::osl::ResettableMutexGuard
aLock(m_aLock
);
430 if (m_xURLParser
.is())
432 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
435 // <- SAFE ----------------------------------
437 css::uno::Reference
< css::util::XURLTransformer
> xParser
= css::util::URLTransformer::create( xContext
);
439 // SAFE -> ----------------------------------
441 m_xURLParser
= xParser
;
443 // <- SAFE ----------------------------------
448 AsyncAccelExec::AsyncAccelExec(const css::uno::Reference
<css::lang::XComponent
>& xFrame
,
449 const css::uno::Reference
<css::frame::XDispatch
>& xDispatch
,
450 const css::util::URL
& rURL
)
452 , m_xDispatch(xDispatch
)
454 , m_aAsyncCallback(LINK(this, AsyncAccelExec
, impl_ts_asyncCallback
))
458 AsyncAccelExec
* AsyncAccelExec::createOneShotInstance(const css::uno::Reference
<css::lang::XComponent
> &xFrame
,
459 const css::uno::Reference
< css::frame::XDispatch
>& xDispatch
,
460 const css::util::URL
& rURL
)
462 AsyncAccelExec
* pExec
= new AsyncAccelExec(xFrame
, xDispatch
, rURL
);
467 void AsyncAccelExec::execAsync()
471 m_xFrame
->addEventListener(this);
472 m_aAsyncCallback
.Post();
475 IMPL_LINK_NOARG(AsyncAccelExec
, impl_ts_asyncCallback
, LinkParamNone
*, void)
477 if (m_xDispatch
.is())
482 m_xFrame
->removeEventListener(this);
483 m_xDispatch
->dispatch(m_aURL
, css::uno::Sequence
< css::beans::PropertyValue
>());
485 catch(const css::uno::Exception
&)
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */