LibreOffice Module vcl (master) 1
menuitemlist.cxx
Go to the documentation of this file.
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 "menuitemlist.hxx"
21
22#include <salframe.hxx>
23#include <salinst.hxx>
24#include <salmenu.hxx>
25#include <svdata.hxx>
26
27#include <vcl/i18nhelp.hxx>
28#include <vcl/mnemonic.hxx>
29#include <vcl/settings.hxx>
30#include <vcl/vcllayout.hxx>
31#include <vcl/window.hxx>
32
33using namespace css;
34using namespace vcl;
35
37{
40 pSalMenuItem.reset();
42}
43
45{
46 if (aTextGlyphs.IsValid())
47 // Use pre-calculated result.
48 return &aTextGlyphs;
49
50 OUString aNonMnemonicString = removeMnemonicFromString(aText);
51 std::unique_ptr<SalLayout> pLayout
52 = pOutputDevice->ImplLayout(aNonMnemonicString, 0, aNonMnemonicString.getLength(),
53 Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly);
54 if (!pLayout)
55 return nullptr;
56
57 // Remember the calculation result.
58 aTextGlyphs = pLayout->GetGlyphs();
59
60 return &aTextGlyphs;
61}
62
64{
65}
66
68 sal_uInt16 nId,
69 MenuItemType eType,
70 MenuItemBits nBits,
71 const OUString& rStr,
72 Menu* pMenu,
73 size_t nPos,
74 const OString &rIdent
75)
76{
77 MenuItemData* pData = new MenuItemData( rStr );
78 pData->nId = nId;
79 pData->sIdent = rIdent;
80 pData->eType = eType;
81 pData->nBits = nBits;
82 pData->pSubMenu = nullptr;
83 pData->nUserValue = nullptr;
84 pData->bChecked = false;
85 pData->bEnabled = true;
86 pData->bVisible = true;
87 pData->bIsTemporary = false;
88
89 SalItemParams aSalMIData;
90 aSalMIData.nId = nId;
91 aSalMIData.eType = eType;
92 aSalMIData.nBits = nBits;
93 aSalMIData.pMenu = pMenu;
94 aSalMIData.aText = rStr;
95
96 // Native-support: returns NULL if not supported
97 pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
98
99 if( nPos < maItemList.size() ) {
100 maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
101 } else {
102 maItemList.emplace_back( pData );
103 }
104 return pData;
105}
106
107void MenuItemList::InsertSeparator(const OString &rIdent, size_t nPos)
108{
110 pData->nId = 0;
111 pData->sIdent = rIdent;
113 pData->nBits = MenuItemBits::NONE;
114 pData->pSubMenu = nullptr;
115 pData->nUserValue = nullptr;
116 pData->bChecked = false;
117 pData->bEnabled = true;
118 pData->bVisible = true;
119 pData->bIsTemporary = false;
120
121 SalItemParams aSalMIData;
122 aSalMIData.nId = 0;
123 aSalMIData.eType = MenuItemType::SEPARATOR;
124 aSalMIData.nBits = MenuItemBits::NONE;
125 aSalMIData.pMenu = nullptr;
126 aSalMIData.aText.clear();
127 aSalMIData.aImage = Image();
128
129 // Native-support: returns NULL if not supported
130 pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( aSalMIData );
131
132 if( nPos < maItemList.size() ) {
133 maItemList.insert( maItemList.begin() + nPos, std::unique_ptr<MenuItemData>(pData) );
134 } else {
135 maItemList.emplace_back( pData );
136 }
137}
138
139void MenuItemList::Remove( size_t nPos )
140{
141 if( nPos < maItemList.size() )
142 {
143 maItemList.erase( maItemList.begin() + nPos );
144 }
145}
146
148{
149 maItemList.clear();
150}
151
152MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const
153{
154 for( size_t i = 0, n = maItemList.size(); i < n; ++i )
155 {
156 if ( maItemList[ i ]->nId == nSVId )
157 {
158 rPos = i;
159 return maItemList[ i ].get();
160 }
161 }
162 return nullptr;
163}
164
166 sal_Unicode cSelectChar,
167 KeyCode aKeyCode,
168 size_t& rPos,
169 size_t& nDuplicates,
170 size_t nCurrentPos
171) const
172{
174
175 size_t nListCount = maItemList.size();
176
177 // try character code first
178 nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates
179 if( nDuplicates )
180 {
181 MenuItemData* pFirstMatch = nullptr;
182 size_t nFirstPos(0);
183 for ( rPos = 0; rPos < nListCount; rPos++)
184 {
185 MenuItemData* pData = maItemList[ rPos ].get();
186 if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
187 {
188 if (nDuplicates == 1)
189 return pData;
190 if (rPos > nCurrentPos)
191 return pData; // select next entry with the same mnemonic
192 if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
193 {
194 pFirstMatch = pData;
195 nFirstPos = rPos;
196 }
197 }
198 }
199 if (pFirstMatch)
200 {
201 rPos = nFirstPos;
202 return pFirstMatch;
203 }
204 }
205
206 // nothing found, try keycode instead
207 nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates
208
209 if( nDuplicates )
210 {
211 char ascii = 0;
212 if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
213 ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
214
215 MenuItemData* pFirstMatch = nullptr;
216 size_t nFirstPos(0);
217 for ( rPos = 0; rPos < nListCount; rPos++)
218 {
219 MenuItemData* pData = maItemList[ rPos ].get();
220 if ( pData->bEnabled )
221 {
222 sal_Int32 n = pData->aText.indexOf('~');
223 if ( n != -1 )
224 {
225 KeyCode nKeyCode;
226 sal_Unicode nUnicode = pData->aText[n+1];
227 vcl::Window* pDefWindow = ImplGetDefaultWindow();
228 if( ( pDefWindow
229 && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( nUnicode,
231 && aKeyCode.GetCode() == nKeyCode.GetCode()
232 )
233 || ( ascii
234 && rI18nHelper.MatchMnemonic( pData->aText, ascii )
235 )
236 )
237 {
238 if (nDuplicates == 1)
239 return pData;
240 if (rPos > nCurrentPos)
241 return pData; // select next entry with the same mnemonic
242 if (!pFirstMatch) // stash the first match for use if nothing follows nCurrentPos
243 {
244 pFirstMatch = pData;
245 nFirstPos = rPos;
246 }
247 }
248 }
249 }
250 }
251 if (pFirstMatch)
252 {
253 rPos = nFirstPos;
254 return pFirstMatch;
255 }
256 }
257
258 return nullptr;
259}
260
261size_t MenuItemList::GetItemCount( sal_Unicode cSelectChar ) const
262{
263 // returns number of entries with same mnemonic
265
266 size_t nItems = 0;
267 for ( size_t nPos = maItemList.size(); nPos; )
268 {
269 MenuItemData* pData = maItemList[ --nPos ].get();
270 if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) )
271 nItems++;
272 }
273
274 return nItems;
275}
276
277size_t MenuItemList::GetItemCount( KeyCode aKeyCode ) const
278{
279 // returns number of entries with same mnemonic
280 // uses key codes instead of character codes
282 char ascii = 0;
283 if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z )
284 ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A));
285
286 size_t nItems = 0;
287 for ( size_t nPos = maItemList.size(); nPos; )
288 {
289 MenuItemData* pData = maItemList[ --nPos ].get();
290 if ( pData->bEnabled )
291 {
292 sal_Int32 n = pData->aText.indexOf('~');
293 if (n != -1)
294 {
295 KeyCode nKeyCode;
296 // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes
297 // so we have working shortcuts when ascii mnemonics are used
298 vcl::Window* pDefWindow = ImplGetDefaultWindow();
299 if( ( pDefWindow
300 && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText[n+1],
302 && aKeyCode.GetCode() == nKeyCode.GetCode()
303 )
304 || ( ascii
305 && rI18nHelper.MatchMnemonic( pData->aText, ascii )
306 )
307 )
308 nItems++;
309 }
310 }
311 }
312
313 return nItems;
314}
315
316/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const vcl::I18nHelper & GetUILocaleI18nHelper() const
const LanguageTag & GetUILanguageTag() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:761
Definition: image.hxx:40
LanguageType getLanguageType(bool bResolveSystem=true) const
size_t GetItemCount(sal_Unicode cSelectChar) const
void Remove(size_t nPos)
MenuItemData * GetData(sal_uInt16 nSVId, size_t &rPos) const
MenuItemData * Insert(sal_uInt16 nId, MenuItemType eType, MenuItemBits nBits, const OUString &rStr, Menu *pMenu, size_t nPos, const OString &rIdent)
::std::vector< std::unique_ptr< MenuItemData > > maItemList
void InsertSeparator(const OString &rIdent, size_t nPos)
MenuItemData * SearchItem(sal_Unicode cSelectChar, vcl::KeyCode aKeyCode, size_t &rPos, size_t &nDuplicates, size_t nCurrentPos) const
Definition: menu.hxx:116
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:171
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), tools::Long nLogicWidth=0, o3tl::span< const sal_Int32 > pLogicDXArray={}, o3tl::span< const sal_Bool > pKashidaArray={}, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1317
virtual bool MapUnicodeToKeyCode(sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode &rKeyCode)=0
virtual std::unique_ptr< SalMenuItem > CreateMenuItem(const SalItemParams &pItemData)
Definition: salvtables.cxx:165
bool IsValid() const
void disposeAndClear()
Definition: vclptr.hxx:200
bool MatchMnemonic(std::u16string_view rString, sal_Unicode cMnemonicChar) const
Definition: i18nhelp.cxx:142
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
SalFrame * ImplGetFrame() const
Definition: window2.cxx:867
DocumentType eType
sal_Int64 n
constexpr sal_uInt16 KEY_Z
Definition: keycodes.hxx:81
constexpr sal_uInt16 KEY_A
Definition: keycodes.hxx:56
sal_uInt16 nPos
std::unique_ptr< sal_Int32[]> pData
int i
sal_Int16 nId
SalInstance * mpDefInst
Definition: svdata.hxx:392
SalLayoutGlyphs aTextGlyphs
Text layout of aText.
VclPtr< Menu > pSubMenu
void * nUserValue
MenuUserDataReleaseFunction aUserValueReleaseFunc
SalLayoutGlyphs * GetTextGlyphs(const OutputDevice *pOutputDevice)
Computes aText's text layout (glyphs), cached in aTextGlyphs.
std::unique_ptr< SalMenuItem > pSalMenuItem
OUString aText
VclPtr< Menu > pMenu
Definition: salmenu.hxx:34
MenuItemBits nBits
Definition: salmenu.hxx:38
MenuItemType eType
Definition: salmenu.hxx:36
sal_uInt16 nId
Definition: salmenu.hxx:37
OUString aText
Definition: salmenu.hxx:35
Image aImage
Definition: salmenu.hxx:33
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
vcl::Window * ImplGetDefaultWindow()
Returns either the application window, or the default GL context window.
Definition: svdata.cxx:211
OUString removeMnemonicFromString(OUString const &rStr)
sal_uInt16 sal_Unicode
MenuItemType
Definition: vclenum.hxx:30
MenuItemBits
Definition: vclenum.hxx:33