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 .
20 #include <vcl/commandinfoprovider.hxx>
21 #include <vcl/keycod.hxx>
22 #include <vcl/mnemonic.hxx>
23 #include <comphelper/string.hxx>
24 #include <comphelper/sequence.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <cppuhelper/weakref.hxx>
28 #include <com/sun/star/frame/XFrame.hpp>
29 #include <com/sun/star/frame/ModuleManager.hpp>
30 #include <com/sun/star/frame/theUICommandDescription.hpp>
31 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
32 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
33 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
34 #include <com/sun/star/ui/ImageType.hpp>
35 #include <com/sun/star/ui/XImageManager.hpp>
36 #include <com/sun/star/awt/KeyModifier.hpp>
39 using namespace css::uno
;
41 namespace vcl::CommandInfoProvider
{
43 static Reference
<container::XNameAccess
> GetCommandDescription()
45 static WeakReference
<container::XNameAccess
> xWeakRef
;
46 css::uno::Reference
<container::XNameAccess
> xRef(xWeakRef
);
50 xRef
= frame::theUICommandDescription::get(comphelper::getProcessComponentContext());
57 static Reference
<ui::XModuleUIConfigurationManagerSupplier
> GetModuleConfigurationSupplier()
59 static WeakReference
<ui::XModuleUIConfigurationManagerSupplier
> xWeakRef
;
60 css::uno::Reference
<ui::XModuleUIConfigurationManagerSupplier
> xRef(xWeakRef
);
64 xRef
= ui::theModuleUIConfigurationManagerSupplier::get(comphelper::getProcessComponentContext());
71 static Reference
<ui::XAcceleratorConfiguration
> GetGlobalAcceleratorConfiguration()
73 static WeakReference
<ui::XAcceleratorConfiguration
> xWeakRef
;
74 css::uno::Reference
<ui::XAcceleratorConfiguration
> xRef(xWeakRef
);
78 xRef
= ui::GlobalAcceleratorConfiguration::create(comphelper::getProcessComponentContext());
85 static Reference
<ui::XAcceleratorConfiguration
> GetDocumentAcceleratorConfiguration(const Reference
<frame::XFrame
>& rxFrame
)
87 Reference
<frame::XController
> xController
= rxFrame
->getController();
90 Reference
<ui::XUIConfigurationManagerSupplier
> xSupplier(xController
->getModel(), UNO_QUERY
);
93 Reference
<ui::XUIConfigurationManager
> xConfigurationManager(
94 xSupplier
->getUIConfigurationManager());
95 if (xConfigurationManager
.is())
97 return xConfigurationManager
->getShortCutManager();
104 static Reference
<ui::XAcceleratorConfiguration
> GetModuleAcceleratorConfiguration(const Reference
<frame::XFrame
>& rxFrame
)
106 css::uno::Reference
<css::ui::XAcceleratorConfiguration
> curModuleAcceleratorConfiguration
;
109 Reference
<ui::XModuleUIConfigurationManagerSupplier
> xSupplier(GetModuleConfigurationSupplier());
110 Reference
<ui::XUIConfigurationManager
> xManager (
111 xSupplier
->getUIConfigurationManager(GetModuleIdentifier(rxFrame
)));
114 curModuleAcceleratorConfiguration
= xManager
->getShortCutManager();
120 return curModuleAcceleratorConfiguration
;
123 static vcl::KeyCode
AWTKey2VCLKey(const awt::KeyEvent
& aAWTKey
)
125 bool bShift
= ((aAWTKey
.Modifiers
& awt::KeyModifier::SHIFT
) == awt::KeyModifier::SHIFT
);
126 bool bMod1
= ((aAWTKey
.Modifiers
& awt::KeyModifier::MOD1
) == awt::KeyModifier::MOD1
);
127 bool bMod2
= ((aAWTKey
.Modifiers
& awt::KeyModifier::MOD2
) == awt::KeyModifier::MOD2
);
128 bool bMod3
= ((aAWTKey
.Modifiers
& awt::KeyModifier::MOD3
) == awt::KeyModifier::MOD3
);
129 sal_uInt16 nKey
= static_cast<sal_uInt16
>(aAWTKey
.KeyCode
);
131 return vcl::KeyCode(nKey
, bShift
, bMod1
, bMod2
, bMod3
);
134 static OUString
RetrieveShortcutsFromConfiguration(
135 const Reference
<ui::XAcceleratorConfiguration
>& rxConfiguration
,
136 const OUString
& rsCommandName
)
138 if (rxConfiguration
.is())
142 Sequence
<OUString
> aCommands
{ rsCommandName
};
144 Sequence
<Any
> aKeyCodes (rxConfiguration
->getPreferredKeyEventsForCommandList(aCommands
));
145 if (aCommands
.getLength() == 1)
147 awt::KeyEvent aKeyEvent
;
148 if (aKeyCodes
[0] >>= aKeyEvent
)
150 return AWTKey2VCLKey(aKeyEvent
).GetName();
154 catch (css::lang::IllegalArgumentException
&)
161 static vcl::KeyCode
RetrieveKeyCodeShortcutsFromConfiguration(
162 const Reference
<ui::XAcceleratorConfiguration
>& rxConfiguration
,
163 const OUString
& rsCommandName
)
165 if (rxConfiguration
.is())
169 Sequence
<OUString
> aCommands
{ rsCommandName
};
171 Sequence
<Any
> aKeyCodes (rxConfiguration
->getPreferredKeyEventsForCommandList(aCommands
));
172 if (aCommands
.getLength() == 1)
174 awt::KeyEvent aKeyEvent
;
175 if (aKeyCodes
[0] >>= aKeyEvent
)
177 return AWTKey2VCLKey(aKeyEvent
);
181 catch (css::lang::IllegalArgumentException
&)
185 return vcl::KeyCode();
188 static bool ResourceHasKey(const OUString
& rsResourceName
, const OUString
& rsCommandName
, const OUString
& rsModuleName
)
190 Sequence
< OUString
> aSequence
;
193 if (!rsModuleName
.isEmpty())
195 Reference
<container::XNameAccess
> xNameAccess(GetCommandDescription());
196 Reference
<container::XNameAccess
> xUICommandLabels
;
197 if (xNameAccess
->getByName(rsModuleName
) >>= xUICommandLabels
)
199 xUICommandLabels
->getByName(rsResourceName
) >>= aSequence
;
200 if (comphelper::findValue(aSequence
, rsCommandName
) != -1)
211 Sequence
<beans::PropertyValue
> GetCommandProperties(const OUString
& rsCommandName
, const OUString
& rsModuleName
)
213 Sequence
<beans::PropertyValue
> aProperties
;
217 if (!rsModuleName
.isEmpty())
219 Reference
<container::XNameAccess
> xNameAccess(GetCommandDescription());
220 Reference
<container::XNameAccess
> xUICommandLabels
;
221 if ((xNameAccess
->getByName(rsModuleName
) >>= xUICommandLabels
) && xUICommandLabels
->hasByName(rsCommandName
))
222 xUICommandLabels
->getByName(rsCommandName
) >>= aProperties
;
232 static OUString
GetCommandProperty(const OUString
& rsProperty
, const Sequence
<beans::PropertyValue
> &rProperties
)
234 auto pProp
= std::find_if(rProperties
.begin(), rProperties
.end(),
235 [&rsProperty
](const beans::PropertyValue
& rProp
) { return rProp
.Name
== rsProperty
; });
236 if (pProp
!= rProperties
.end())
239 pProp
->Value
>>= sLabel
;
245 OUString
GetLabelForCommand(const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
)
247 return GetCommandProperty(u
"Name"_ustr
, rProperties
);
250 OUString
GetMenuLabelForCommand(const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
)
252 // Here we want to use "Label", not "Name". "Name" is a stripped-down version of "Label" without accelerators
253 // and ellipsis. In the menu, we want to have those accelerators and ellipsis.
254 return GetCommandProperty(u
"Label"_ustr
, rProperties
);
257 OUString
GetPopupLabelForCommand(const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
)
259 OUString
sPopupLabel(GetCommandProperty(u
"PopupLabel"_ustr
, rProperties
));
260 if (!sPopupLabel
.isEmpty())
262 return GetCommandProperty(u
"Label"_ustr
, rProperties
);
265 OUString
GetTooltipLabelForCommand(const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
)
267 OUString
sLabel(GetCommandProperty(u
"TooltipLabel"_ustr
, rProperties
));
268 if (!sLabel
.isEmpty())
270 return GetCommandProperty(u
"Label"_ustr
, rProperties
);
273 OUString
GetTooltipForCommand(
274 const OUString
& rsCommandName
,
275 const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
,
276 const Reference
<frame::XFrame
>& rxFrame
)
278 OUString
sLabel(GetCommandProperty(u
"TooltipLabel"_ustr
, rProperties
));
279 if (sLabel
.isEmpty()) {
280 sLabel
= GetPopupLabelForCommand(rProperties
);
281 // Remove '...' at the end and mnemonics (we don't want those in tooltips)
282 sLabel
= comphelper::string::stripEnd(sLabel
, '.');
283 sLabel
= MnemonicGenerator::EraseAllMnemonicChars(sLabel
);
286 // Command can be just an alias to another command,
287 // so need to get the shortcut of the "real" command.
288 const OUString
sRealCommand(GetRealCommandForCommand(rProperties
));
289 const OUString
sShortCut(GetCommandShortcut(!sRealCommand
.isEmpty() ? sRealCommand
: rsCommandName
, rxFrame
));
290 if (!sShortCut
.isEmpty())
291 return sLabel
+ " (" + sShortCut
+ ")";
295 OUString
GetCommandShortcut (const OUString
& rsCommandName
,
296 const Reference
<frame::XFrame
>& rxFrame
)
301 sShortcut
= RetrieveShortcutsFromConfiguration(GetDocumentAcceleratorConfiguration(rxFrame
), rsCommandName
);
302 if (sShortcut
.getLength() > 0)
305 sShortcut
= RetrieveShortcutsFromConfiguration(GetModuleAcceleratorConfiguration(rxFrame
), rsCommandName
);
306 if (sShortcut
.getLength() > 0)
309 sShortcut
= RetrieveShortcutsFromConfiguration(GetGlobalAcceleratorConfiguration(), rsCommandName
);
310 if (sShortcut
.getLength() > 0)
316 vcl::KeyCode
GetCommandKeyCodeShortcut (const OUString
& rsCommandName
, const Reference
<frame::XFrame
>& rxFrame
)
318 vcl::KeyCode aKeyCodeShortcut
;
320 aKeyCodeShortcut
= RetrieveKeyCodeShortcutsFromConfiguration(GetDocumentAcceleratorConfiguration(rxFrame
), rsCommandName
);
321 if (aKeyCodeShortcut
.GetCode())
322 return aKeyCodeShortcut
;
324 aKeyCodeShortcut
= RetrieveKeyCodeShortcutsFromConfiguration(GetModuleAcceleratorConfiguration(rxFrame
), rsCommandName
);
325 if (aKeyCodeShortcut
.GetCode())
326 return aKeyCodeShortcut
;
328 aKeyCodeShortcut
= RetrieveKeyCodeShortcutsFromConfiguration(GetGlobalAcceleratorConfiguration(), rsCommandName
);
329 if (aKeyCodeShortcut
.GetCode())
330 return aKeyCodeShortcut
;
332 return vcl::KeyCode();
335 OUString
GetRealCommandForCommand(const css::uno::Sequence
<css::beans::PropertyValue
>& rProperties
)
337 return GetCommandProperty(u
"TargetURL"_ustr
, rProperties
);
340 Reference
<graphic::XGraphic
> GetXGraphicForCommand(const OUString
& rsCommandName
,
341 const Reference
<frame::XFrame
>& rxFrame
,
342 vcl::ImageType eImageType
)
344 if (rsCommandName
.isEmpty())
347 sal_Int16
nImageType(ui::ImageType::COLOR_NORMAL
| ui::ImageType::SIZE_DEFAULT
);
349 if (eImageType
== vcl::ImageType::Size26
)
350 nImageType
|= ui::ImageType::SIZE_LARGE
;
351 else if (eImageType
== vcl::ImageType::Size32
)
352 nImageType
|= ui::ImageType::SIZE_32
;
356 Reference
<frame::XController
> xController(rxFrame
->getController(), UNO_SET_THROW
);
357 Reference
<ui::XUIConfigurationManagerSupplier
> xSupplier(xController
->getModel(), UNO_QUERY
);
360 Reference
<ui::XUIConfigurationManager
> xDocUICfgMgr(xSupplier
->getUIConfigurationManager());
361 Reference
<ui::XImageManager
> xDocImgMgr(xDocUICfgMgr
->getImageManager(), UNO_QUERY
);
363 Sequence
<OUString
> aImageCmdSeq
{ rsCommandName
};
365 Sequence
<Reference
<graphic::XGraphic
>> aGraphicSeq
= xDocImgMgr
->getImages(nImageType
, aImageCmdSeq
);
366 Reference
<graphic::XGraphic
> xGraphic
= aGraphicSeq
[0];
377 Reference
<ui::XModuleUIConfigurationManagerSupplier
> xModuleCfgMgrSupplier(GetModuleConfigurationSupplier());
378 Reference
<ui::XUIConfigurationManager
> xUICfgMgr(xModuleCfgMgrSupplier
->getUIConfigurationManager(GetModuleIdentifier(rxFrame
)));
379 Reference
<ui::XImageManager
> xModuleImageManager(xUICfgMgr
->getImageManager(), UNO_QUERY
);
381 Sequence
<OUString
> aImageCmdSeq
{ rsCommandName
};
383 Sequence
<Reference
<graphic::XGraphic
>> aGraphicSeq
= xModuleImageManager
->getImages(nImageType
, aImageCmdSeq
);
384 Reference
<graphic::XGraphic
> xGraphic(aGraphicSeq
[0]);
395 Image
GetImageForCommand(const OUString
& rsCommandName
,
396 const Reference
<frame::XFrame
>& rxFrame
,
397 vcl::ImageType eImageType
)
399 return Image(GetXGraphicForCommand(rsCommandName
, rxFrame
, eImageType
));
402 sal_Int32
GetPropertiesForCommand (
403 const OUString
& rsCommandName
,
404 const OUString
& rsModuleName
)
406 sal_Int32 nValue
= 0;
407 const Sequence
<beans::PropertyValue
> aProperties (GetCommandProperties(rsCommandName
, rsModuleName
));
409 auto pProp
= std::find_if(aProperties
.begin(), aProperties
.end(),
410 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "Properties"; });
411 if (pProp
!= aProperties
.end())
412 pProp
->Value
>>= nValue
;
417 bool IsRotated(const OUString
& rsCommandName
, const OUString
& rsModuleName
)
419 return ResourceHasKey(u
"private:resource/image/commandrotateimagelist"_ustr
, rsCommandName
, rsModuleName
);
422 bool IsMirrored(const OUString
& rsCommandName
, const OUString
& rsModuleName
)
424 return ResourceHasKey(u
"private:resource/image/commandmirrorimagelist"_ustr
, rsCommandName
, rsModuleName
);
427 bool IsExperimental(const OUString
& rsCommandName
, const OUString
& rModuleName
)
429 Sequence
<beans::PropertyValue
> aProperties
;
432 if( rModuleName
.getLength() > 0)
434 Reference
<container::XNameAccess
> xNameAccess(GetCommandDescription());
435 Reference
<container::XNameAccess
> xUICommandLabels
;
436 if (xNameAccess
->getByName( rModuleName
) >>= xUICommandLabels
)
437 xUICommandLabels
->getByName(rsCommandName
) >>= aProperties
;
439 auto pProp
= std::find_if(std::cbegin(aProperties
), std::cend(aProperties
),
440 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "IsExperimental"; });
441 if (pProp
!= std::cend(aProperties
))
444 return (pProp
->Value
>>= bValue
) && bValue
;
454 OUString
GetModuleIdentifier(const Reference
<frame::XFrame
>& rxFrame
)
456 static WeakReference
<frame::XModuleManager2
> xWeakRef
;
457 css::uno::Reference
<frame::XModuleManager2
> xRef(xWeakRef
);
461 xRef
= frame::ModuleManager::create(comphelper::getProcessComponentContext());
467 return xRef
->identify(rxFrame
);
469 catch (const Exception
&)
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */